Shri Jayaram commited on
Commit
ca5acf7
·
1 Parent(s): 5840fb7

fixes & changes closed

Browse files
Files changed (1) hide show
  1. app.py +94 -33
app.py CHANGED
@@ -95,10 +95,31 @@ def calculate_pip_width(image, original_img, pixel_per_metric):
95
  cv2.circle(img, (int(xB), int(yB)), 5, color_circle, -1)
96
  cv2.line(img, (int(xA), int(yA)), (int(xB), int(yB)), color_line, 2)
97
  d_mm = d / pixel_per_metric
98
- d_mm = d_mm - 2.5
99
  cv2.putText(img, "{:.1f}".format(d_mm), (int(xA - 15), int(yA - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2)
100
- # print(d_mm)
101
- return d_mm, img
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  og_img = original_img.copy()
104
  imgH, imgW, _ = image.shape
@@ -111,18 +132,15 @@ def calculate_pip_width(image, original_img, pixel_per_metric):
111
  cv2.drawContours(imgcpy, contours, -1, (0, 255, 0), 2)
112
  # print("length : ",len(contours))
113
 
114
- d_mm = 0
115
  marked_img = image.copy()
116
 
117
  if len(contours) > 0:
118
- # print("hi")
119
  cnt = max(contours, key=cv2.contourArea)
120
  frame2 = cv2.cvtColor(og_img, cv2.COLOR_BGR2RGB)
121
  handsLM = mp.solutions.hands.Hands(max_num_hands=1, min_detection_confidence=0.8, min_tracking_confidence=0.8)
122
  pr = handsLM.process(frame2)
123
- # print(pr.multi_hand_landmarks)
124
  if pr.multi_hand_landmarks:
125
- # print("inside")
126
  for hand_landmarks in pr.multi_hand_landmarks:
127
  lmlist = []
128
  for id, landMark in enumerate(hand_landmarks.landmark):
@@ -133,39 +151,67 @@ def calculate_pip_width(image, original_img, pixel_per_metric):
133
  pip_joint = [lmlist[14][1], lmlist[14][2]]
134
  mcp_joint = [lmlist[13][1], lmlist[13][2]]
135
 
 
 
 
 
136
  m2 = (pip_joint[1] - mcp_joint[1]) / (pip_joint[0] - mcp_joint[0])
137
  m1 = -1 / m2
138
  b = pip_joint[1] - m1 * pip_joint[0]
139
 
140
- x1, x2 = pip_joint[0], pip_joint[0]
141
- y1 = m1 * x1 + b
142
- y2 = m1 * x2 + b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
- result = 1.0
145
- while result > 0:
146
- result = cv2.pointPolygonTest(cnt, (x1, y1), False)
147
- x1 += 1
148
- y1 = m1 * x1 + b
149
- x1 -= 1
150
 
151
- result = 1.0
152
- while result > 0:
153
- result = cv2.pointPolygonTest(cnt, (x2, y2), False)
154
- x2 -= 1
155
- y2 = m1 * x2 + b
156
- x2 += 1
157
 
158
- d_mm, marked_img = calSize(x1, y1, x2, y2, (255, 0, 0), (255, 0, 255), original_img)
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
- return original_img, d_mm, imgcpy, marked_img
161
 
162
  def show_resized_image(images, titles, scale=0.5):
163
  num_images = len(images)
164
- fig, axes = plt.subplots(1, num_images, figsize=(15, 5))
165
-
166
- if num_images == 1:
167
- axes = [axes]
168
 
 
 
 
169
  for ax, img, title in zip(axes, images, titles):
170
  resized_image = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)
171
  ax.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
@@ -187,12 +233,24 @@ def get_ring_size(mm_value):
187
  return ring_size_dict[closest_mm]
188
 
189
  st.set_page_config(layout="wide", page_title="Ring Size Measurement")
190
-
191
  st.write("## Determine Your Ring Size")
192
  st.write(
193
- "📏 Upload an image of your finger to measure the width and determine your ring size. The measurement will be displayed along with a visual breakdown of the image processing flow."
194
  )
195
  st.sidebar.write("## Upload :gear:")
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
  MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
198
 
@@ -204,6 +262,8 @@ def process_image_and_get_results(upload):
204
  original_img = image_np.copy()
205
  og_img1 = image_np.copy()
206
  og_img2 = image_np.copy()
 
 
207
 
208
  pixel_per_metric, mm_per_pixel, image_with_coin_info = calculate_pixel_per_metric(image_np)
209
  processed_image = process_image(og_img1)
@@ -211,8 +271,9 @@ def process_image_and_get_results(upload):
211
 
212
  ring_size = get_ring_size(width_mm)
213
  return {
214
- "processed_image": pip_mark_img,
215
  "original_image": og_img2,
 
216
  "image_with_coin_info": image_with_coin_info,
217
  "contour_image": contour_image,
218
  "width_mm": width_mm,
@@ -246,8 +307,8 @@ if my_upload is not None:
246
  st.write("## How It Works")
247
  st.write("Here's a step-by-step breakdown of how your image is processed to determine your ring size:")
248
  img_stream = show_resized_image(
249
- [results["original_image"], results["image_with_coin_info"], results["contour_image"], results["processed_image"]],
250
- ['Original Image', 'Image with Coin Info', 'Contour Boundary Image', 'Ring Finger Width'],
251
  scale=0.5
252
  )
253
  st.image(img_stream, caption="Processing Flow", use_column_width=True)
 
95
  cv2.circle(img, (int(xB), int(yB)), 5, color_circle, -1)
96
  cv2.line(img, (int(xA), int(yA)), (int(xB), int(yB)), color_line, 2)
97
  d_mm = d / pixel_per_metric
98
+ d_mm = d_mm - 1.5
99
  cv2.putText(img, "{:.1f}".format(d_mm), (int(xA - 15), int(yA - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2)
100
+ print(d_mm)
101
+ return d_mm
102
+
103
+ def process_point(point, cnt, m1, b):
104
+ x1, x2 = point[0], point[0]
105
+ y1 = m1 * x1 + b
106
+ y2 = m1 * x2 + b
107
+
108
+ result = 1.0
109
+ while result > 0:
110
+ result = cv2.pointPolygonTest(cnt, (x1, y1), False)
111
+ x1 += 1
112
+ y1 = m1 * x1 + b
113
+ x1 -= 1
114
+
115
+ result = 1.0
116
+ while result > 0:
117
+ result = cv2.pointPolygonTest(cnt, (x2, y2), False)
118
+ x2 -= 1
119
+ y2 = m1 * x2 + b
120
+ x2 += 1
121
+
122
+ return x1, y1, x2, y2
123
 
124
  og_img = original_img.copy()
125
  imgH, imgW, _ = image.shape
 
132
  cv2.drawContours(imgcpy, contours, -1, (0, 255, 0), 2)
133
  # print("length : ",len(contours))
134
 
 
135
  marked_img = image.copy()
136
 
137
  if len(contours) > 0:
 
138
  cnt = max(contours, key=cv2.contourArea)
139
  frame2 = cv2.cvtColor(og_img, cv2.COLOR_BGR2RGB)
140
  handsLM = mp.solutions.hands.Hands(max_num_hands=1, min_detection_confidence=0.8, min_tracking_confidence=0.8)
141
  pr = handsLM.process(frame2)
142
+ print(pr.multi_hand_landmarks)
143
  if pr.multi_hand_landmarks:
 
144
  for hand_landmarks in pr.multi_hand_landmarks:
145
  lmlist = []
146
  for id, landMark in enumerate(hand_landmarks.landmark):
 
151
  pip_joint = [lmlist[14][1], lmlist[14][2]]
152
  mcp_joint = [lmlist[13][1], lmlist[13][2]]
153
 
154
+ midpoint_x = (pip_joint[0] + mcp_joint[0]) / 2
155
+ midpoint_y = (pip_joint[1] + mcp_joint[1]) / 2
156
+ midpoint = [midpoint_x, midpoint_y]
157
+
158
  m2 = (pip_joint[1] - mcp_joint[1]) / (pip_joint[0] - mcp_joint[0])
159
  m1 = -1 / m2
160
  b = pip_joint[1] - m1 * pip_joint[0]
161
 
162
+ #pip_joint
163
+ x1_pip, y1_pip, x2_pip, y2_pip = process_point(pip_joint, cnt, m1, b)
164
+
165
+ m2 = (midpoint_y - mcp_joint[1]) / (midpoint_x - mcp_joint[0])
166
+ m1 = -1 / m2
167
+ b = midpoint_y - m1 * midpoint_x
168
+
169
+ #midpoint
170
+ x1_mid, y1_mid, x2_mid, y2_mid = process_point(midpoint, cnt, m1, b)
171
+
172
+ d_mm_pip = calSize(x1_pip, y1_pip, x2_pip, y2_pip, (255, 0, 0), (255, 0, 255), original_img)
173
+ d_mm_mid = calSize(x1_mid, y1_mid, x2_mid, y2_mid, (0, 255, 0), (0, 0, 255), original_img)
174
+
175
+ largest_d_mm = max(int(d_mm_mid),int(d_mm_pip))
176
+ return original_img, largest_d_mm, imgcpy, marked_img
177
+
178
+ def mark_hand_landmarks(image_path):
179
+
180
+ mp_hands = mp.solutions.hands
181
+ hands = mp_hands.Hands()
182
+ mp_draw = mp.solutions.drawing_utils
183
 
184
+ img = image_path
185
+ img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
 
 
 
 
186
 
187
+ results = hands.process(img_rgb)
 
 
 
 
 
188
 
189
+ if results.multi_hand_landmarks:
190
+ for hand_landmarks in results.multi_hand_landmarks:
191
+ mp_draw.draw_landmarks(img, hand_landmarks, mp_hands.HAND_CONNECTIONS)
192
+
193
+ mcp = hand_landmarks.landmark[13]
194
+ pip = hand_landmarks.landmark[14]
195
+
196
+ img_height, img_width, _ = img.shape
197
+
198
+ mcp_x, mcp_y = int(mcp.x * img_width), int(mcp.y * img_height)
199
+ pip_x, pip_y = int(pip.x * img_width), int(pip.y * img_height)
200
+
201
+ cv2.circle(img, (mcp_x, mcp_y), 10, (255, 0, 0), -1)
202
+ cv2.circle(img, (pip_x, pip_y), 10, (255, 0, 0), -1)
203
 
204
+ return img
205
 
206
  def show_resized_image(images, titles, scale=0.5):
207
  num_images = len(images)
208
+
209
+ fig, axes = plt.subplots(2, 3, figsize=(17, 13))
210
+ axes = axes.flatten()
 
211
 
212
+ for ax in axes[num_images:]:
213
+ ax.axis('off')
214
+
215
  for ax, img, title in zip(axes, images, titles):
216
  resized_image = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)
217
  ax.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
 
233
  return ring_size_dict[closest_mm]
234
 
235
  st.set_page_config(layout="wide", page_title="Ring Size Measurement")
 
236
  st.write("## Determine Your Ring Size")
237
  st.write(
238
+ "📏 Upload an image of your hand to measure the finger width and determine your ring size. The measurement will be displayed along with a visual breakdown of the image processing flow."
239
  )
240
  st.sidebar.write("## Upload :gear:")
241
+ #~~
242
+ st.write("### Workflow Overview")
243
+ st.image("FlowChart.png", caption="Workflow Overview", use_column_width=True)
244
+
245
+ st.write("### Detailed Workflow")
246
+ st.write("1. **Hough Circle Transform:** The Hough Circle Transform is a technique used to detect circles in an image. It works by transforming the image into a parameter space, identifying circles based on their radius and center coordinates. This method is effective for locating circular objects, such as a coin, within the image.")
247
+ st.write("2. **Pixel Per Metric Ratio:** The Pixel Per Metric Ratio is used to convert pixel measurements into real-world units. By comparing the pixel length obtained from image analysis (i.e., Hough Circle) with the known real-world measurement of the reference object (coin), we get the ratio. This ratio then allows us to accurately scale and size estimation of objects within the image.")
248
+ st.write("3. **Background Removal:** Removing the background first ensures that only the relevant subject is highlighted. We start by converting the image to grayscale and applying thresholding to distinguish the subject from the background. Erosion and dilation then clean up the image, improving the detection of specific features like individual fingers.")
249
+ st.write("4. **Contour Detection:** We use Contour Detection to find the largest contour, which allows us to outline or draw a boundary around the subject (i.e., hand). This highlights the object's shape and edges, improving the precision of the subject.")
250
+ st.write("5. **Finding Hand Landmarks:** This involves using the MediaPipe library to identify key points on the hand, such as the PIP (Proximal Interphalangeal) and MCP (Metacarpophalangeal) joints of the ring finger. This enables precise tracking and analysis of finger positions and movements.")
251
+ st.write("6. **Determining Finger Width:** Here we use the slope formula `[y = mx + b]` with PIP and MCP points to measure the finger's width. We project outward perpendicularly from the PIP point towards the MCP point, then apply a point polygon test to accurately determine the pixel width of the finger.")
252
+ st.write("7. **Predicting Ring Size:** Predicting Ring Size involves calculating the finger’s diameter using the Pixel Per Metric Ratio and the largest width measurement at the PIP or MCP joint. This diameter is then used to predict the appropriate ring size.")
253
+ #~~
254
 
255
  MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
256
 
 
262
  original_img = image_np.copy()
263
  og_img1 = image_np.copy()
264
  og_img2 = image_np.copy()
265
+ img_1 = image_np.copy()
266
+ hand_lms = mark_hand_landmarks(img_1)
267
 
268
  pixel_per_metric, mm_per_pixel, image_with_coin_info = calculate_pixel_per_metric(image_np)
269
  processed_image = process_image(og_img1)
 
271
 
272
  ring_size = get_ring_size(width_mm)
273
  return {
274
+ "processed_image": image_with_pip_width,
275
  "original_image": og_img2,
276
+ "hand_lm_marked_image": hand_lms,
277
  "image_with_coin_info": image_with_coin_info,
278
  "contour_image": contour_image,
279
  "width_mm": width_mm,
 
307
  st.write("## How It Works")
308
  st.write("Here's a step-by-step breakdown of how your image is processed to determine your ring size:")
309
  img_stream = show_resized_image(
310
+ [results["original_image"], results["image_with_coin_info"], results["contour_image"], results["hand_lm_marked_image"], results["processed_image"]],
311
+ ['Original Image', 'Image with Coin Info', 'Contour Boundary Image', 'Hand Landmarks', 'Ring Finger Width'],
312
  scale=0.5
313
  )
314
  st.image(img_stream, caption="Processing Flow", use_column_width=True)