Spaces:
Running
Running
File size: 8,749 Bytes
d1df3f4 5e568dc 1c48bcd d1df3f4 1c48bcd 5e568dc d1df3f4 1c48bcd d1df3f4 88f1d1e d1df3f4 e310885 d1df3f4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
import glob
import os
import cv2
import gradio as gr
def center_crop_mod64(img):
"""Crop image to largest area that's divisible by 64"""
h, w = img.shape[:2]
shortside, longside = min(w, h), max(w, h)
longside_crop = (longside // 64) * 64
left = (w - longside_crop) // 2 if w > h else 0
top = (h - longside_crop) // 2 if h > w else 0
right = left + longside_crop if w > h else shortside
bottom = top + longside_crop if h > w else shortside
return img[top:bottom, left:right]
def load_example_images():
"""Load all images from images/ directory"""
image_dir = os.path.join(os.path.dirname(__file__), "images")
if not os.path.exists(image_dir):
return []
extensions = ['*.png', '*.jpg', '*.jpeg', '*.webp']
examples = []
for ext in extensions:
examples.extend(glob.glob(os.path.join(image_dir, ext)))
examples.extend(glob.glob(os.path.join(image_dir, ext.upper())))
return sorted(examples)
def apply_edge_detection(image_rgb, algorithm, apply_crop, convert2grayscale, params):
"""Apply selected edge detection algorithm with specified parameters"""
if image_rgb is None:
return None
# Apply cropping if requested
if apply_crop:
img_processed = center_crop_mod64(image_rgb)
else:
img_processed = image_rgb.copy()
# Convert to grayscale if requested
if convert2grayscale and len(img_processed.shape) == 3:
img_input = cv2.cvtColor(cv2.cvtColor(img_processed, cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB)
else:
img_input = img_processed
ret = img_input.copy()
# set parameters
# Detect edges
ed = cv2.ximgproc.createEdgeDrawing()
ed.setParams(params)
ed.detectEdges(img_input)
if algorithm == "Edges":
ret = ed.getEdgeImage()
return ret
elif algorithm == "Lines":
lines = ed.detectLines()
# draw lines
if lines is not None:
for line in lines:
x1, y1, x2, y2 = map(int, line[0])
cv2.line(ret, (x1, y1), (x2, y2), (0, 255, 0), 1)
return ret
elif algorithm == "Ellipses":
ellipsess = ed.detectEllipses()
# draw ellipses
if ellipsess is not None:
for ellipses in ellipsess:
ellipse = ellipses[0]
center = (int(ellipse[0]), int(ellipse[1]))
if ellipse[2] == 0: # Ellipse
axes = (int(ellipse[3]), int(ellipse[4]))
angle = ellipse[5]
cv2.ellipse(ret, center, axes, angle, 0, 360, (0, 255, 0), 1)
else: # Circle
radius = int(ellipse[2])
cv2.circle(ret, center, radius, (0, 255, 0), 1)
return ret
return img_input
# Create Gradio interface
with gr.Blocks(title="Edge Drawing") as app:
examples = load_example_images()
gr.Markdown("# Enhanced Edge Detection using [Edge Drawing](https://github.com/CihanTopal/ED_Lib) with [opencv-contrib-python](https://docs.opencv.org/4.x/d1/d1c/classcv_1_1ximgproc_1_1EdgeDrawing.html)")
# Image row - Input and Output side by side
with gr.Row():
input_image = gr.Image(value=examples[0] if examples else None , label="Input Image" , type="numpy")
output_image = gr.Image(value=None , label="Detection Result" , type="numpy")
# Controls row - Processing Options on left, Parameters on right
with gr.Row():
# Processing Options
with gr.Column():
with gr.Group():
gr.Markdown("### Processing Options")
algorithm_radio = gr.Radio(label="Detection mode", value="Edges", choices=["Edges", "Lines", "Ellipses"])
paramterfree_checkbox = gr.Checkbox(label ="Parameter Free Mode" , value=True , info="Auto-determine optimal parameters")
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)")
crop_checkbox = gr.Checkbox(label ="Apply center crop mod-64" , value=False , info="Crop to largest area divisible by 64 (used for Stable Diffusion)")
# EdgeDrawing Parameters
with gr.Column():
with gr.Group():
gr.Markdown("### Edge Drawing Parameters")
# Parameter controls group (disabled by default)
with gr.Group(visible=False) as param_group:
with gr.Column():
with gr.Row():
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")
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" )
with gr.Row():
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" )
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" )
with gr.Row():
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" )
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" )
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" )
with gr.Row():
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" )
scan_interval = gr.Slider(minimum= 1 , maximum= 10 , value= 1 , step= 1 , label="Scan Interval" , scale= 1 , info="Default value is 1" )
with gr.Row():
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" )
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")
sum_flag = gr.Checkbox(label="Sum Flag" , value=True , info="Default value is true")
# Update function
def update_output(
image_rgb, algorithm, apply_crop, conv2grayscale, pf_mode,
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
):
operator_map = {
"PREWITT" : cv2.ximgproc.EdgeDrawing_PREWITT,
"SOBEL" : cv2.ximgproc.EdgeDrawing_SOBEL,
"SCHARR" : cv2.ximgproc.EdgeDrawing_SCHARR,
"LSD" : cv2.ximgproc.EdgeDrawing_LSD,
}
params = cv2.ximgproc.EdgeDrawing.Params()
params.PFmode = pf_mode
params.EdgeDetectionOperator = operator_map.get(gradient_operator, cv2.ximgproc.EdgeDrawing_PREWITT)
if not pf_mode:
params.AnchorThresholdValue = anchor_threshold
params.GradientThresholdValue = gradient_threshold
params.MinPathLength = min_path_length
params.MinLineLength = min_line_length
params.LineFitErrorThreshold = line_fit_error_threshold
params.MaxDistanceBetweenTwoLines = max_distance_between_two_lines
params.MaxErrorThreshold = max_error_threshold
params.NFAValidation = nfa_validation
params.ScanInterval = scan_interval
params.Sigma = sigma
params.SumFlag = sum_flag
ret = apply_edge_detection(image_rgb, algorithm, apply_crop, conv2grayscale, params)
return ret
# Function to toggle parameter group visibility
def toggle_params(pf_mode):
return gr.Group(visible=not pf_mode)
# Set up event handlers
inputs = [
input_image,
algorithm_radio,
crop_checkbox,
convert2grayscale_checkbox,
paramterfree_checkbox,
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,
]
# Update output when any input changes
for inp in inputs:
inp.change(fn=update_output, inputs=inputs, outputs=output_image)
# Toggle parameter group when parameter free mode changes
paramterfree_checkbox.change(fn=toggle_params, inputs=paramterfree_checkbox, outputs=param_group)
# Apply edge detection immediately on startup
app.load(fn=update_output, inputs=inputs, outputs=output_image)
# Examples
if examples:
gr.Examples(examples=examples, inputs=input_image, label="Example Images" )
if __name__ == "__main__":
app.launch()
|