| import json |
| import cv2 |
| import numpy as np |
| import matplotlib.pyplot as plt |
| from lxml import etree |
|
|
| |
| def autocrop(image, tol=0): |
| """Crops black borders from an image.""" |
| if len(image.shape) == 3: |
| mask = (image > tol).any(2) |
| else: |
| mask = image > tol |
| if mask.any(): |
| coords = np.argwhere(mask) |
| y0, x0 = coords.min(axis=0) |
| y1, x1 = coords.max(axis=0) + 1 |
| image = image[y0:y1, x0:x1] |
| return image |
|
|
| |
| def stack_images_side_by_side(img1, img2): |
| """Resizes two images to a common height and stacks them horizontally.""" |
| target_h = max(img1.shape[0], img2.shape[0]) |
| w1 = int(img1.shape[1] * (target_h / img1.shape[0])) |
| w2 = int(img2.shape[1] * (target_h / img2.shape[0])) |
|
|
| img1_resized = cv2.resize(img1, (w1, target_h)) |
| img2_resized = cv2.resize(img2, (w2, target_h)) |
|
|
| return np.hstack([img1_resized, img2_resized]) |
|
|
| |
| def get_json_corners(json_file): |
| """Extracts rotated rectangle corners from mockup.json.""" |
| with open(json_file, 'r') as f: |
| data = json.load(f) |
|
|
| area = data['printAreas'][0] |
| x, y = area['position']['x'], area['position']['y'] |
| w, h, angle = area['width'], area['height'], area['rotation'] |
| cx, cy = x + w / 2, y + h / 2 |
|
|
| angle_rad = np.radians(angle) |
| dx, dy = w / 2, h / 2 |
| corners = np.array([[-dx, -dy], [dx, -dy], [dx, dy], [-dx, dy]]) |
| R = np.array([[np.cos(angle_rad), -np.sin(angle_rad)], |
| [np.sin(angle_rad), np.cos(angle_rad)]]) |
| rotated = np.dot(corners, R.T) + np.array([cx, cy]) |
| return rotated.astype(int) |
|
|
| |
| def extract_points_from_xml(xml_file): |
| """Extracts corner points from a visual.xml file.""" |
| tree = etree.parse(xml_file) |
| root = tree.getroot() |
| transform = root.find('.//transform') |
| points = {} |
| for pt in transform.findall('.//point'): |
| points[pt.attrib['type']] = (float(pt.attrib['x']), float(pt.attrib['y'])) |
| order = ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'] |
| return np.array([points[p] for p in order], dtype=np.float32) |
|
|
| |
| def draw_feature_matching(img1, pts1, img2, pts2, color,draw_boxes=True): |
| """ |
| Draws feature correspondences between two images, handling different sizes. |
| """ |
| |
| target_h = max(img1.shape[0], img2.shape[0]) |
|
|
| |
| scale1 = target_h / img1.shape[0] |
| w1_new = int(img1.shape[1] * scale1) |
|
|
| scale2 = target_h / img2.shape[0] |
| w2_new = int(img2.shape[1] * scale2) |
|
|
| |
| img1_resized = cv2.resize(img1, (w1_new, target_h)) |
| img2_resized = cv2.resize(img2, (w2_new, target_h)) |
|
|
| |
| pts1_scaled = (pts1 * scale1).astype(int) |
| pts2_scaled = (pts2 * scale2).astype(int) |
|
|
| |
| h, w1, w2 = target_h, w1_new, w2_new |
| new_img = np.concatenate([img1_resized, img2_resized], axis=1) |
|
|
| |
| if draw_boxes: |
| cv2.polylines(new_img, [pts1_scaled.reshape((-1,1,2))], True, color, 3) |
| cv2.polylines(new_img, [pts2_scaled.reshape((-1,1,2)) + np.array([w1_new,0])], True, color, 3) |
|
|
| |
| for (x1, y1), (x2, y2) in zip(pts1_scaled, pts2_scaled): |
| color = tuple(np.random.randint(0, 255, 3).tolist()) |
| cv2.circle(new_img, (x1, y1), 6, color, -1) |
| cv2.circle(new_img, (x2 + w1, y2), 6, color, -1) |
| cv2.line(new_img, (x1, y1), (x2 + w1, y2), color, 2) |
|
|
| return new_img |
|
|
|
|
|
|