Gerold Meisinger commited on
Commit
d1df3f4
·
1 Parent(s): a0e1baf

upgraded to opencv-contrib-python>=4.12 and added EDColor, EDLines and EDEllipses

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app.py +214 -46
  3. requirements.txt +2 -2
.gitignore CHANGED
@@ -1,3 +1,4 @@
 
1
  venv
2
  flagged
3
 
 
1
+ .venv
2
  venv
3
  flagged
4
 
app.py CHANGED
@@ -1,52 +1,220 @@
1
- import gradio as gr
2
- import cv2
3
  import os
4
 
5
- ed = cv2.ximgproc.createEdgeDrawing()
6
- params = cv2.ximgproc.EdgeDrawing.Params()
7
- params.PFmode = True
8
- ed.setParams(params)
9
 
10
  def center_crop_mod64(img):
11
- h, w = img.shape[:2]
12
- shortside, longside = min(w, h), max(w, h)
13
- longside_crop = (longside // 64) * 64
14
- left = (w - longside_crop) // 2 if w > h else 0
15
- top = (h - longside_crop) // 2 if h > w else 0
16
- right = left + longside_crop if w > h else shortside
17
- bottom = top + longside_crop if h > w else shortside
18
- return img[top:bottom, left:right]
19
-
20
- def edpf(image_rgb):
21
- img_gray = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2GRAY)
22
- img_crop = center_crop_mod64(img_gray)
23
- edges = ed.detectEdges(img_crop)
24
- edge_map = ed.getEdgeImage(edges)
25
- return edge_map
26
-
27
- examples=[
28
- os.path.join(os.path.dirname(__file__), "images/bag.png"),
29
- os.path.join(os.path.dirname(__file__), "images/beard.png"),
30
- os.path.join(os.path.dirname(__file__), "images/bird.png"),
31
- os.path.join(os.path.dirname(__file__), "images/cat.png"),
32
- os.path.join(os.path.dirname(__file__), "images/dog2.png"),
33
- os.path.join(os.path.dirname(__file__), "images/house.png"),
34
- os.path.join(os.path.dirname(__file__), "images/house2.png"),
35
- os.path.join(os.path.dirname(__file__), "images/human.png"),
36
- os.path.join(os.path.dirname(__file__), "images/kitten.png"),
37
- os.path.join(os.path.dirname(__file__), "images/lion.png"),
38
- os.path.join(os.path.dirname(__file__), "images/man.png"),
39
- os.path.join(os.path.dirname(__file__), "images/robot.png"),
40
- os.path.join(os.path.dirname(__file__), "images/robotics.png"),
41
- os.path.join(os.path.dirname(__file__), "images/room.png"),
42
- os.path.join(os.path.dirname(__file__), "images/room2.png"),
43
- os.path.join(os.path.dirname(__file__), "images/suit.png"),
44
- os.path.join(os.path.dirname(__file__), "images/tree.png"),
45
- os.path.join(os.path.dirname(__file__), "images/vermeer.png"),
46
- ]
47
-
48
- app = gr.Interface(fn=edpf, inputs=gr.Image(value="images/dog2.png"), outputs="image", title="Edge Drawing Parameter Free", description="A modern edge detection algorithm which requires no parameter tuning. Generate edge maps for the edpf ControlNet model at https://huggingface.co/GeroldMeisinger/control-edgedrawing", examples=examples)
49
 
50
- if __name__ == "__main__":
51
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import glob
 
2
  import os
3
 
4
+ import cv2
5
+ import gradio as gr
6
+
 
7
 
8
  def center_crop_mod64(img):
9
+ """Crop image to largest area that's divisible by 64"""
10
+ h, w = img.shape[:2]
11
+ shortside, longside = min(w, h), max(w, h)
12
+ longside_crop = (longside // 64) * 64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
+ left = (w - longside_crop) // 2 if w > h else 0
15
+ top = (h - longside_crop) // 2 if h > w else 0
16
+ right = left + longside_crop if w > h else shortside
17
+ bottom = top + longside_crop if h > w else shortside
18
+
19
+ return img[top:bottom, left:right]
20
+
21
+ def load_example_images():
22
+ """Load all images from images/ directory"""
23
+ image_dir = os.path.join(os.path.dirname(__file__), "images")
24
+ if not os.path.exists(image_dir):
25
+ return []
26
+
27
+ extensions = ['*.png', '*.jpg', '*.jpeg', '*.webp']
28
+ examples = []
29
+ for ext in extensions:
30
+ examples.extend(glob.glob(os.path.join(image_dir, ext)))
31
+ examples.extend(glob.glob(os.path.join(image_dir, ext.upper())))
32
+
33
+ return sorted(examples)
34
+
35
+ def apply_edge_detection(image_rgb, algorithm, apply_crop, convert2grayscale, params):
36
+ """Apply selected edge detection algorithm with specified parameters"""
37
+
38
+ if image_rgb is None:
39
+ return None
40
+
41
+ # Apply cropping if requested
42
+ if apply_crop:
43
+ img_processed = center_crop_mod64(image_rgb)
44
+ else:
45
+ img_processed = image_rgb.copy()
46
+
47
+ # Convert to grayscale if requested
48
+ if convert2grayscale and len(img_processed.shape) == 3:
49
+ img_input = cv2.cvtColor(cv2.cvtColor(img_processed, cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB)
50
+ else:
51
+ img_input = img_processed
52
+ ret = img_input.copy()
53
+
54
+ # set parameters
55
+
56
+
57
+ # Detect edges
58
+ ed = cv2.ximgproc.createEdgeDrawing()
59
+ ed.setParams(params)
60
+ ed.detectEdges(img_input)
61
+
62
+ if algorithm == "Edges":
63
+ ret = ed.getEdgeImage()
64
+ return ret
65
+
66
+ elif algorithm == "Lines":
67
+ lines = ed.detectLines()
68
+
69
+ # draw lines
70
+ if lines is not None:
71
+ for line in lines:
72
+ x1, y1, x2, y2 = map(int, line[0])
73
+ cv2.line(ret, (x1, y1), (x2, y2), (0, 255, 0), 1)
74
+
75
+ return ret
76
+
77
+ elif algorithm == "Ellipses":
78
+ ellipsess = ed.detectEllipses()
79
+
80
+ # draw ellipses
81
+ if ellipsess is not None:
82
+ for ellipses in ellipsess:
83
+ ellipse = ellipses[0]
84
+ center = (int(ellipse[0]), int(ellipse[1]))
85
+ if ellipse[2] == 0: # Ellipse
86
+ axes = (int(ellipse[3]), int(ellipse[4]))
87
+ angle = ellipse[5]
88
+ cv2.ellipse(ret, center, axes, angle, 0, 360, (0, 255, 0), 1)
89
+ else: # Circle
90
+ radius = int(ellipse[2])
91
+ cv2.circle(ret, center, radius, (0, 255, 0), 1)
92
 
93
+ return ret
94
+
95
+ return img_input
96
+
97
+ # Create Gradio interface
98
+ with gr.Blocks(title="Edge Drawing") as app:
99
+ examples = load_example_images()
100
+ gr.Markdown("# Enhanced Edge Detection with [Edge Drawing](https://github.com/CihanTopal/ED_Lib) using [opencv-contrib-python](https://docs.opencv.org/4.x/d1/d1c/classcv_1_1ximgproc_1_1EdgeDrawing.html)")
101
+
102
+ # Image row - Input and Output side by side
103
+ with gr.Row():
104
+ input_image = gr.Image(value=examples[0] if examples else None , label="Input Image" , type="numpy")
105
+ output_image = gr.Image(value=None , label="Detection Result" , type="numpy")
106
+
107
+ # Controls row - Processing Options on left, Parameters on right
108
+ with gr.Row():
109
+ # Processing Options
110
+ with gr.Column():
111
+ with gr.Group():
112
+ gr.Markdown("### Processing Options")
113
+ algorithm_radio = gr.Radio(label="Detection mode", value="Edges", choices=["Edges", "Lines", "Ellipses"])
114
+
115
+ paramterfree_checkbox = gr.Checkbox(label ="Parameter Free Mode" , value=True , info="Auto-determine optimal parameters")
116
+ convert2grayscale_checkbox = gr.Checkbox(label ="Convert to Grayscale" , value=False , info="Force conversion to grayscale prior to edge detection (note that Edge Drawing has native support for color images)")
117
+ crop_checkbox = gr.Checkbox(label ="Apply center crop mod-64" , value=False , info="Crop to largest area divisible by 64 (used for Stable Diffusion)")
118
+
119
+ # EdgeDrawing Parameters
120
+ with gr.Column():
121
+ with gr.Group():
122
+ gr.Markdown("### Edge Drawing Parameters")
123
+
124
+ # Parameter controls group (disabled by default)
125
+ with gr.Group(visible=False) as param_group:
126
+ with gr.Column():
127
+ with gr.Row():
128
+ gradient_operator = gr.Radio(choices=["PREWITT", "SOBEL", "SCHARR", "LSD"], value="PREWITT", label="Gradient Operator", info="indicates the operator used for gradient calculation. Default value is PREWITT")
129
+ gradient_threshold = gr.Slider(minimum= 1 , maximum= 100 , value= 20 , step= 1 , label="Gradient Threshold" , scale= 1 , info="Threshold value of gradiential difference between pixels. Used to create gradient image. Default value is 20" )
130
+
131
+ with gr.Row():
132
+ anchor_threshold = gr.Slider(minimum= 0 , maximum= 255 , value= 0 , step= 1 , label="Anchor Threshold" , scale= 1 , info="Threshold value used to select anchor points. Default value is 0" )
133
+ min_path_length = gr.Slider(minimum= 1 , maximum= 50 , value= 10 , step= 1 , label="Min Path Length" , scale= 1 , info="Minimum connected pixels length processed to create an edge segment. Default value is 10" )
134
+
135
+ with gr.Row():
136
+ min_line_length = gr.Slider(minimum= -1 , maximum= 100 , value= -1 , step= 1 , label="Min Line Length" , scale= 1 , info="Minimum line length to detect. Default value is -1" )
137
+ line_fit_error_threshold = gr.Slider(minimum= 0.1 , maximum= 10.0 , value= 1.0 , step= 0.1 , label="Line Fit Error Threshold" , scale= 1 , info="Default value is 1.0" )
138
+ max_distance_between_two_lines = gr.Slider(minimum= 1.0 , maximum= 20.0 , value= 6.0 , step= 0.1 , label="Max Distance Between Two Lines" , scale= 1 , info="Default value is 6.0" )
139
+
140
+ with gr.Row():
141
+ max_error_threshold = gr.Slider(minimum= 0.1 , maximum= 5.0 , value= 1.3 , step= 0.1 , label="Max Error Threshold" , scale= 1 , info="Default value is 1.3" )
142
+ scan_interval = gr.Slider(minimum= 1 , maximum= 10 , value= 1 , step= 1 , label="Scan Interval" , scale= 1 , info="Default value is 1" )
143
+
144
+ with gr.Row():
145
+ sigma = gr.Slider(minimum= 0.1 , maximum= 5.0 , value= 1.0 , step= 0.1 , label="Sigma" , scale= 1 , info="Sigma value for internal GaussianBlur() function. Default value is 1.0" )
146
+ nfa_validation = gr.Checkbox(label="NFA Validation" , value=True , info="Indicates if NFA (Number of False Alarms) algorithm will be used for line and ellipse validation. Default value is true")
147
+ sum_flag = gr.Checkbox(label="Sum Flag" , value=True , info="Default value is true")
148
+
149
+ # Update function
150
+ def update_output(
151
+ image_rgb, algorithm, apply_crop, conv2grayscale, pf_mode,
152
+ gradient_operator, anchor_threshold, gradient_threshold, min_path_length, min_line_length, line_fit_error_threshold, max_distance_between_two_lines, max_error_threshold, nfa_validation, scan_interval, sigma, sum_flag
153
+ ):
154
+ operator_map = {
155
+ "PREWITT" : cv2.ximgproc.EdgeDrawing_PREWITT,
156
+ "SOBEL" : cv2.ximgproc.EdgeDrawing_SOBEL,
157
+ "SCHARR" : cv2.ximgproc.EdgeDrawing_SCHARR,
158
+ "LSD" : cv2.ximgproc.EdgeDrawing_LSD,
159
+ }
160
+
161
+ params = cv2.ximgproc.EdgeDrawing.Params()
162
+ params.PFmode = pf_mode
163
+ params.EdgeDetectionOperator = operator_map.get(gradient_operator, cv2.ximgproc.EdgeDrawing_PREWITT)
164
+ if not pf_mode:
165
+ params.AnchorThresholdValue = anchor_threshold
166
+ params.GradientThresholdValue = gradient_threshold
167
+ params.MinPathLength = min_path_length
168
+ params.MinLineLength = min_line_length
169
+ params.LineFitErrorThreshold = line_fit_error_threshold
170
+ params.MaxDistanceBetweenTwoLines = max_distance_between_two_lines
171
+ params.MaxErrorThreshold = max_error_threshold
172
+ params.NFAValidation = nfa_validation
173
+ params.ScanInterval = scan_interval
174
+ params.Sigma = sigma
175
+ params.SumFlag = sum_flag
176
+
177
+ ret = apply_edge_detection(image_rgb, algorithm, apply_crop, conv2grayscale, params)
178
+ return ret
179
+
180
+ # Function to toggle parameter group visibility
181
+ def toggle_params(pf_mode):
182
+ return gr.Group(visible=not pf_mode)
183
+
184
+ # Set up event handlers
185
+ inputs = [
186
+ input_image,
187
+ algorithm_radio,
188
+ crop_checkbox,
189
+ convert2grayscale_checkbox,
190
+ paramterfree_checkbox,
191
+ gradient_operator,
192
+ anchor_threshold,
193
+ gradient_threshold,
194
+ min_path_length,
195
+ min_line_length,
196
+ line_fit_error_threshold,
197
+ max_distance_between_two_lines,
198
+ max_error_threshold,
199
+ nfa_validation,
200
+ scan_interval,
201
+ sigma,
202
+ sum_flag,
203
+ ]
204
+
205
+ # Update output when any input changes
206
+ for inp in inputs:
207
+ inp.change(fn=update_output, inputs=inputs, outputs=output_image)
208
+
209
+ # Toggle parameter group when parameter free mode changes
210
+ paramterfree_checkbox.change(fn=toggle_params, inputs=paramterfree_checkbox, outputs=param_group)
211
+
212
+ # Apply edge detection immediately on startup
213
+ app.load(fn=update_output, inputs=inputs, outputs=output_image)
214
+
215
+ # Examples
216
+ if examples:
217
+ gr.Examples(examples=examples, inputs=input_image, label="Example Images" )
218
+
219
+ if __name__ == "__main__":
220
+ app.launch()
requirements.txt CHANGED
@@ -1,2 +1,2 @@
1
- gradio==3.44.4
2
- opencv-contrib-python==4.8.0.76
 
1
+ gradio==5.39.0
2
+ opencv-contrib-python>=4.12