Ayesha352 commited on
Commit
5138913
·
verified ·
1 Parent(s): 438fcec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -158
app.py CHANGED
@@ -1,178 +1,120 @@
1
  import gradio as gr
2
  import cv2
3
  import numpy as np
4
- import matplotlib.pyplot as plt
5
  import json
6
  import math
7
- import os
8
-
9
- def ransac(image1, image2, detector_type):
10
- """
11
- Finds the homography matrix using the RANSAC algorithm with the selected feature detector.
12
- """
13
- gray1 = cv2.cvtColor(image1, cv2.COLOR_RGB2GRAY)
14
- gray2 = cv2.cvtColor(image2, cv2.COLOR_RGB2GRAY)
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  if detector_type == "SIFT":
17
- detector = cv2.SIFT_create()
18
- matcher = cv2.FlannBasedMatcher(dict(algorithm=1, trees=5), dict(checks=50))
19
- elif detector_type == "ORB":
20
- detector = cv2.ORB_create()
21
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
22
  elif detector_type == "BRISK":
23
  detector = cv2.BRISK_create()
24
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
 
 
 
25
  elif detector_type == "AKAZE":
26
  detector = cv2.AKAZE_create()
27
- matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
28
  elif detector_type == "KAZE":
29
  detector = cv2.KAZE_create()
30
- matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
31
- else:
32
- return None
33
-
34
- kp1, des1 = detector.detectAndCompute(gray1, None)
35
- kp2, des2 = detector.detectAndCompute(gray2, None)
36
-
37
- if des1 is None or des2 is None or len(kp1) < 2 or len(kp2) < 2:
38
- return None
39
-
40
- try:
41
- if detector_type == "SIFT":
42
- matches = matcher.knnMatch(des1, des2, k=2)
43
- good_matches = []
44
- if matches:
45
- for m, n in matches:
46
- if m.distance < 0.75 * n.distance:
47
- good_matches.append(m)
48
- else:
49
- matches = matcher.match(des1, des2)
50
- good_matches = sorted(matches, key=lambda x: x.distance)
51
- except cv2.error as e:
52
- print(f"Error during matching: {e}")
53
- return None
54
-
55
- if len(good_matches) > 10:
56
- src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
57
- dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
58
- H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
59
- return H
60
  else:
61
- return None
62
-
63
- def get_bounding_box_points(json_data):
64
- """
65
- Extracts and calculates the four corner points of the bounding box, assuming x,y are top-left.
66
- """
67
- print_area = json_data['printAreas'][0]
68
- x = print_area['position']['x']
69
- y = print_area['position']['y']
70
- w = print_area['width']
71
- h = print_area['height']
72
- rotation_deg = print_area['rotation']
73
-
74
- points = np.float32([
75
- [0, 0],
76
- [w, 0],
77
- [w, h],
78
- [0, h]
79
- ]).reshape(-1, 1, 2)
80
-
81
- rotation_rad = math.radians(rotation_deg)
82
- cos_theta = math.cos(rotation_rad)
83
- sin_theta = math.sin(rotation_rad)
84
- rotation_matrix = np.array([
85
- [cos_theta, -sin_theta],
86
- [sin_theta, cos_theta]
87
- ])
88
-
89
- rotated_points = np.dot(points.reshape(-1, 2), rotation_matrix.T)
90
- final_points = rotated_points + np.array([x, y])
91
- return final_points.reshape(-1, 1, 2)
92
-
93
- def process_and_plot_all_detectors(image1_np, image2_np, json_file):
94
- """
95
- Processes the images with all available detectors and returns image data for display and download.
96
- Keeps original RGB colors intact.
97
- """
98
- if image1_np is None or image2_np is None:
99
- return [None] * 6
100
-
101
- try:
102
- with open(json_file.name, 'r') as f:
103
- data = json.load(f)
104
- except Exception as e:
105
- print(f"Error: Could not read JSON file. {e}")
106
- return [None] * 6
107
-
108
- detectors = ["SIFT", "ORB", "BRISK", "AKAZE", "KAZE"]
109
  gallery_images = []
110
- download_files = [None] * 5
111
-
112
- for i, detector_type in enumerate(detectors):
113
- H = ransac(image1_np, image2_np, detector_type)
114
-
115
- if H is not None:
116
- box_points = get_bounding_box_points(data)
117
-
118
- # Convert RGB → BGR for OpenCV drawing
119
- output_flat_img = cv2.cvtColor(image1_np, cv2.COLOR_RGB2BGR)
120
- cv2.polylines(output_flat_img, [np.int32(box_points)], isClosed=True, color=(0, 0, 255), thickness=5)
121
-
122
- transformed_box_points = cv2.perspectiveTransform(box_points, H)
123
-
124
- output_perspective_img = cv2.cvtColor(image2_np, cv2.COLOR_RGB2BGR)
125
- cv2.polylines(output_perspective_img, [np.int32(transformed_box_points)], isClosed=True, color=(0, 0, 255), thickness=5)
126
-
127
- # Convert BGR → RGB for display
128
- output_flat_img = cv2.cvtColor(output_flat_img, cv2.COLOR_BGR2RGB)
129
- output_perspective_img = cv2.cvtColor(output_perspective_img, cv2.COLOR_BGR2RGB)
130
-
131
- # Plot images side by side
132
- fig, axes = plt.subplots(1, 3, figsize=(18, 6))
133
- axes[0].imshow(output_flat_img)
134
- axes[0].set_title(f'Original (Flat) - {detector_type}')
135
- axes[0].axis('off')
136
-
137
- axes[1].imshow(image2_np) # original perspective image in RGB
138
- axes[1].set_title('Original (Perspective)')
139
- axes[1].axis('off')
140
-
141
- axes[2].imshow(output_perspective_img)
142
- axes[2].set_title('Projected Bounding Box')
143
- axes[2].axis('off')
144
-
145
- plt.tight_layout()
146
- file_name = f"result_{detector_type.lower()}.png"
147
- plt.savefig(file_name)
148
- plt.close(fig)
149
-
150
- gallery_images.append(file_name)
151
- download_files[i] = file_name
152
- else:
153
- print(f"Warning: Homography matrix could not be found with {detector_type} detector. Skipping this result.")
154
- # download_files[i] remains None
155
-
156
- return [gallery_images] + download_files
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  iface = gr.Interface(
160
- fn=process_and_plot_all_detectors,
161
- inputs=[
162
- gr.Image(type="numpy", label="Image 1 (Flat)"),
163
- gr.Image(type="numpy", label="Image 2 (Perspective)"),
164
- gr.File(type="filepath", label="JSON File")
165
- ],
166
- outputs=[
167
- gr.Gallery(label="Results"),
168
- gr.File(label="Download SIFT Result"),
169
- gr.File(label="Download ORB Result"),
170
- gr.File(label="Download BRISK Result"),
171
- gr.File(label="Download AKAZE Result"),
172
- gr.File(label="Download KAZE Result")
173
- ],
174
- title="Homography and Bounding Box Projection with All Detectors",
175
- description="Upload two images and a JSON file to see the bounding box projection for all 5 feature extraction methods. Each result can be downloaded separately."
176
  )
177
 
178
- iface.launch()
 
1
  import gradio as gr
2
  import cv2
3
  import numpy as np
 
4
  import json
5
  import math
6
+ import matplotlib.pyplot as plt
 
 
 
 
 
 
 
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],
14
+ [sin_r, cos_r]])
15
+ cx, cy = x + w/2, y + h/2
16
+ local_corners = np.array([[-w/2,-h/2],[w/2,-h/2],[w/2,h/2],[-w/2,h/2]])
17
+ rotated_corners = np.dot(local_corners, R.T) + np.array([cx, cy])
18
+ return rotated_corners.astype(np.float32)
19
+
20
+ def preprocess_gray_clahe(img):
21
+ gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
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, detector_type, ratio_thresh=0.78):
26
  if detector_type == "SIFT":
27
+ detector = cv2.SIFT_create(nfeatures=5000)
28
+ matcher = cv2.BFMatcher(cv2.NORM_L2)
 
 
 
29
  elif detector_type == "BRISK":
30
  detector = cv2.BRISK_create()
31
+ matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
32
+ elif detector_type == "ORB":
33
+ detector = cv2.ORB_create(5000)
34
+ matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
35
  elif detector_type == "AKAZE":
36
  detector = cv2.AKAZE_create()
37
+ matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
38
  elif detector_type == "KAZE":
39
  detector = cv2.KAZE_create()
40
+ matcher = cv2.BFMatcher(cv2.NORM_L2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  else:
42
+ return None, None, []
43
+
44
+ kp1, des1 = detector.detectAndCompute(img1_gray, None)
45
+ kp2, des2 = detector.detectAndCompute(img2_gray, None)
46
+ if des1 is None or des2 is None:
47
+ return kp1, kp2, []
48
+
49
+ raw_matches = matcher.knnMatch(des1, des2, k=2)
50
+ good = [m for m,n in raw_matches if m.distance < ratio_thresh * n.distance]
51
+ return kp1, kp2, good
52
+
53
+ def get_roi_points_from_json(json_file):
54
+ data = json.load(json_file)
55
+ area = data["printAreas"][0]
56
+ x = area["position"]["x"]
57
+ y = area["position"]["y"]
58
+ w = area["width"]
59
+ h = area["height"]
60
+ rot = area["rotation"]
61
+ return x, y, w, h, rot
62
+
63
+ def process_images(flat_img, persp_img, json_file):
64
+ # Preprocess
65
+ flat_gray = preprocess_gray_clahe(flat_img)
66
+ persp_gray = preprocess_gray_clahe(persp_img)
67
+ x, y, w, h, rot = get_roi_points_from_json(json_file)
68
+
69
+ detectors = ["SIFT","BRISK","ORB","AKAZE","KAZE"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  gallery_images = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
+ for det in detectors:
73
+ kp1, kp2, matches = detect_and_match(flat_gray, persp_gray, det)
74
+ if len(matches) < 4:
75
+ # Skip if too few matches
76
+ continue
77
+
78
+ src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1,1,2)
79
+ dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1,1,2)
80
+ H, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
81
+
82
+ # ROI in flat
83
+ roi_flat = get_rotated_rect_corners(x,y,w,h,rot)
84
+ flat_copy = flat_img.copy()
85
+ cv2.polylines(flat_copy, [roi_flat.astype(int)], True, (0,0,255),2)
86
+
87
+ # Project ROI to perspective
88
+ roi_persp = cv2.perspectiveTransform(roi_flat.reshape(-1,1,2), H).reshape(-1,2)
89
+ persp_copy = persp_img.copy()
90
+ cv2.polylines(persp_copy, [roi_persp.astype(int)], True, (0,255,0),2)
91
+ for px, py in roi_persp:
92
+ cv2.circle(persp_copy, (int(px),int(py)), 5, (255,0,0), -1)
93
+
94
+ # Side-by-side for this detector
95
+ fig, ax = plt.subplots(1,2,figsize=(12,6))
96
+ ax[0].imshow(flat_copy)
97
+ ax[0].set_title(f"Flat ROI - {det}")
98
+ ax[0].axis("off")
99
+ ax[1].imshow(persp_copy)
100
+ ax[1].set_title(f"Perspective ROI - {det}")
101
+ ax[1].axis("off")
102
+ plt.tight_layout()
103
+ filename = f"{det}_result.png"
104
+ plt.savefig(filename)
105
+ plt.close(fig)
106
+ gallery_images.append(filename)
107
+
108
+ return gallery_images
109
 
110
  iface = gr.Interface(
111
+ fn=process_images,
112
+ inputs=[gr.Image(type="numpy", label="Flat Image"),
113
+ gr.Image(type="numpy", label="Perspective Image"),
114
+ gr.File(label="JSON File")],
115
+ outputs=gr.Gallery(label="ROI Projection Results"),
116
+ title="ROI Projection with Multiple Feature Detectors",
117
+ description="Displays ROI projected from Flat to Perspective image using SIFT, BRISK, ORB, AKAZE, KAZE."
 
 
 
 
 
 
 
 
 
118
  )
119
 
120
+ iface.launch()