Ayesha352 commited on
Commit
6ba6b88
·
verified ·
1 Parent(s): 2df0729

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -50
app.py CHANGED
@@ -3,7 +3,7 @@ import numpy as np
3
  import json
4
  import gradio as gr
5
  import os
6
- from lxml import etree
7
 
8
  # ---------------- Helper functions ----------------
9
  def get_rotated_rect_corners(x, y, w, h, rotation_deg):
@@ -36,48 +36,33 @@ def detect_and_match(img1_gray, img2_gray, method="SIFT", ratio_thresh=0.78):
36
  good = [m for m,n in raw_matches if m.distance < ratio_thresh*n.distance]
37
  return kp1, kp2, good
38
 
39
- # ---------------- XML overlay helper using lxml ----------------
40
- def extract_points_lxml(xml_path):
41
- tree = etree.parse(xml_path)
42
  root = tree.getroot()
43
- transform = root.find('.//transform')
44
- points = {}
45
- for pt in transform.findall('.//point'):
46
- pt_type = pt.attrib['type']
47
- x = float(pt.attrib['x'])
48
- y = float(pt.attrib['y'])
49
- points[pt_type] = (x,y)
50
- return points
51
-
52
- def draw_polygon_on_image(img, points_dict):
53
- ordered_points = ['TopLeft','TopRight','BottomRight','BottomLeft']
54
- polygon = [points_dict[pt] for pt in ordered_points]
55
- pts = np.array(polygon, np.int32).reshape((-1,1,2))
56
- img_copy = img.copy()
57
- cv2.polylines(img_copy, [pts], isClosed=True, color=(0,0,255), thickness=3)
58
- for px, py in polygon:
59
- cv2.circle(img_copy, (int(px),int(py)), 5, (255,0,0), -1)
60
- return img_copy
61
 
62
  # ---------------- Padding Helper ----------------
63
  def pad_to_size(img, target_h, target_w):
64
  h, w = img.shape[:2]
 
 
 
 
65
  canvas = np.ones((target_h, target_w,3), dtype=np.uint8)*255
66
- canvas[:h,:w] = img
67
  return canvas
68
 
69
- def match_img_to_reference(match_img, ref_h, ref_w):
70
- h, w = match_img.shape[:2]
71
- scale = ref_w / w
72
- new_w = ref_w
73
- new_h = int(h * scale)
74
- resized = cv2.resize(match_img, (new_w,new_h))
75
- if new_h < ref_h:
76
- canvas = np.ones((ref_h, ref_w,3), dtype=np.uint8)*255
77
- canvas[:new_h,:new_w] = resized
78
- return canvas
79
- else:
80
- return resized
81
 
82
  # ---------------- Main Function ----------------
83
  def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
@@ -91,7 +76,7 @@ def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
91
 
92
  flat_gray = preprocess_gray_clahe(flat_img)
93
  persp_gray = preprocess_gray_clahe(persp_img)
94
- xml_points_dict = extract_points_lxml(xml_file.name)
95
 
96
  methods = ["SIFT","ORB","BRISK","KAZE","AKAZE"]
97
  gallery_paths = []
@@ -103,42 +88,44 @@ def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
103
 
104
  match_img = cv2.drawMatches(flat_img,kp1,persp_img,kp2,good_matches,None,flags=2)
105
 
106
- # ROI on perspective image
107
- roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
108
  src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
109
  dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
110
  H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
 
 
 
 
 
111
  persp_roi = persp_img.copy()
112
- if H is not None:
113
- roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
114
- cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
115
- for px,py in roi_corners_persp: cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
116
 
117
- # XML GT overlay on perspective
118
- xml_gt_img = draw_polygon_on_image(persp_img, xml_points_dict)
 
119
 
120
  # Convert to RGB
121
  flat_rgb = cv2.cvtColor(flat_img,cv2.COLOR_BGR2RGB)
122
- match_rgb = match_img_to_reference(cv2.cvtColor(match_img,cv2.COLOR_BGR2RGB),
123
- flat_rgb.shape[0], flat_rgb.shape[1])
124
  roi_rgb = cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB)
125
  xml_rgb = cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB)
126
 
127
- # Determine max height and width
128
  max_h = max(flat_rgb.shape[0], match_rgb.shape[0], roi_rgb.shape[0], xml_rgb.shape[0])
129
  max_w = max(flat_rgb.shape[1], match_rgb.shape[1], roi_rgb.shape[1], xml_rgb.shape[1])
130
 
131
- # Pad images
132
  flat_pad = pad_to_size(flat_rgb, max_h, max_w)
133
  match_pad = pad_to_size(match_rgb, max_h, max_w)
134
  roi_pad = pad_to_size(roi_rgb, max_h, max_w)
135
  xml_pad = pad_to_size(xml_rgb, max_h, max_w)
136
 
137
- # 2x2 grid
138
  top = np.hstack([flat_pad, match_pad])
139
  bottom = np.hstack([roi_pad, xml_pad])
140
  combined_grid = np.vstack([top, bottom])
141
 
 
142
  base_name = os.path.splitext(os.path.basename(persp_file))[0]
143
  file_name = f"{base_name}_{method.lower()}.png"
144
  cv2.imwrite(file_name, cv2.cvtColor(combined_grid,cv2.COLOR_RGB2BGR))
@@ -166,7 +153,7 @@ iface = gr.Interface(
166
  gr.File(label="Download AKAZE Result")
167
  ],
168
  title="Homography ROI Projection with Feature Matching & XML GT",
169
- description="Flat + Perspective images with mockup.json & XML. Grid aligned. Perspective GT overlay now uses XML lxml parsing."
170
  )
171
 
172
  iface.launch()
 
3
  import json
4
  import gradio as gr
5
  import os
6
+ import xml.etree.ElementTree as ET
7
 
8
  # ---------------- Helper functions ----------------
9
  def get_rotated_rect_corners(x, y, w, h, rotation_deg):
 
36
  good = [m for m,n in raw_matches if m.distance < ratio_thresh*n.distance]
37
  return kp1, kp2, good
38
 
39
+ def parse_xml_points(xml_file):
40
+ tree = ET.parse(xml_file)
 
41
  root = tree.getroot()
42
+ points=[]
43
+ for pt_type in ["TopLeft","TopRight","BottomLeft","BottomRight"]:
44
+ elem=root.find(f".//point[@type='{pt_type}']")
45
+ points.append([float(elem.get("x")), float(elem.get("y"))])
46
+ return np.array(points,dtype=np.float32).reshape(-1,2)
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  # ---------------- Padding Helper ----------------
49
  def pad_to_size(img, target_h, target_w):
50
  h, w = img.shape[:2]
51
+ top_pad = 0
52
+ left_pad = 0
53
+ bottom_pad = target_h - h
54
+ right_pad = target_w - w
55
  canvas = np.ones((target_h, target_w,3), dtype=np.uint8)*255
56
+ canvas[top_pad:top_pad+h, left_pad:left_pad+w] = img
57
  return canvas
58
 
59
+ # ---------------- Draw XML Ground-Truth ----------------
60
+ def draw_xml_gt(img, xml_points):
61
+ for px,py in xml_points:
62
+ cv2.circle(img,(int(px),int(py)),5,(0,0,255),-1)
63
+ # Draw polygon
64
+ cv2.polylines(img,[xml_points.astype(np.int32)],True,(255,0,0),2)
65
+ return img
 
 
 
 
 
66
 
67
  # ---------------- Main Function ----------------
68
  def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
 
76
 
77
  flat_gray = preprocess_gray_clahe(flat_img)
78
  persp_gray = preprocess_gray_clahe(persp_img)
79
+ xml_points = parse_xml_points(xml_file.name)
80
 
81
  methods = ["SIFT","ORB","BRISK","KAZE","AKAZE"]
82
  gallery_paths = []
 
88
 
89
  match_img = cv2.drawMatches(flat_img,kp1,persp_img,kp2,good_matches,None,flags=2)
90
 
 
 
91
  src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
92
  dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
93
  H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
94
+ if H is None: continue
95
+
96
+ # ROI homography projection
97
+ roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
98
+ roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
99
  persp_roi = persp_img.copy()
100
+ cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
101
+ for px,py in roi_corners_persp: cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
 
 
102
 
103
+ # XML GT overlay
104
+ xml_gt_img = persp_img.copy()
105
+ xml_gt_img = draw_xml_gt(xml_gt_img, xml_points)
106
 
107
  # Convert to RGB
108
  flat_rgb = cv2.cvtColor(flat_img,cv2.COLOR_BGR2RGB)
109
+ match_rgb = cv2.cvtColor(match_img,cv2.COLOR_BGR2RGB)
 
110
  roi_rgb = cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB)
111
  xml_rgb = cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB)
112
 
113
+ # Determine max height and width for padding
114
  max_h = max(flat_rgb.shape[0], match_rgb.shape[0], roi_rgb.shape[0], xml_rgb.shape[0])
115
  max_w = max(flat_rgb.shape[1], match_rgb.shape[1], roi_rgb.shape[1], xml_rgb.shape[1])
116
 
117
+ # Pad all images to same size
118
  flat_pad = pad_to_size(flat_rgb, max_h, max_w)
119
  match_pad = pad_to_size(match_rgb, max_h, max_w)
120
  roi_pad = pad_to_size(roi_rgb, max_h, max_w)
121
  xml_pad = pad_to_size(xml_rgb, max_h, max_w)
122
 
123
+ # Merge 2x2 grid
124
  top = np.hstack([flat_pad, match_pad])
125
  bottom = np.hstack([roi_pad, xml_pad])
126
  combined_grid = np.vstack([top, bottom])
127
 
128
+ # Save combined grid
129
  base_name = os.path.splitext(os.path.basename(persp_file))[0]
130
  file_name = f"{base_name}_{method.lower()}.png"
131
  cv2.imwrite(file_name, cv2.cvtColor(combined_grid,cv2.COLOR_RGB2BGR))
 
153
  gr.File(label="Download AKAZE Result")
154
  ],
155
  title="Homography ROI Projection with Feature Matching & XML GT",
156
+ description="Flat + Perspective images with mockup.json & XML. Original resolution maintained. Grid aligned with white padding. XML GT overlaid."
157
  )
158
 
159
  iface.launch()