Spaces:
Sleeping
Sleeping
Upload 18 files
Browse files- app.py +79 -66
- utils/__pycache__/plot.cpython-310.pyc +0 -0
- utils/plot.py +9 -2
app.py
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import cv2
|
2 |
import gradio as gr
|
3 |
import pandas as pd
|
@@ -32,15 +33,17 @@ css = """
|
|
32 |
# Create the Gradio interface using defined theme and CSS
|
33 |
with gr.Blocks(theme=theme, css=css) as demo:
|
34 |
# Title and description for the app
|
35 |
-
gr.Markdown("# Concrete Crack
|
36 |
-
gr.Markdown("Upload concrete crack images and get segmented results.")
|
37 |
with gr.Tab('Instructions'):
|
38 |
gr.Markdown(
|
39 |
"""**Instructions for Concrete Crack Detection and Segmentation App:**
|
40 |
|
41 |
**Input:**
|
42 |
- Upload one or more concrete crack images using the "Image Input" section.
|
43 |
-
- Adjust confidence level and distance sliders if needed
|
|
|
|
|
44 |
**Buttons:**
|
45 |
- Click "Segment" to perform crack segmentation.
|
46 |
- Click "Clear" to reset inputs and outputs.\n
|
@@ -51,7 +54,7 @@ with gr.Blocks(theme=theme, css=css) as demo:
|
|
51 |
|
52 |
**Additional Information:**
|
53 |
- The app uses a YOLOv8 trained model for crack detection with 86.8\% accuracy.
|
54 |
-
- Results include orientation category, width of the crack (widest), number of cracks per photo.
|
55 |
|
56 |
**Notes:**
|
57 |
- Ensure uploaded images are in the supported formats: PNG, JPG, JPEG, WEBP.
|
@@ -198,79 +201,89 @@ with gr.Blocks(theme=theme, css=css) as demo:
|
|
198 |
filenames = [file.name for file in image]
|
199 |
conf= conf * 0.01
|
200 |
model = load_model()
|
201 |
-
|
202 |
processed_image_paths = []
|
203 |
output_image_paths = []
|
204 |
result_list = []
|
205 |
width_list = []
|
206 |
orientation_list = []
|
207 |
width_interpretations = []
|
|
|
208 |
# Populate the dataframe with counts
|
209 |
-
for i,
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
|
269 |
# Delete binarized and initial segmented images after processing
|
270 |
for path in processed_image_paths:
|
271 |
if os.path.exists(path):
|
272 |
-
os.
|
273 |
-
|
|
|
|
|
274 |
# results = gr.Textbox(res, visible=True)
|
275 |
csv, df = pt.count_instance(result_list, filenames, uuid, width_list, orientation_list, output_image_paths, reference, remark, width_interpretations)
|
276 |
|
|
|
1 |
+
import shutil
|
2 |
import cv2
|
3 |
import gradio as gr
|
4 |
import pandas as pd
|
|
|
33 |
# Create the Gradio interface using defined theme and CSS
|
34 |
with gr.Blocks(theme=theme, css=css) as demo:
|
35 |
# Title and description for the app
|
36 |
+
gr.Markdown("# Concrete Crack Segmentation and Documentation")
|
37 |
+
gr.Markdown("Upload concrete crack images and get segmented results with pdf report.")
|
38 |
with gr.Tab('Instructions'):
|
39 |
gr.Markdown(
|
40 |
"""**Instructions for Concrete Crack Detection and Segmentation App:**
|
41 |
|
42 |
**Input:**
|
43 |
- Upload one or more concrete crack images using the "Image Input" section.
|
44 |
+
- Adjust confidence level and distance sliders if needed.
|
45 |
+
- Upload reference images. (e.g. whole wall with many cracks)
|
46 |
+
- Input Remarks (e.g. First floor wall on the left)\n
|
47 |
**Buttons:**
|
48 |
- Click "Segment" to perform crack segmentation.
|
49 |
- Click "Clear" to reset inputs and outputs.\n
|
|
|
54 |
|
55 |
**Additional Information:**
|
56 |
- The app uses a YOLOv8 trained model for crack detection with 86.8\% accuracy.
|
57 |
+
- Results include orientation category, width of the crack (widest), number of cracks per photo, and damage level.
|
58 |
|
59 |
**Notes:**
|
60 |
- Ensure uploaded images are in the supported formats: PNG, JPG, JPEG, WEBP.
|
|
|
201 |
filenames = [file.name for file in image]
|
202 |
conf= conf * 0.01
|
203 |
model = load_model()
|
204 |
+
|
205 |
processed_image_paths = []
|
206 |
output_image_paths = []
|
207 |
result_list = []
|
208 |
width_list = []
|
209 |
orientation_list = []
|
210 |
width_interpretations = []
|
211 |
+
folder_name = []
|
212 |
# Populate the dataframe with counts
|
213 |
+
for i, image_path in enumerate(image):
|
214 |
+
results = model.predict(image_path, conf=conf, save=True, project='output', name=f'{uuid}{i}', stream=True)
|
215 |
+
for r in results:
|
216 |
+
result_list.append(r)
|
217 |
+
instance_count = len(r)
|
218 |
+
if r.masks is not None and r.masks.data.numel() > 0:
|
219 |
+
masks = r.masks.data
|
220 |
+
boxes = r.boxes.data
|
221 |
+
clss = boxes[:, 5]
|
222 |
+
people_indices = torch.where(clss == 0)
|
223 |
+
people_masks = masks[people_indices]
|
224 |
+
people_mask = torch.any(people_masks, dim=0).int() * 255
|
225 |
+
processed_image_path = str(f'output/{uuid}0/binarize{i}.jpg')
|
226 |
+
cv2.imwrite(processed_image_path, people_mask.cpu().numpy())
|
227 |
+
processed_image_paths.append(processed_image_path)
|
228 |
+
|
229 |
+
crack_image_path = processed_image_path
|
230 |
+
principal_orientation, orientation_category = detect_pattern(crack_image_path)
|
231 |
+
|
232 |
+
# Print the results if needed
|
233 |
+
print(f"Crack Detection Results for {crack_image_path}:")
|
234 |
+
print("Principal Component Analysis Orientation:", principal_orientation)
|
235 |
+
print("Orientation Category:", orientation_category)
|
236 |
+
if i>0:
|
237 |
+
processed_image_paths.append(f'output/{uuid}{i}')
|
238 |
+
#transfer item to current folder
|
239 |
+
the_paths = f'output/{uuid}{i}/{os.path.basename(image_path)}'
|
240 |
+
print(the_paths)
|
241 |
+
shutil.copyfile(the_paths, f'output/{uuid}0/image{i}.jpg')
|
242 |
+
# Load the original image in color
|
243 |
+
original_img = cv2.imread(f'output/{uuid}0/image{i}.jpg')
|
244 |
+
orig_image_path = str(f'output/{uuid}0/image{i}.jpg')
|
245 |
+
processed_image_paths.append(orig_image_path)
|
246 |
+
# Load and resize the binary image to match the dimensions of the original image
|
247 |
+
binary_image = cv2.imread(f'output/{uuid}0/binarize{i}.jpg', cv2.IMREAD_GRAYSCALE)
|
248 |
+
binary_image = cv2.resize(binary_image, (original_img.shape[1], original_img.shape[0]))
|
249 |
+
|
250 |
+
contour_analyzer = ContourAnalyzer()
|
251 |
+
max_width, thickest_section, thickest_points, distance_transforms = contour_analyzer.find_contours(binary_image)
|
252 |
+
|
253 |
+
visualized_image = original_img.copy()
|
254 |
+
cv2.drawContours(visualized_image, [thickest_section], 0, (0, 255, 0), 1)
|
255 |
+
|
256 |
+
contour_analyzer.draw_circle_on_image(visualized_image, (int(thickest_points[0]), int(thickest_points[1])), 5, (57, 255, 20), -1)
|
257 |
+
print("Max Width in pixels: ", max_width)
|
258 |
+
|
259 |
+
width = contour_analyzer.calculate_width(y=10, x=5, pixel_width=max_width, calibration_factor=0.001, distance=150)
|
260 |
+
print("Max Width, converted: ", width)
|
261 |
+
|
262 |
+
prets = pt.classify_wall_damage(width)
|
263 |
+
width_interpretations.append(prets)
|
264 |
+
|
265 |
+
visualized_image_path = f'output/{uuid}0/visualized_image{i}.jpg'
|
266 |
+
output_image_paths.append(visualized_image_path)
|
267 |
+
cv2.imwrite(visualized_image_path, visualized_image)
|
268 |
+
|
269 |
+
width_list.append(round(width, 2))
|
270 |
+
orientation_list.append(orientation_category)
|
271 |
+
else:
|
272 |
+
original_img = cv2.imread(f'output/{uuid}0/image{i}.jpg')
|
273 |
+
visualized_image_path = f'output/{uuid}0/visualized_image{i}.jpg'
|
274 |
+
output_image_paths.append(visualized_image_path)
|
275 |
+
cv2.imwrite(visualized_image_path, original_img)
|
276 |
+
width_list.append('None')
|
277 |
+
orientation_list.append('None')
|
278 |
+
width_interpretations.append('None')
|
279 |
|
280 |
# Delete binarized and initial segmented images after processing
|
281 |
for path in processed_image_paths:
|
282 |
if os.path.exists(path):
|
283 |
+
if os.path.isfile(path):
|
284 |
+
os.remove(path)
|
285 |
+
elif os.path.isdir(path):
|
286 |
+
shutil.rmtree(path)
|
287 |
# results = gr.Textbox(res, visible=True)
|
288 |
csv, df = pt.count_instance(result_list, filenames, uuid, width_list, orientation_list, output_image_paths, reference, remark, width_interpretations)
|
289 |
|
utils/__pycache__/plot.cpython-310.pyc
CHANGED
Binary files a/utils/__pycache__/plot.cpython-310.pyc and b/utils/__pycache__/plot.cpython-310.pyc differ
|
|
utils/plot.py
CHANGED
@@ -78,6 +78,8 @@ def count_instance(result, filenames, uuid, width_list, orientation_list, image_
|
|
78 |
tuple: Path to the generated CSV and dataframe with counts.
|
79 |
"""
|
80 |
# Initializing the dataframe
|
|
|
|
|
81 |
print(damage)
|
82 |
data = {
|
83 |
'Index': [],
|
@@ -177,8 +179,13 @@ def count_instance(result, filenames, uuid, width_list, orientation_list, image_
|
|
177 |
|
178 |
merger.write(f'output/{uuid}/report.pdf')
|
179 |
merger.close()
|
180 |
-
|
181 |
-
|
|
|
|
|
|
|
|
|
|
|
182 |
return f'output/{uuid}/report.pdf', df
|
183 |
|
184 |
|
|
|
78 |
tuple: Path to the generated CSV and dataframe with counts.
|
79 |
"""
|
80 |
# Initializing the dataframe
|
81 |
+
uuid= f'{uuid}0'
|
82 |
+
print(uuid)
|
83 |
print(damage)
|
84 |
data = {
|
85 |
'Index': [],
|
|
|
179 |
|
180 |
merger.write(f'output/{uuid}/report.pdf')
|
181 |
merger.close()
|
182 |
+
|
183 |
+
paths = [f'output/{uuid}/df_batch.html', f'output/{uuid}/df_ref_summary.html',
|
184 |
+
f'output/{uuid}/df_ref.html', f'output/{uuid}/out.html',
|
185 |
+
f'output/{uuid}/report_batch.pdf', f'output/{uuid}/report_ref.pdf']
|
186 |
+
for path in paths:
|
187 |
+
if os.path.exists(path):
|
188 |
+
os.remove(path)
|
189 |
return f'output/{uuid}/report.pdf', df
|
190 |
|
191 |
|