mlbench123 commited on
Commit
ebb091d
·
verified ·
1 Parent(s): 4cb75c5

Update scalingtestupdated.py

Browse files
Files changed (1) hide show
  1. scalingtestupdated.py +200 -85
scalingtestupdated.py CHANGED
@@ -2,7 +2,7 @@ import cv2
2
  import numpy as np
3
  import os
4
  import argparse
5
- from typing import Union
6
  from matplotlib import pyplot as plt
7
 
8
  class ScalingSquareDetector:
@@ -33,8 +33,7 @@ class ScalingSquareDetector:
33
  ):
34
  """
35
  Detect the scaling square in the target image based on the reference image.
36
- :param reference_image_path: Path to the reference image of the square.
37
- :param target_image_path: Path to the target image containing the square.
38
  :param known_size_mm: Physical size of the square in millimeters.
39
  :param roi_margin: Margin to expand the ROI around the detected square (in pixels).
40
  :return: Scaling factor (mm per pixel).
@@ -44,54 +43,38 @@ class ScalingSquareDetector:
44
  )
45
 
46
  if not contours:
47
- raise ValueError("No contours found in the cropped ROI.")
48
 
49
- # # Select the largest square-like contour
50
  print(f"No of contours: {len(contours)}")
51
- largest_square = None
52
- # largest_square_area = 0
53
- # for contour in contours:
54
- # x_c, y_c, w_c, h_c = cv2.boundingRect(contour)
55
- # aspect_ratio = w_c / float(h_c)
56
- # if 0.9 <= aspect_ratio <= 1.1:
57
- # peri = cv2.arcLength(contour, True)
58
- # approx = cv2.approxPolyDP(contour, 0.02 * peri, True)
59
- # if len(approx) == 4:
60
- # area = cv2.contourArea(contour)
61
- # if area > largest_square_area:
62
- # largest_square = contour
63
- # largest_square_area = area
64
-
65
- for contour in contours:
66
- largest_square = contour
67
-
68
- # if largest_square is None:
69
- # raise ValueError("No square-like contour found in the ROI.")
70
-
71
- # Draw the largest contour on the original image
72
  target_image_color = cv2.cvtColor(target_image, cv2.COLOR_GRAY2BGR)
73
  cv2.drawContours(
74
- target_image_color, largest_square, -1, (255, 0, 0), 3
75
  )
76
 
77
- # if self.debug:
78
- cv2.imwrite("largest_contour.jpg", target_image_color)
79
 
80
  # Calculate the bounding rectangle of the largest contour
81
- x, y, w, h = cv2.boundingRect(largest_square)
82
  square_width_px = w
83
  square_height_px = h
84
- print(f"Reference object size: {known_size_mm} mm")
85
- print(f"width: {square_width_px} px")
86
- print(f"height: {square_height_px} px")
 
87
 
88
- # Calculate the scaling factor
89
  avg_square_size_px = (square_width_px + square_height_px) / 2
90
- print(f"avg square size: {avg_square_size_px} px")
 
91
  scaling_factor = known_size_mm / avg_square_size_px # mm per pixel
92
- print(f"scaling factor: {scaling_factor} mm per pixel")
93
 
94
- return scaling_factor #, square_height_px, square_width_px, roi_binary
95
 
96
  def draw_debug_images(self, output_folder):
97
  """
@@ -113,7 +96,17 @@ def calculate_scaling_factor(
113
  feature_detector="ORB",
114
  debug=False,
115
  roi_margin=30,
116
- ):
 
 
 
 
 
 
 
 
 
 
117
  # Initialize detector
118
  detector = ScalingSquareDetector(feature_detector=feature_detector, debug=debug)
119
 
@@ -131,54 +124,176 @@ def calculate_scaling_factor(
131
  return scaling_factor
132
 
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  # Example usage:
135
  if __name__ == "__main__":
136
  import os
137
  from PIL import Image
138
- from ultralytics import YOLO
139
- from app import yolo_detect, shrink_bbox
140
- from ultralytics.utils.plotting import save_one_box
141
-
142
- for idx, file in enumerate(os.listdir("./sample_images")):
143
- img = np.array(Image.open(os.path.join("./sample_images", file)))
144
- img = yolo_detect(img, ['box'])
145
- model = YOLO("./best.pt")
146
- res = model.predict(img, conf=0.6)
147
-
148
- box_img = save_one_box(res[0].cpu().boxes.xyxy, im=res[0].orig_img, save=False)
149
- # img = shrink_bbox(box_img, 1.20)
150
- cv2.imwrite(f"./outputs/{idx}_{file}", box_img)
151
-
152
- print("File: ",f"./outputs/{idx}_{file}")
153
- try:
154
-
155
- scaling_factor = calculate_scaling_factor(
156
- target_image=box_img,
157
- known_square_size_mm=20,
158
- feature_detector="ORB",
159
- debug=False,
160
- roi_margin=90,
161
- )
162
- # cv2.imwrite(f"./outputs/{idx}_binary_{file}", roi_binary)
163
-
164
- # Square size in mm
165
- # square_size_mm = 12.7
166
-
167
- # # Compute the calculated scaling factors and compare
168
- # calculated_scaling_factor = square_size_mm / height_px
169
- # discrepancy = abs(calculated_scaling_factor - scaling_factor)
170
- # import pprint
171
- # pprint.pprint({
172
- # "height_px": height_px,
173
- # "width_px": width_px,
174
- # "given_scaling_factor": scaling_factor,
175
- # "calculated_scaling_factor": calculated_scaling_factor,
176
- # "discrepancy": discrepancy,
177
- # })
178
-
179
-
180
- print(f"Scaling Factor (mm per pixel): {scaling_factor:.6f}")
181
- except Exception as e:
182
- from traceback import print_exc
183
- print(print_exc())
184
- print(f"Error: {e}")
 
 
 
 
 
 
2
  import numpy as np
3
  import os
4
  import argparse
5
+ from typing import Union, Tuple
6
  from matplotlib import pyplot as plt
7
 
8
  class ScalingSquareDetector:
 
33
  ):
34
  """
35
  Detect the scaling square in the target image based on the reference image.
36
+ :param target_image: Binary image containing the square.
 
37
  :param known_size_mm: Physical size of the square in millimeters.
38
  :param roi_margin: Margin to expand the ROI around the detected square (in pixels).
39
  :return: Scaling factor (mm per pixel).
 
43
  )
44
 
45
  if not contours:
46
+ raise ValueError("No contours found in the target image.")
47
 
48
+ # Select the largest contour (assuming it's the reference object)
49
  print(f"No of contours: {len(contours)}")
50
+ largest_contour = max(contours, key=cv2.contourArea)
51
+
52
+ # Draw the largest contour on the original image for debugging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  target_image_color = cv2.cvtColor(target_image, cv2.COLOR_GRAY2BGR)
54
  cv2.drawContours(
55
+ target_image_color, [largest_contour], -1, (255, 0, 0), 3
56
  )
57
 
58
+ if self.debug:
59
+ cv2.imwrite("largest_contour.jpg", target_image_color)
60
 
61
  # Calculate the bounding rectangle of the largest contour
62
+ x, y, w, h = cv2.boundingRect(largest_contour)
63
  square_width_px = w
64
  square_height_px = h
65
+
66
+ print(f"Reference object size: {known_size_mm} mm")
67
+ print(f"Detected width: {square_width_px} px")
68
+ print(f"Detected height: {square_height_px} px")
69
 
70
+ # Calculate the scaling factor using average of width and height
71
  avg_square_size_px = (square_width_px + square_height_px) / 2
72
+ print(f"Average square size: {avg_square_size_px} px")
73
+
74
  scaling_factor = known_size_mm / avg_square_size_px # mm per pixel
75
+ print(f"Calculated scaling factor: {scaling_factor:.6f} mm per pixel")
76
 
77
+ return scaling_factor
78
 
79
  def draw_debug_images(self, output_folder):
80
  """
 
96
  feature_detector="ORB",
97
  debug=False,
98
  roi_margin=30,
99
+ ) -> float:
100
+ """
101
+ Calculate scaling factor from reference object in image.
102
+
103
+ :param target_image: Input image (numpy array)
104
+ :param reference_obj_size_mm: Known size of reference object in millimeters
105
+ :param feature_detector: Feature detector to use ("ORB" or "SIFT")
106
+ :param debug: Enable debug output
107
+ :param roi_margin: ROI margin in pixels
108
+ :return: Scaling factor in mm per pixel
109
+ """
110
  # Initialize detector
111
  detector = ScalingSquareDetector(feature_detector=feature_detector, debug=debug)
112
 
 
124
  return scaling_factor
125
 
126
 
127
+ def convert_units(value: float, from_unit: str, to_unit: str) -> float:
128
+ """
129
+ Convert between mm and inches.
130
+
131
+ :param value: Value to convert
132
+ :param from_unit: Source unit ("mm" or "inches")
133
+ :param to_unit: Target unit ("mm" or "inches")
134
+ :return: Converted value
135
+ """
136
+ if from_unit == to_unit:
137
+ return value
138
+
139
+ if from_unit == "inches" and to_unit == "mm":
140
+ return value * 25.4
141
+ elif from_unit == "mm" and to_unit == "inches":
142
+ return value / 25.4
143
+ else:
144
+ raise ValueError(f"Unsupported unit conversion: {from_unit} to {to_unit}")
145
+
146
+
147
+ def calculate_scaling_factor_with_units(
148
+ target_image,
149
+ reference_obj_size: float,
150
+ reference_unit: str = "mm",
151
+ output_unit: str = "mm",
152
+ feature_detector="ORB",
153
+ debug=False,
154
+ roi_margin=30,
155
+ ) -> Tuple[float, str]:
156
+ """
157
+ Calculate scaling factor with proper unit handling.
158
+
159
+ :param target_image: Input image (numpy array)
160
+ :param reference_obj_size: Known size of reference object
161
+ :param reference_unit: Unit of reference object size ("mm" or "inches")
162
+ :param output_unit: Desired unit for scaling factor ("mm" or "inches")
163
+ :param feature_detector: Feature detector to use ("ORB" or "SIFT")
164
+ :param debug: Enable debug output
165
+ :param roi_margin: ROI margin in pixels
166
+ :return: Tuple of (scaling_factor, unit_string)
167
+ """
168
+ # Convert reference size to mm for internal calculation
169
+ reference_size_mm = convert_units(reference_obj_size, reference_unit, "mm")
170
+
171
+ # Calculate scaling factor in mm/px
172
+ scaling_factor_mm = calculate_scaling_factor(
173
+ target_image=target_image,
174
+ reference_obj_size_mm=reference_size_mm,
175
+ feature_detector=feature_detector,
176
+ debug=debug,
177
+ roi_margin=roi_margin,
178
+ )
179
+
180
+ # Convert scaling factor to desired output unit
181
+ if output_unit == "inches":
182
+ scaling_factor = scaling_factor_mm / 25.4 # Convert mm/px to inches/px
183
+ unit_string = "inches per pixel"
184
+ else:
185
+ scaling_factor = scaling_factor_mm
186
+ unit_string = "mm per pixel"
187
+
188
+ print(f"Final scaling factor: {scaling_factor:.6f} {unit_string}")
189
+
190
+ return scaling_factor, unit_string
191
+
192
+
193
+ # Paper size configurations (in mm and inches)
194
+ PAPER_SIZES = {
195
+ "A4": {"width_mm": 210, "height_mm": 297, "width_inches": 8.27, "height_inches": 11.69},
196
+ "A3": {"width_mm": 297, "height_mm": 420, "width_inches": 11.69, "height_inches": 16.54},
197
+ "US Letter": {"width_mm": 215.9, "height_mm": 279.4, "width_inches": 8.5, "height_inches": 11.0}
198
+ }
199
+
200
+
201
+ def calculate_paper_scaling_factor(
202
+ paper_contour: np.ndarray,
203
+ paper_size: str,
204
+ output_unit: str = "mm"
205
+ ) -> Tuple[float, str]:
206
+ """
207
+ Calculate scaling factor based on detected paper dimensions with proper unit handling.
208
+
209
+ :param paper_contour: Detected paper contour
210
+ :param paper_size: Paper size identifier ("A4", "A3", "US Letter")
211
+ :param output_unit: Desired unit for scaling factor ("mm" or "inches")
212
+ :return: Tuple of (scaling_factor, unit_string)
213
+ """
214
+ # Get paper dimensions in the desired unit
215
+ if output_unit == "inches":
216
+ expected_width = PAPER_SIZES[paper_size]["width_inches"]
217
+ expected_height = PAPER_SIZES[paper_size]["height_inches"]
218
+ unit_string = "inches per pixel"
219
+ else:
220
+ expected_width = PAPER_SIZES[paper_size]["width_mm"]
221
+ expected_height = PAPER_SIZES[paper_size]["height_mm"]
222
+ unit_string = "mm per pixel"
223
+
224
+ # Calculate bounding rectangle of paper contour
225
+ rect = cv2.boundingRect(paper_contour)
226
+ detected_width_px = rect[2]
227
+ detected_height_px = rect[3]
228
+
229
+ # Calculate scaling factors for both dimensions
230
+ scale_x = expected_width / detected_width_px
231
+ scale_y = expected_height / detected_height_px
232
+
233
+ # Use the minimum scale to ensure the object fits within expected dimensions
234
+ scaling_factor = min(scale_x, scale_y)
235
+
236
+ print(f"Paper detection: {detected_width_px}x{detected_height_px} px")
237
+ print(f"Expected paper size: {expected_width}x{expected_height} {output_unit}")
238
+ print(f"Scale X: {scale_x:.6f}, Scale Y: {scale_y:.6f}")
239
+ print(f"Final scaling factor: {scaling_factor:.6f} {unit_string}")
240
+
241
+ return scaling_factor, unit_string
242
+
243
+
244
  # Example usage:
245
  if __name__ == "__main__":
246
  import os
247
  from PIL import Image
248
+
249
+ # Test with different units
250
+ sample_dir = "./sample_images"
251
+ if os.path.exists(sample_dir):
252
+ for idx, file in enumerate(os.listdir(sample_dir)):
253
+ if file.lower().endswith(('.jpg', '.jpeg', '.png')):
254
+ img_path = os.path.join(sample_dir, file)
255
+ img = np.array(Image.open(img_path))
256
+
257
+ # Convert to grayscale if needed
258
+ if len(img.shape) == 3:
259
+ img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
260
+ else:
261
+ img_gray = img
262
+
263
+ print(f"\nProcessing: {file}")
264
+
265
+ try:
266
+ # Test with mm units
267
+ scaling_factor_mm, unit_mm = calculate_scaling_factor_with_units(
268
+ target_image=img_gray,
269
+ reference_obj_size=20.0, # 20mm reference object
270
+ reference_unit="mm",
271
+ output_unit="mm",
272
+ feature_detector="ORB",
273
+ debug=False,
274
+ roi_margin=90,
275
+ )
276
+
277
+ # Test with inch units
278
+ scaling_factor_inch, unit_inch = calculate_scaling_factor_with_units(
279
+ target_image=img_gray,
280
+ reference_obj_size=0.787, # ~20mm in inches
281
+ reference_unit="inches",
282
+ output_unit="inches",
283
+ feature_detector="ORB",
284
+ debug=False,
285
+ roi_margin=90,
286
+ )
287
+
288
+ print(f"MM scaling: {scaling_factor_mm:.6f} {unit_mm}")
289
+ print(f"Inch scaling: {scaling_factor_inch:.6f} {unit_inch}")
290
+
291
+ # Verify conversion consistency
292
+ converted_mm_to_inch = scaling_factor_mm / 25.4
293
+ print(f"Converted mm to inch: {converted_mm_to_inch:.6f}")
294
+ print(f"Difference: {abs(scaling_factor_inch - converted_mm_to_inch):.8f}")
295
+
296
+ except Exception as e:
297
+ print(f"Error processing {file}: {e}")
298
+ else:
299
+ print(f"Sample directory {sample_dir} not found")