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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -107
app.py CHANGED
@@ -3,152 +3,143 @@ import numpy as np
3
  import json
4
  import gradio as gr
5
  import os
 
6
 
7
  # ---------------- Helper functions ----------------
8
  def get_rotated_rect_corners(x, y, w, h, rotation_deg):
9
  rot_rad = np.deg2rad(rotation_deg)
10
  cos_r = np.cos(rot_rad)
11
  sin_r = np.sin(rot_rad)
12
-
13
- R = np.array([[cos_r, -sin_r],
14
- [sin_r, cos_r]])
15
-
16
- cx = x + w/2
17
- cy = y + h/2
18
-
19
- local_corners = np.array([
20
- [-w/2, -h/2],
21
- [ w/2, -h/2],
22
- [ w/2, h/2],
23
- [-w/2, h/2]
24
- ])
25
-
26
  rotated_corners = np.dot(local_corners, R.T)
27
  corners = rotated_corners + np.array([cx, cy])
28
  return corners.astype(np.float32)
29
 
30
  def preprocess_gray_clahe(img):
31
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
32
- clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
33
  return clahe.apply(gray)
34
 
35
  def detect_and_match(img1_gray, img2_gray, method="SIFT", ratio_thresh=0.78):
36
- if method == "SIFT":
37
- sift = cv2.SIFT_create(nfeatures=5000)
38
- kp1, des1 = sift.detectAndCompute(img1_gray, None)
39
- kp2, des2 = sift.detectAndCompute(img2_gray, None)
40
- matcher = cv2.BFMatcher(cv2.NORM_L2)
41
- elif method == "ORB":
42
- orb = cv2.ORB_create(5000)
43
- kp1, des1 = orb.detectAndCompute(img1_gray, None)
44
- kp2, des2 = orb.detectAndCompute(img2_gray, None)
45
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
46
- elif method == "BRISK":
47
- brisk = cv2.BRISK_create()
48
- kp1, des1 = brisk.detectAndCompute(img1_gray, None)
49
- kp2, des2 = brisk.detectAndCompute(img2_gray, None)
50
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
51
- elif method == "KAZE":
52
- kaze = cv2.KAZE_create()
53
- kp1, des1 = kaze.detectAndCompute(img1_gray, None)
54
- kp2, des2 = kaze.detectAndCompute(img2_gray, None)
55
- matcher = cv2.BFMatcher(cv2.NORM_L2)
56
- elif method == "AKAZE":
57
- akaze = cv2.AKAZE_create()
58
- kp1, des1 = akaze.detectAndCompute(img1_gray, None)
59
- kp2, des2 = akaze.detectAndCompute(img2_gray, None)
60
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
61
- else:
62
- return None, None, []
63
-
64
- if des1 is None or des2 is None:
65
- return None, None, []
66
-
67
- raw_matches = matcher.knnMatch(des1, des2, k=2)
68
- good = []
69
- for m, n in raw_matches:
70
- if m.distance < ratio_thresh * n.distance:
71
- good.append(m)
72
- return kp1, kp2, good
73
-
74
- # ---------------- Main Homography Function ----------------
75
- def homography_all_detectors(flat_file, persp_file, json_file):
76
- flat_img = cv2.imread(flat_file)
77
- persp_img = cv2.imread(persp_file)
78
- mockup = json.load(open(json_file.name))
79
 
80
- roi_data = mockup["printAreas"][0]["position"]
81
- roi_x = roi_data["x"]
82
- roi_y = roi_data["y"]
83
- roi_w = mockup["printAreas"][0]["width"]
84
- roi_h = mockup["printAreas"][0]["height"]
85
- roi_rot_deg = mockup["printAreas"][0]["rotation"]
86
 
87
- flat_gray = preprocess_gray_clahe(flat_img)
88
- persp_gray = preprocess_gray_clahe(persp_img)
 
 
 
89
 
90
- methods = ["SIFT", "ORB", "BRISK", "KAZE", "AKAZE"]
91
- gallery_images = []
92
- download_files = []
93
 
94
- for method in methods:
95
- kp1, kp2, good_matches = detect_and_match(flat_gray, persp_gray, method=method)
96
-
97
- if kp1 is None or kp2 is None or len(good_matches) < 4:
98
- continue # skip if no matches
99
-
100
- src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1,1,2)
101
- dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1,1,2)
102
- H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
103
-
104
- if H is None:
105
- continue
106
 
107
- roi_corners_flat = get_rotated_rect_corners(roi_x, roi_y, roi_w, roi_h, roi_rot_deg)
108
- roi_corners_persp = cv2.perspectiveTransform(roi_corners_flat.reshape(-1,1,2), H).reshape(-1,2)
 
 
 
 
 
 
 
109
 
110
- persp_debug = persp_img.copy()
111
- cv2.polylines(persp_debug, [roi_corners_persp.astype(int)], True, (0,255,0), 2)
112
- for (px, py) in roi_corners_persp:
113
- cv2.circle(persp_debug, (int(px), int(py)), 5, (255,0,0), -1)
 
 
 
 
 
 
114
 
115
- # Convert BGR -> RGB for display
116
- result_rgb = cv2.cvtColor(persp_debug, cv2.COLOR_BGR2RGB)
 
117
 
118
- # Save result for download
119
- base_name = os.path.splitext(os.path.basename(persp_file))[0]
120
 
121
- # Save with same name + detector
122
- file_name = f"{base_name}_{method.lower()}.png"
123
- cv2.imwrite(file_name, cv2.cvtColor(result_rgb, cv2.COLOR_RGB2BGR))
124
 
125
- gallery_images.append((result_rgb, f"{method} Result"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  download_files.append(file_name)
127
 
128
- # return gallery + 5 download files (pad with None if less)
129
- while len(download_files) < 5:
130
- download_files.append(None)
131
-
132
- return [gallery_images] + download_files[:5]
133
 
134
  # ---------------- Gradio UI ----------------
135
- iface = gr.Interface(
136
  fn=homography_all_detectors,
137
  inputs=[
138
- gr.Image(label="Upload Flat Image", type="filepath"),
139
- gr.Image(label="Upload Perspective Image", type="filepath"),
140
- gr.File(label="Upload mockup.json", file_types=[".json"])
 
141
  ],
142
  outputs=[
143
- gr.Gallery(label="Results (per Detector)", show_label=True),
144
  gr.File(label="Download SIFT Result"),
145
  gr.File(label="Download ORB Result"),
146
  gr.File(label="Download BRISK Result"),
147
  gr.File(label="Download KAZE Result"),
148
  gr.File(label="Download AKAZE Result")
149
  ],
150
- title="Homography ROI Projection with Multiple Feature Detectors",
151
- description="Upload flat & perspective images with mockup.json. The system will project ROI using SIFT, ORB, BRISK, KAZE, and AKAZE. Each result can be viewed and downloaded."
152
  )
153
 
154
  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):
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)
22
+ clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
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
 
48
+ def parse_xml_points(xml_file):
49
+ tree = ET.parse(xml_file)
50
+ root = tree.getroot()
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"),
129
+ gr.Image(label="Upload Perspective Image",type="filepath"),
130
+ gr.File(label="Upload mockup.json",file_types=[".json"]),
131
+ gr.File(label="Upload XML file",file_types=[".xml"])
132
  ],
133
  outputs=[
134
+ gr.Gallery(label="Results per Detector",show_label=True),
135
  gr.File(label="Download SIFT Result"),
136
  gr.File(label="Download ORB Result"),
137
  gr.File(label="Download BRISK Result"),
138
  gr.File(label="Download KAZE Result"),
139
  gr.File(label="Download AKAZE Result")
140
  ],
141
+ title="Homography ROI Projection with Feature Matching & XML GT",
142
+ description="Flat + Perspective images with mockup.json & XML. Shows 4 views per detector: Flat, Feature Matches, ROI Projection, XML Ground Truth."
143
  )
144
 
145
  iface.launch()