saim1309's picture
Update plot.py
e0400ee verified
import json
import cv2
import numpy as np
import matplotlib.pyplot as plt
from lxml import etree
# ========= Crop black borders =========
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
# ========= Stack horizontally =========
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])
# ========= Extract rectangle from JSON =========
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)
# ========= Extract polygon from XML =========
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)
# ========= Draw correspondences and (optional) boxes =========
def draw_feature_matching(img1, pts1, img2, pts2, color,draw_boxes=True):
"""
Draws feature correspondences between two images, handling different sizes.
"""
# Resize images to a common height to avoid black padding bars
target_h = max(img1.shape[0], img2.shape[0])
# Calculate scaling factors and new widths
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)
# Resize images
img1_resized = cv2.resize(img1, (w1_new, target_h))
img2_resized = cv2.resize(img2, (w2_new, target_h))
# Scale points to match the resized images
pts1_scaled = (pts1 * scale1).astype(int)
pts2_scaled = (pts2 * scale2).astype(int)
# Create the combined image canvas
h, w1, w2 = target_h, w1_new, w2_new
new_img = np.concatenate([img1_resized, img2_resized], axis=1)
# Optional: Draw polygons (boxes)
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)
# Draw correspondences
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