Afeezee commited on
Commit
6bcb3da
·
verified ·
1 Parent(s): 7e677c1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -0
app.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import gradio as gr
4
+
5
+ def process_image(image, calibration_factor):
6
+ """
7
+ Processes the input image to measure the hair diameter.
8
+
9
+ Args:
10
+ image (numpy array): Uploaded image in RGB format.
11
+ calibration_factor (float): Conversion factor from pixels to micrometers.
12
+
13
+ Returns:
14
+ tuple: A result text and the annotated image.
15
+ """
16
+ if image is None:
17
+ return "No image provided.", None
18
+
19
+ # Convert image from RGB (Gradio default) to BGR (OpenCV default)
20
+ image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
21
+
22
+ # Convert to grayscale
23
+ gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
24
+
25
+ # Apply Gaussian blur to reduce noise
26
+ blurred = cv2.GaussianBlur(gray, (5, 5), 0)
27
+
28
+ # Apply thresholding (using Otsu's method) to create a binary image
29
+ ret, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
30
+
31
+ # Find contours in the thresholded image
32
+ contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
33
+
34
+ if not contours:
35
+ return "No hair contour found.", image
36
+
37
+ # Assume the hair strand is the largest contour
38
+ hair_contour = max(contours, key=cv2.contourArea)
39
+
40
+ # Fit a minimum area rectangle to the contour
41
+ rect = cv2.minAreaRect(hair_contour)
42
+ (center, (width, height), angle) = rect
43
+
44
+ # The smaller dimension is considered the hair's diameter in pixels
45
+ diameter_pixels = min(width, height)
46
+ diameter_real = diameter_pixels * calibration_factor # Convert to micrometers
47
+
48
+ # Draw the fitted rectangle on the image for visualization
49
+ box = cv2.boxPoints(rect)
50
+ box = np.int0(box)
51
+ annotated = image_bgr.copy()
52
+ cv2.drawContours(annotated, [box], 0, (0, 255, 0), 2)
53
+
54
+ # Convert annotated image back to RGB for Gradio display
55
+ annotated_rgb = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
56
+
57
+ result_text = f"Estimated Hair Diameter: {diameter_real:.2f} micrometers"
58
+ return result_text, annotated_rgb
59
+
60
+ # Build the Gradio interface
61
+ iface = gr.Interface(
62
+ fn=process_image,
63
+ inputs=[
64
+ gr.Image(type="numpy", label="Upload Hair Image"),
65
+ gr.Number(value=0.5, label="Calibration Factor (micrometers per pixel)")
66
+ ],
67
+ outputs=[
68
+ gr.Textbox(label="Result"),
69
+ gr.Image(label="Annotated Image")
70
+ ],
71
+ title="Hair Diameter Measurement Tool",
72
+ description=(
73
+ "Upload a high-resolution image of a hair sample (captured with a dermascope) "
74
+ "and provide a calibration factor based on a reference object included in the image. "
75
+ "This tool processes the image to estimate the hair diameter using image processing techniques."
76
+ )
77
+ )
78
+
79
+ if __name__ == '__main__':
80
+ iface.launch()