Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import json | |
| import math | |
| import os | |
| def ransac(image1, image2, detector_type): | |
| """ | |
| Finds the homography matrix using the RANSAC algorithm with the selected feature detector. | |
| """ | |
| gray1 = cv2.cvtColor(image1, cv2.COLOR_RGB2GRAY) | |
| gray2 = cv2.cvtColor(image2, cv2.COLOR_RGB2GRAY) | |
| if detector_type == "SIFT": | |
| detector = cv2.SIFT_create() | |
| matcher = cv2.FlannBasedMatcher(dict(algorithm=1, trees=5), dict(checks=50)) | |
| elif detector_type == "ORB": | |
| detector = cv2.ORB_create() | |
| matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) | |
| elif detector_type == "BRISK": | |
| detector = cv2.BRISK_create() | |
| matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) | |
| elif detector_type == "AKAZE": | |
| detector = cv2.AKAZE_create() | |
| matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) | |
| elif detector_type == "KAZE": | |
| detector = cv2.KAZE_create() | |
| matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True) | |
| else: | |
| return None | |
| kp1, des1 = detector.detectAndCompute(gray1, None) | |
| kp2, des2 = detector.detectAndCompute(gray2, None) | |
| if des1 is None or des2 is None or len(kp1) < 2 or len(kp2) < 2: | |
| return None | |
| try: | |
| if detector_type == "SIFT": | |
| matches = matcher.knnMatch(des1, des2, k=2) | |
| good_matches = [] | |
| if matches: | |
| for m, n in matches: | |
| if m.distance < 0.75 * n.distance: | |
| good_matches.append(m) | |
| else: | |
| matches = matcher.match(des1, des2) | |
| good_matches = sorted(matches, key=lambda x: x.distance) | |
| except cv2.error as e: | |
| print(f"Error during matching: {e}") | |
| return None | |
| if len(good_matches) > 10: | |
| src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) | |
| dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) | |
| H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) | |
| return H | |
| else: | |
| return None | |
| def get_bounding_box_points(json_data): | |
| """ | |
| Extracts and calculates the four corner points of the bounding box, assuming x,y are top-left. | |
| """ | |
| print_area = json_data['printAreas'][0] | |
| x = print_area['position']['x'] | |
| y = print_area['position']['y'] | |
| w = print_area['width'] | |
| h = print_area['height'] | |
| rotation_deg = print_area['rotation'] | |
| points = np.float32([ | |
| [0, 0], | |
| [w, 0], | |
| [w, h], | |
| [0, h] | |
| ]).reshape(-1, 1, 2) | |
| rotation_rad = math.radians(rotation_deg) | |
| cos_theta = math.cos(rotation_rad) | |
| sin_theta = math.sin(rotation_rad) | |
| rotation_matrix = np.array([ | |
| [cos_theta, -sin_theta], | |
| [sin_theta, cos_theta] | |
| ]) | |
| rotated_points = np.dot(points.reshape(-1, 2), rotation_matrix.T) | |
| final_points = rotated_points + np.array([x, y]) | |
| return final_points.reshape(-1, 1, 2) | |
| def process_and_plot_all_detectors(image1_np, image2_np, json_file): | |
| """ | |
| Processes the images with all available detectors and returns image data for display and download. | |
| """ | |
| if image1_np is None or image2_np is None: | |
| return [None] * 6 | |
| try: | |
| with open(json_file.name, 'r') as f: | |
| data = json.load(f) | |
| except Exception as e: | |
| print(f"Error: Could not read JSON file. {e}") | |
| return [None] * 6 | |
| detectors = ["SIFT", "ORB", "BRISK", "AKAZE", "KAZE"] | |
| gallery_images = [] | |
| download_files = [None] * 5 | |
| for i, detector_type in enumerate(detectors): | |
| H = ransac(image1_np, image2_np, detector_type) | |
| if H is not None: | |
| box_points = get_bounding_box_points(data) | |
| output_flat_img = image1_np.copy() | |
| cv2.polylines(output_flat_img, [np.int32(box_points)], isClosed=True, color=(0, 0, 255), thickness=5) | |
| transformed_box_points = cv2.perspectiveTransform(box_points, H) | |
| output_perspective_img = image2_np.copy() | |
| cv2.polylines(output_perspective_img, [np.int32(transformed_box_points)], isClosed=True, color=(0, 0, 255), thickness=5) | |
| fig, axes = plt.subplots(1, 3, figsize=(18, 6)) | |
| axes[0].imshow(cv2.cvtColor(output_flat_img, cv2.COLOR_BGR2RGB)) | |
| axes[0].set_title(f'Original (Flat) - {detector_type}') | |
| axes[0].axis('off') | |
| axes[1].imshow(cv2.cvtColor(image2_np, cv2.COLOR_BGR2RGB)) | |
| axes[1].set_title('Original (Perspective)') | |
| axes[1].axis('off') | |
| axes[2].imshow(cv2.cvtColor(output_perspective_img, cv2.COLOR_BGR2RGB)) | |
| axes[2].set_title('Projected Bounding Box') | |
| axes[2].axis('off') | |
| plt.tight_layout() | |
| file_name = f"result_{detector_type.lower()}.png" | |
| plt.savefig(file_name) | |
| plt.close(fig) | |
| gallery_images.append(file_name) | |
| download_files[i] = file_name | |
| else: | |
| print(f"Warning: Homography matrix could not be found with {detector_type} detector. Skipping this result.") | |
| # We don't append None to the gallery_images list to avoid the error. | |
| # download_files[i] remains None, which is handled correctly by gr.File. | |
| return [gallery_images] + download_files | |
| iface = gr.Interface( | |
| fn=process_and_plot_all_detectors, | |
| inputs=[ | |
| gr.Image(type="numpy", label="Image 1 (Flat)"), | |
| gr.Image(type="numpy", label="Image 2 (Perspective)"), | |
| gr.File(type="filepath", label="JSON File") | |
| ], | |
| outputs=[ | |
| gr.Gallery(label="Results"), | |
| gr.File(label="Download SIFT Result"), | |
| gr.File(label="Download ORB Result"), | |
| gr.File(label="Download BRISK Result"), | |
| gr.File(label="Download AKAZE Result"), | |
| gr.File(label="Download KAZE Result") | |
| ], | |
| title="Homography and Bounding Box Projection with All Detectors", | |
| 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." | |
| ) | |
| iface.launch() |