Ayesha352 commited on
Commit
aada67b
·
verified ·
1 Parent(s): 87dd4d6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -63
app.py CHANGED
@@ -8,14 +8,12 @@ import xml.etree.ElementTree as ET
8
  # ---------------- Helper functions ----------------
9
  def get_rotated_rect_corners(x, y, w, h, rotation_deg):
10
  rot_rad = np.deg2rad(rotation_deg)
11
- cos_r = np.cos(rot_rad)
12
- sin_r = np.sin(rot_rad)
13
  R = np.array([[cos_r, -sin_r], [sin_r, cos_r]])
14
  cx, cy = x + w/2, y + h/2
15
- local_corners = np.array([[-w/2, -h/2],[w/2,-h/2],[w/2,h/2],[-w/2,h/2]])
16
  rotated_corners = np.dot(local_corners, R.T)
17
- corners = rotated_corners + np.array([cx, cy])
18
- return corners.astype(np.float32)
19
 
20
  def preprocess_gray_clahe(img):
21
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
@@ -23,25 +21,18 @@ def preprocess_gray_clahe(img):
23
  return clahe.apply(gray)
24
 
25
  def detect_and_match(img1_gray, img2_gray, method="SIFT", ratio_thresh=0.78):
26
- if method == "SIFT": sift=cv2.SIFT_create(nfeatures=5000); matcher=cv2.BFMatcher(cv2.NORM_L2)
27
- elif method=="ORB": orb=cv2.ORB_create(5000); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
28
- elif method=="BRISK": brisk=cv2.BRISK_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
29
- elif method=="KAZE": kaze=cv2.KAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_L2)
30
- elif method=="AKAZE": akaze=cv2.AKAZE_create(); matcher=cv2.BFMatcher(cv2.NORM_HAMMING)
31
  else: return None,None,[]
32
-
33
- kp1, des1 = None, None
34
- kp2, des2 = None, None
35
-
36
- if method=="SIFT": kp1, des1 = sift.detectAndCompute(img1_gray,None); kp2, des2 = sift.detectAndCompute(img2_gray,None)
37
- elif method=="ORB": kp1, des1 = orb.detectAndCompute(img1_gray,None); kp2, des2 = orb.detectAndCompute(img2_gray,None)
38
- elif method=="BRISK": kp1, des1 = brisk.detectAndCompute(img1_gray,None); kp2, des2 = brisk.detectAndCompute(img2_gray,None)
39
- elif method=="KAZE": kp1, des1 = kaze.detectAndCompute(img1_gray,None); kp2, des2 = kaze.detectAndCompute(img2_gray,None)
40
- elif method=="AKAZE": kp1, des1 = akaze.detectAndCompute(img1_gray,None); kp2, des2 = akaze.detectAndCompute(img2_gray,None)
41
-
42
  if des1 is None or des2 is None: return None,None,[]
43
-
44
- raw_matches = matcher.knnMatch(des1, des2, k=2)
45
  good = [m for m,n in raw_matches if m.distance < ratio_thresh*n.distance]
46
  return kp1, kp2, good
47
 
@@ -51,78 +42,80 @@ def parse_xml_points(xml_file):
51
  points=[]
52
  for pt_type in ["TopLeft","TopRight","BottomLeft","BottomRight"]:
53
  elem=root.find(f".//point[@type='{pt_type}']")
54
- x=float(elem.get("x")); y=float(elem.get("y"))
55
- points.extend([x,y])
56
  return np.array(points,dtype=np.float32).reshape(-1,2)
57
 
58
- # ---------------- Main Homography Function ----------------
59
  def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
60
- flat_img=cv2.imread(flat_file)
61
- persp_img=cv2.imread(persp_file)
62
- mockup=json.load(open(json_file.name))
63
- roi_data=mockup["printAreas"][0]["position"]
64
- roi_x, roi_y=roi_data["x"], roi_data["y"]
65
- roi_w=mockup["printAreas"][0]["width"]
66
- roi_h=mockup["printAreas"][0]["height"]
67
- roi_rot_deg=mockup["printAreas"][0]["rotation"]
68
-
69
- flat_gray=preprocess_gray_clahe(flat_img)
70
- persp_gray=preprocess_gray_clahe(persp_img)
71
- methods=["SIFT","ORB","BRISK","KAZE","AKAZE"]
72
-
73
- gallery_images=[]
74
- download_files=[]
75
-
76
- xml_points=parse_xml_points(xml_file.name)
77
 
78
  for method in methods:
79
- kp1,kp2,good_matches=detect_and_match(flat_gray,persp_gray,method=method)
80
  if kp1 is None or kp2 is None or len(good_matches)<4: continue
81
 
82
- # Feature matching lines
83
  match_img = cv2.drawMatches(flat_img,kp1,persp_img,kp2,good_matches,None,flags=2)
84
 
85
- src_pts=np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
86
- dst_pts=np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
 
87
  H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
88
  if H is None: continue
89
 
90
- # ROI mapping
91
  roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
92
  roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
93
  persp_roi = persp_img.copy()
94
  cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
95
  for px,py in roi_corners_persp: cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
96
 
97
- # XML ground truth mapping
98
  xml_gt_img = persp_img.copy()
99
  xml_mapped = cv2.perspectiveTransform(xml_points.reshape(-1,1,2),H).reshape(-1,2)
100
  for px,py in xml_mapped: cv2.circle(xml_gt_img,(int(px),int(py)),5,(0,0,255),-1)
101
 
102
- # Convert all to RGB
103
- flat_rgb=cv2.cvtColor(flat_img,cv2.COLOR_BGR2RGB)
104
- persp_roi_rgb=cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB)
105
- match_rgb=cv2.cvtColor(match_img,cv2.COLOR_BGR2RGB)
106
- xml_rgb=cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB)
 
 
 
 
 
 
 
 
 
 
107
 
108
- # Combine all 4 in one gallery list per detector
109
- combined = np.hstack([cv2.resize(flat_rgb,(256,256)),
110
- cv2.resize(match_rgb,(256,256)),
111
- cv2.resize(persp_roi_rgb,(256,256)),
112
- cv2.resize(xml_rgb,(256,256))])
113
- gallery_images.append((combined,f"{method} Detector"))
114
 
115
  # Save for download
116
- base_name=os.path.splitext(os.path.basename(persp_file))[0]
117
- file_name=f"{base_name}_{method.lower()}.png"
118
- cv2.imwrite(file_name,combined[:,:,::-1]) # RGB->BGR
119
  download_files.append(file_name)
120
 
121
  while len(download_files)<5: download_files.append(None)
122
  return [gallery_images]+download_files[:5]
123
 
124
  # ---------------- Gradio UI ----------------
125
- iface=gr.Interface(
126
  fn=homography_all_detectors,
127
  inputs=[
128
  gr.Image(label="Upload Flat Image",type="filepath"),
 
8
  # ---------------- Helper functions ----------------
9
  def get_rotated_rect_corners(x, y, w, h, rotation_deg):
10
  rot_rad = np.deg2rad(rotation_deg)
11
+ cos_r, sin_r = np.cos(rot_rad), np.sin(rot_rad)
 
12
  R = np.array([[cos_r, -sin_r], [sin_r, cos_r]])
13
  cx, cy = x + w/2, y + h/2
14
+ local_corners = np.array([[-w/2,-h/2],[w/2,-h/2],[w/2,h/2],[-w/2,h/2]])
15
  rotated_corners = np.dot(local_corners, R.T)
16
+ return (rotated_corners + np.array([cx,cy])).astype(np.float32)
 
17
 
18
  def preprocess_gray_clahe(img):
19
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
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
38
 
 
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
+ # ---------------- Main Function ----------------
49
  def homography_all_detectors(flat_file, persp_file, json_file, xml_file):
50
+ flat_img = cv2.imread(flat_file)
51
+ persp_img = cv2.imread(persp_file)
52
+ mockup = json.load(open(json_file.name))
53
+ roi_data = mockup["printAreas"][0]["position"]
54
+ roi_x, roi_y = roi_data["x"], roi_data["y"]
55
+ roi_w, roi_h = mockup["printAreas"][0]["width"], mockup["printAreas"][0]["height"]
56
+ roi_rot_deg = mockup["printAreas"][0]["rotation"]
57
+
58
+ flat_gray = preprocess_gray_clahe(flat_img)
59
+ persp_gray = preprocess_gray_clahe(persp_img)
60
+ xml_points = parse_xml_points(xml_file.name)
61
+
62
+ methods = ["SIFT","ORB","BRISK","KAZE","AKAZE"]
63
+ gallery_images = []
64
+ download_files = []
 
 
65
 
66
  for method in methods:
67
+ kp1,kp2,good_matches = detect_and_match(flat_gray,persp_gray,method)
68
  if kp1 is None or kp2 is None or len(good_matches)<4: continue
69
 
70
+ # Feature matching
71
  match_img = cv2.drawMatches(flat_img,kp1,persp_img,kp2,good_matches,None,flags=2)
72
 
73
+ # Homography & ROI mapping
74
+ src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
75
+ dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
76
  H,_ = cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
77
  if H is None: continue
78
 
 
79
  roi_corners_flat = get_rotated_rect_corners(roi_x,roi_y,roi_w,roi_h,roi_rot_deg)
80
  roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2),H).reshape(-1,2)
81
  persp_roi = persp_img.copy()
82
  cv2.polylines(persp_roi,[roi_corners_persp.astype(int)],True,(0,255,0),2)
83
  for px,py in roi_corners_persp: cv2.circle(persp_roi,(int(px),int(py)),5,(255,0,0),-1)
84
 
85
+ # XML Ground truth on perspective
86
  xml_gt_img = persp_img.copy()
87
  xml_mapped = cv2.perspectiveTransform(xml_points.reshape(-1,1,2),H).reshape(-1,2)
88
  for px,py in xml_mapped: cv2.circle(xml_gt_img,(int(px),int(py)),5,(0,0,255),-1)
89
 
90
+ # Convert to RGB & resize
91
+ size=(256,256)
92
+ flat_rgb = cv2.cvtColor(flat_img,cv2.COLOR_BGR2RGB)
93
+ flat_rgb = cv2.resize(flat_rgb,size)
94
+ match_rgb = cv2.cvtColor(match_img,cv2.COLOR_BGR2RGB)
95
+ match_rgb = cv2.resize(match_rgb,size)
96
+ roi_rgb = cv2.cvtColor(persp_roi,cv2.COLOR_BGR2RGB)
97
+ roi_rgb = cv2.resize(roi_rgb,size)
98
+ xml_rgb = cv2.cvtColor(xml_gt_img,cv2.COLOR_BGR2RGB)
99
+ xml_rgb = cv2.resize(xml_rgb,size)
100
+
101
+ # Merge 2x2 grid
102
+ top = np.hstack([flat_rgb, match_rgb])
103
+ bottom = np.hstack([roi_rgb, xml_rgb])
104
+ combined_grid = np.vstack([top,bottom])
105
 
106
+ gallery_images.append((combined_grid,f"{method} Detector"))
 
 
 
 
 
107
 
108
  # Save for download
109
+ base_name = os.path.splitext(os.path.basename(persp_file))[0]
110
+ file_name = f"{base_name}_{method.lower()}.png"
111
+ cv2.imwrite(file_name, cv2.cvtColor(combined_grid,cv2.COLOR_RGB2BGR))
112
  download_files.append(file_name)
113
 
114
  while len(download_files)<5: download_files.append(None)
115
  return [gallery_images]+download_files[:5]
116
 
117
  # ---------------- Gradio UI ----------------
118
+ iface = gr.Interface(
119
  fn=homography_all_detectors,
120
  inputs=[
121
  gr.Image(label="Upload Flat Image",type="filepath"),