Ayesha352 commited on
Commit
14ffea8
·
verified ·
1 Parent(s): 19d0a08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -61
app.py CHANGED
@@ -21,17 +21,23 @@ def preprocess_gray_clahe(img):
21
  return clahe.apply(gray)
22
 
23
  def detect_and_match(img1_gray, img2_gray, method="SIFT", ratio_thresh=0.78):
24
- if method=="SIFT": detector=cv2.SIFT_create(nfeatures=5000); matcher=cv2.BFMatcher(cv2.NORM_L2)
25
- elif method=="ORB": detector=cv2.ORB_create(5000); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
26
- elif method=="BRISK": detector=cv2.BRISK_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
27
- elif method=="KAZE": detector=cv2.KAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_L2)
28
- elif method=="AKAZE": detector=cv2.AKAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
29
- else: return None,None,[]
30
-
 
 
 
 
 
 
31
  kp1, des1 = detector.detectAndCompute(img1_gray,None)
32
  kp2, des2 = detector.detectAndCompute(img2_gray,None)
33
- if des1 is None or des2 is None: return None,None,[]
34
-
35
  raw_matches = matcher.knnMatch(des1,des2,k=2)
36
  good = [m for m,n in raw_matches if m.distance < ratio_thresh*n.distance]
37
  return kp1, kp2, good
@@ -51,16 +57,14 @@ def parse_xml_points(xml_file):
51
  # ---------------- Fit-to-Box Helper ----------------
52
  def fit_to_box(img, target_h=600, target_w=600):
53
  h, w = img.shape[:2]
54
- scale = min(target_w/w, target_h/h) # preserve aspect ratio
55
  new_w, new_h = int(w*scale), int(h*scale)
56
  resized = cv2.resize(img, (new_w, new_h))
57
-
58
  # symmetric padding
59
  top = (target_h - new_h) // 2
60
  bottom = target_h - new_h - top
61
  left = (target_w - new_w) // 2
62
  right = target_w - new_w - left
63
-
64
  canvas = np.ones((target_h, target_w, 3), dtype=np.uint8) * 255
65
  canvas[top:top+new_h, left:left+new_w] = resized
66
  return canvas
@@ -71,14 +75,14 @@ def add_heading(img, text):
71
  band_h = 40
72
  canvas = np.ones((h+band_h, w, 3), dtype=np.uint8) * 255
73
  canvas[band_h:] = img
74
- cv2.putText(canvas, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
75
- 1, (0,0,0), 2, cv2.LINE_AA)
76
  return canvas
77
 
78
  # ---------------- Main Function ----------------
79
- def homography_show_three(flat_file, persp_file, json_file, xml_file):
80
  flat_img = cv2.imread(flat_file)
81
  persp_img = cv2.imread(persp_file)
 
82
  mockup = json.load(open(json_file.name))
83
  roi_data = mockup["printAreas"][0]["position"]
84
  roi_x, roi_y = roi_data["x"], roi_data["y"]
@@ -87,53 +91,67 @@ def homography_show_three(flat_file, persp_file, json_file, xml_file):
87
 
88
  flat_gray = preprocess_gray_clahe(flat_img)
89
  persp_gray = preprocess_gray_clahe(persp_img)
90
- xml_points = parse_xml_points(xml_file.name)
91
-
92
- # --- SIFT (only to get Homography) ---
93
- kp1,kp2,good_matches = detect_and_match(flat_gray,persp_gray,"SIFT")
94
- if kp1 is None or kp2 is None or len(good_matches)<4:
95
- return ["Not enough matches found"], None, None, None
96
-
97
- src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
98
- dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
99
- H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
100
 
101
- # --- 1. Flat image with ROI from JSON ---
102
- flat_with_roi = flat_img.copy()
103
- roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
104
- cv2.polylines(flat_with_roi,[roi_corners_flat.astype(int)],True,(0,255,0),2)
105
- for px,py in roi_corners_flat: cv2.circle(flat_with_roi,(int(px),int(py)),5,(255,0,0),-1)
106
-
107
- # --- 2. Perspective image with Homography ROI ---
108
- roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
109
- persp_roi = persp_img.copy()
110
- cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
111
- for px,py in roi_corners_persp: cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
112
-
113
- # --- 3. Perspective image with Ground Truth ROI from XML ---
114
- xml_gt_img = persp_img.copy()
115
- ordered_pts = ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft']
116
- xml_polygon = [xml_points[pt] for pt in ordered_pts]
117
- pts = np.array(xml_polygon, np.int32).reshape((-1,1,2))
118
- cv2.polylines(xml_gt_img,[pts],isClosed=True,color=(255,0,0),thickness=3)
119
-
120
- # Resize + Headings
121
- flat_rgb = add_heading(fit_to_box(cv2.cvtColor(flat_with_roi,cv2.COLOR_BGR2RGB),600,600), "Flat Image with JSON ROI")
122
- roi_rgb = add_heading(fit_to_box(cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB),600,600), "Perspective Img with ROI(Homography)")
123
- xml_rgb = add_heading(fit_to_box(cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB),600,600), "Perspective Img with GT ROI")
124
-
125
- # Side-by-side 1 row
126
- combined = np.hstack([flat_rgb, roi_rgb, xml_rgb])
127
-
128
- base_name = os.path.splitext(os.path.basename(persp_file))[0]
129
- file_name = f"{base_name}_result.png"
130
- cv2.imwrite(file_name, cv2.cvtColor(combined,cv2.COLOR_RGB2BGR))
131
 
132
- return [file_name], file_name, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  # ---------------- Gradio UI ----------------
135
  iface = gr.Interface(
136
- fn=homography_show_three,
137
  inputs=[
138
  gr.Image(label="Upload Flat Image",type="filepath"),
139
  gr.Image(label="Upload Perspective Image",type="filepath"),
@@ -141,11 +159,15 @@ iface = gr.Interface(
141
  gr.File(label="Upload XML file",file_types=[".xml"])
142
  ],
143
  outputs=[
144
- gr.Gallery(label="Final Result",show_label=True),
145
- gr.File(label="Download Result")
 
 
 
 
146
  ],
147
- title="Homography ROI vs GT ROI",
148
- description="Shows Flat image with JSON ROI, Perspective with Homography ROI, and Perspective with GT ROI in one row."
149
  )
150
 
151
  iface.launch()
 
21
  return clahe.apply(gray)
22
 
23
  def detect_and_match(img1_gray, img2_gray, method="SIFT", ratio_thresh=0.78):
24
+ if method=="SIFT":
25
+ detector=cv2.SIFT_create(nfeatures=5000); matcher=cv2.BFMatcher(cv2.NORM_L2)
26
+ elif method=="ORB":
27
+ detector=cv2.ORB_create(5000); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
28
+ elif method=="BRISK":
29
+ detector=cv2.BRISK_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
30
+ elif method=="KAZE":
31
+ detector=cv2.KAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_L2)
32
+ elif method=="AKAZE":
33
+ detector=cv2.AKAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
34
+ else:
35
+ return None,None,[]
36
+
37
  kp1, des1 = detector.detectAndCompute(img1_gray,None)
38
  kp2, des2 = detector.detectAndCompute(img2_gray,None)
39
+ if des1 is None or des2 is None:
40
+ return None,None,[]
41
  raw_matches = matcher.knnMatch(des1,des2,k=2)
42
  good = [m for m,n in raw_matches if m.distance < ratio_thresh*n.distance]
43
  return kp1, kp2, good
 
57
  # ---------------- Fit-to-Box Helper ----------------
58
  def fit_to_box(img, target_h=600, target_w=600):
59
  h, w = img.shape[:2]
60
+ scale = min(target_w/w, target_h/h) # preserve aspect ratio
61
  new_w, new_h = int(w*scale), int(h*scale)
62
  resized = cv2.resize(img, (new_w, new_h))
 
63
  # symmetric padding
64
  top = (target_h - new_h) // 2
65
  bottom = target_h - new_h - top
66
  left = (target_w - new_w) // 2
67
  right = target_w - new_w - left
 
68
  canvas = np.ones((target_h, target_w, 3), dtype=np.uint8) * 255
69
  canvas[top:top+new_h, left:left+new_w] = resized
70
  return canvas
 
75
  band_h = 40
76
  canvas = np.ones((h+band_h, w, 3), dtype=np.uint8) * 255
77
  canvas[band_h:] = img
78
+ cv2.putText(canvas, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 2, cv2.LINE_AA)
 
79
  return canvas
80
 
81
  # ---------------- Main Function ----------------
82
+ def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
83
  flat_img = cv2.imread(flat_file)
84
  persp_img = cv2.imread(persp_file)
85
+
86
  mockup = json.load(open(json_file.name))
87
  roi_data = mockup["printAreas"][0]["position"]
88
  roi_x, roi_y = roi_data["x"], roi_data["y"]
 
91
 
92
  flat_gray = preprocess_gray_clahe(flat_img)
93
  persp_gray = preprocess_gray_clahe(persp_img)
 
 
 
 
 
 
 
 
 
 
94
 
95
+ xml_points = parse_xml_points(xml_file.name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ methods = ["SIFT","ORB","BRISK","KAZE","AKAZE"]
98
+ gallery_paths = []
99
+ download_files = []
100
+
101
+ for method in methods:
102
+ kp1,kp2,good_matches = detect_and_match(flat_gray,persp_gray,method)
103
+ if kp1 is None or kp2 is None or len(good_matches)<4:
104
+ continue
105
+
106
+ src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
107
+ dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
108
+ H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
109
+ if H is None:
110
+ continue
111
+
112
+ # 1. Flat image with ROI (from JSON)
113
+ flat_with_roi = flat_img.copy()
114
+ roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
115
+ cv2.polylines(flat_with_roi,[roi_corners_flat.astype(int)],True,(0,255,0),2)
116
+ for px,py in roi_corners_flat:
117
+ cv2.circle(flat_with_roi,(int(px),int(py)),5,(255,0,0),-1)
118
+
119
+ # 2. Perspective with Homography ROI
120
+ roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
121
+ persp_roi = persp_img.copy()
122
+ cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
123
+ for px,py in roi_corners_persp:
124
+ cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
125
+
126
+ # 3. Perspective with GT ROI (from XML)
127
+ xml_gt_img = persp_img.copy()
128
+ ordered_pts = ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft']
129
+ xml_polygon = [xml_points[pt] for pt in ordered_pts]
130
+ pts = np.array(xml_polygon, np.int32).reshape((-1,1,2))
131
+ cv2.polylines(xml_gt_img,[pts],isClosed=True,color=(255,0,0),thickness=3)
132
+
133
+ # Convert to RGB + resize + add headings
134
+ flat_rgb = add_heading(fit_to_box(cv2.cvtColor(flat_with_roi,cv2.COLOR_BGR2RGB),600,600), "Flat Image with ROI")
135
+ roi_rgb = add_heading(fit_to_box(cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB),600,600), "Perspective Image with Homography ROI")
136
+ xml_rgb = add_heading(fit_to_box(cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB),600,600), "Perspective GT ROI")
137
+
138
+ # Concatenate side by side
139
+ combined_row = np.hstack([flat_rgb, roi_rgb, xml_rgb])
140
+
141
+ base_name = os.path.splitext(os.path.basename(persp_file))[0]
142
+ file_name = f"{base_name}_{method.lower()}.png"
143
+ cv2.imwrite(file_name, cv2.cvtColor(combined_row,cv2.COLOR_RGB2BGR))
144
+ gallery_paths.append(file_name)
145
+ download_files.append(file_name)
146
+
147
+ while len(download_files)<5:
148
+ download_files.append(None)
149
+
150
+ return gallery_paths, download_files[0], download_files[1], download_files[2], download_files[3], download_files[4]
151
 
152
  # ---------------- Gradio UI ----------------
153
  iface = gr.Interface(
154
+ fn=homography_all_detectors,
155
  inputs=[
156
  gr.Image(label="Upload Flat Image",type="filepath"),
157
  gr.Image(label="Upload Perspective Image",type="filepath"),
 
159
  gr.File(label="Upload XML file",file_types=[".xml"])
160
  ],
161
  outputs=[
162
+ gr.Gallery(label="Results per Detector",show_label=True),
163
+ gr.File(label="Download SIFT Result"),
164
+ gr.File(label="Download ORB Result"),
165
+ gr.File(label="Download BRISK Result"),
166
+ gr.File(label="Download KAZE Result"),
167
+ gr.File(label="Download AKAZE Result")
168
  ],
169
+ title="Homography ROI + XML GT",
170
+ description="Flat with ROI + Perspective ROI (Homography + GT). Aspect ratio preserved, images centered in uniform boxes, headings added."
171
  )
172
 
173
  iface.launch()