0xSynapse commited on
Commit
65a0c52
1 Parent(s): b36407b

Upload 5 files

Browse files
app.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import gradio as gr
4
+
5
+ def image_inference(image_path, mode, epsilon_thresh):
6
+ # Read the image
7
+ img = cv2.cvtColor(image_path, cv2.COLOR_RGB2BGR)
8
+ if img is None:
9
+ raise FileNotFoundError(f"Image at path '{image_path}' not found.")
10
+
11
+ # Create a copy of the original image
12
+ img_copy = img.copy()
13
+
14
+ # Convert the image to grayscale
15
+ img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
16
+
17
+ # Apply thresholding
18
+ _, img_thresh = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY_INV)
19
+
20
+ # Find the contours
21
+ contours, _ = cv2.findContours(img_thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
22
+ contour_info = f"Number of contours found: {len(contours)}" # Text output for Gradio
23
+ # print(f"Number of contours found = {len(contours)}")
24
+
25
+ def convert_color(hsv):
26
+ # Utility to convert a single HSV color tuple into BGR
27
+ pixel_img = np.uint8([[hsv]])
28
+ return tuple(int(i) for i in cv2.cvtColor(pixel_img, cv2.COLOR_HSV2BGR).flatten())
29
+
30
+ if mode == "contour":
31
+ if len(contours) > 0:
32
+ for i, single_contour in enumerate(contours):
33
+ hsv = (int(i/len(contours) * 180), 255, 255)
34
+ color = convert_color(hsv)
35
+ # Draw the contour
36
+ img_final = cv2.drawContours(img_copy, contours, i, color, 4)
37
+ # Calculate and display the area
38
+ # area = cv2.contourArea(single_contour)
39
+ # x, y, w, h = cv2.boundingRect(single_contour)
40
+ # img_final = cv2.putText(img_final, f"Area: {area}", (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
41
+ else:
42
+ img_final = img_copy # No contours found, return the original image
43
+ elif mode == "rotated rectangle":
44
+ for cnt in contours:
45
+ # Rotated bounding box
46
+ box = cv2.minAreaRect(cnt)
47
+ box_pts = np.intp(cv2.boxPoints(box))
48
+ img_final = cv2.drawContours(img_copy, [box_pts], -1, (0, 255, 0), 4)
49
+
50
+ # Calculate and display the area
51
+ area = cv2.contourArea(cnt)
52
+ x, y, w, h = cv2.boundingRect(cnt)
53
+ img_final = cv2.putText(img_final, f"Area: {area}", (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
54
+
55
+ elif mode == "rectangle":
56
+ for cnt in contours:
57
+ # Bounding rectangle
58
+ x, y, w, h = cv2.boundingRect(cnt)
59
+ img_final = cv2.rectangle(img_copy, (x, y), (x + w, y + h), (0, 255, 0), 4)
60
+
61
+ # Calculate and display the area
62
+ area = cv2.contourArea(cnt)
63
+ img_final = cv2.putText(img_final, f"Area: {area}", (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
64
+
65
+ elif mode == "circle":
66
+ for cnt in contours:
67
+ # Enclosing circle
68
+ ((x, y), radius) = cv2.minEnclosingCircle(cnt)
69
+ img_final = cv2.circle(img_copy, (int(x), int(y)), int(round(radius)), (0, 255, 0), 4)
70
+
71
+ # Calculate and display the perimeter
72
+ perimeter = cv2.arcLength(cnt, True)
73
+ x, y, w, h = cv2.boundingRect(cnt)
74
+ img_final = cv2.putText(img_final, f"Perimeter: {perimeter:.2f}", (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
75
+
76
+ elif mode == "ellipse":
77
+ for cnt in contours:
78
+ if len(cnt) >= 5: # fitEllipse requires at least 5 points
79
+ ellipse = cv2.fitEllipse(cnt)
80
+ img_final = cv2.ellipse(img_copy, ellipse, (0, 255, 0), 4)
81
+
82
+ # Calculate and display the perimeter
83
+ perimeter = cv2.arcLength(cnt, True)
84
+ x, y, w, h = cv2.boundingRect(cnt)
85
+ img_final = cv2.putText(img_final, f"Perimeter: {perimeter:.2f}", (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1)
86
+ else:
87
+ img_final = img_copy
88
+ elif mode == "centroid":
89
+ for cnt in contours:
90
+ M = cv2.moments(cnt)
91
+ if M["m00"] != 0:
92
+ x = int(round(M["m10"] / M["m00"]))
93
+ y = int(round(M["m01"] / M["m00"]))
94
+ img_final = cv2.circle(img_copy, (x, y), 10, (255, 0, 0), -1)
95
+ else:
96
+ img_final = img_copy
97
+ elif mode == "contour approx":
98
+ if len(contours) > 0:
99
+ c = max(contours, key=cv2.contourArea)
100
+ peri = cv2.arcLength(c, True)
101
+ approx = cv2.approxPolyDP(c, epsilon_thresh * peri, True)
102
+ img_final = cv2.drawContours(img_copy, [approx], -1, (0, 255, 0), 3)
103
+ x, y, w, h = cv2.boundingRect(c)
104
+ text = f"eps={epsilon_thresh:.4f}, num_pts={len(approx)}"
105
+ img_final = cv2.putText(img_copy, text, (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
106
+ else:
107
+ img_final = img_copy
108
+ else:
109
+ img_final = img_copy
110
+ print(f"Mode '{mode}' not recognized. Please choose a valid mode.")
111
+
112
+ return contour_info, cv2.cvtColor(img_final, cv2.COLOR_BGR2RGB)
113
+
114
+ # Gradio interface
115
+ input_image = gr.Image(type="numpy", label="Input Image")
116
+ epsilon_thresh = gr.Slider(
117
+ 0.01,
118
+ 0.1,
119
+ step=0.01,
120
+ value=0.05,
121
+ label="Epsilon Threshold",
122
+ info="Adjust the Contour Threshold according to the object size that you want to detect. Only Applicable for Contour Approx",
123
+ )
124
+ mode = gr.Radio(
125
+ ["contour", "rectangle", "rotated rectangle", "circle", "ellipse", "centroid", "contour approx"],
126
+ label="Contour Type",
127
+ info="Choose the MODE",
128
+ )
129
+ output_text = gr.Textbox(label="Contour Information")
130
+ output_image = gr.Image(label="Output Image")
131
+
132
+ app = gr.Interface(
133
+ fn=image_inference,
134
+ inputs=[input_image, mode, epsilon_thresh],
135
+ outputs=[output_text, output_image],
136
+ title="Contour Detection using OpenCV",
137
+ description="A Gradio app for dynamic image analysis using Contour detection techniques.",
138
+ allow_flagging="never",
139
+ examples=[["./sample/tictactoe.png", "contour", float(0.01)], ["./sample/tetris_blocks.png", "rectangle", float(0.00)], ["./sample/shape.png", "contour approx", float(0.05)]],
140
+ cache_examples=False,
141
+ )
142
+ app.queue().launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio==4.42.0
2
+ opencv-python==4.10.0.84
sample/shape.png ADDED
sample/tetris_blocks.png ADDED
sample/tictactoe.png ADDED