I am making a program that executes image-to-image correspondence between a PCB and its diagram. I have made a function template_matching
that handles template matching and deleting visited areas so it can find all instances of the template above a certain threshold. The program should calculate the angle from the reference point (0,0) and see if the components match (I am doing this because i also want to check if their polarity is the same, otherwise I would have used BF Matching). The problem is that it still overlaps matches, meaning it didn’t delete the previous matches from the image.
I have tried some logging prints and displaying the image at different points, but the problem seems to be how it deletes the zones. This is the code:
import cv2
import numpy as np
def template_matching(image, template, threshold=0.38):
matches = []
result = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
h, w = template.shape[:2]
while True:
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val < threshold:
break
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# Append the match
matches.append((top_left, bottom_right, max_val))
# Zero out the region in the result matrix to avoid future detections in this area
result[top_left[1]:bottom_right[1], top_left[0]:bottom_right[0]] = 0
print(np.array(result))
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows(0)
return matches
def calculate_angle(point1, point2):
delta_y = point2[1] - point1[1]
delta_x = point2[0] - point1[0]
angle = np.arctan2(delta_y, delta_x) * 180 / np.pi
return angle
def load_image(filepath):
image = cv2.imread(filepath)
if image is None:
raise FileNotFoundError(f"Error: Unable to open or read image file at '{filepath}'. Please check the file path and file integrity.")
return image
# File paths
pcb_photo_path = "C:\Users\q77597\Desktop\project\templates\template_5.jpeg"
diagram_path = "C:\Users\q77597\Desktop\project\ceplm.png"
pcb_resistor_template_path = "C:\Users\q77597\Desktop\project\templates\pcb_resistor_template.png"
pcb_capacitor_template_path = "C:\Users\q77597\Desktop\project\templates\pcb_capacitor_template.png"
diagram_resistor_template_path = "C:\Users\q77597\Desktop\project\templates\d_resistor_template.png"
diagram_capacitor_template_path = "C:\Users\q77597\Desktop\project\templates\d_capacitor_template.png"
# Load images
try:
pcb_photo = load_image(pcb_photo_path)
diagram = load_image(diagram_path)
pcb_resistor_template = load_image(pcb_resistor_template_path)
pcb_capacitor_template = load_image(pcb_capacitor_template_path)
diagram_resistor_template = load_image(diagram_resistor_template_path)
diagram_capacitor_template = load_image(diagram_capacitor_template_path)
pcb_copy = pcb_photo.copy()
diagram_copy = diagram.copy()
except FileNotFoundError as e:
print(e)
exit(1)
# List of components and their respective templates
components = [
('resistor', pcb_resistor_template, diagram_resistor_template),
('capacitor', pcb_capacitor_template, diagram_capacitor_template)
]
# Reference points (these should be meaningful points in your specific use case)
point1_pcb = (0, 0) # Reference point for the PCB
point1_diagram = (0, 0) # Reference point for the diagram
for component_name, pcb_template, diagram_template in components:
# Match components on the PCB photo
pcb_matches = template_matching(pcb_copy, pcb_template)
diagram_matches = template_matching(diagram_copy, diagram_template)
for pcb_match, diagram_match in zip(pcb_matches, diagram_matches):
top_left_pcb, bottom_right_pcb, match_score_pcb = pcb_match
top_left_diagram, bottom_right_diagram, match_score_diagram = diagram_match
print(f"PCB {component_name}: Top Left: {top_left_pcb}, Bottom Right: {bottom_right_pcb}, Match Score: {match_score_pcb}")
print(f"Diagram {component_name}: Top Left: {top_left_diagram}, Bottom Right: {bottom_right_diagram}, Match Score: {match_score_diagram}")
component_center_pcb = ((top_left_pcb[0] + bottom_right_pcb[0]) // 2, (top_left_pcb[1] + bottom_right_pcb[1]) // 2)
component_center_diagram = ((top_left_diagram[0] + bottom_right_diagram[0]) // 2, (top_left_diagram[1] + bottom_right_diagram[1]) // 2)
# Calculate angles
angle_pcb = calculate_angle(point1_pcb, component_center_pcb)
angle_diagram = calculate_angle(point1_diagram, component_center_diagram)
# Check if the angles are approximately the same
if np.isclose(angle_pcb, angle_diagram, atol=10): # Adjust tolerance as needed
print(f"{component_name} polarity is correct")
else:
print(f"{component_name} polarity is incorrect")
# Visualize matches on PCB photo
cv2.rectangle(pcb_copy, top_left_pcb, bottom_right_pcb, (0, 0, 255), 2)
# Draw line to show angle on PCB
cv2.line(pcb_copy, point1_pcb, component_center_pcb, (0, 0, 255), 2)
cv2.putText(pcb_copy, f'Angle: {angle_pcb:.2f}', (component_center_pcb[0] + 10, component_center_pcb[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
# Visualize matches on diagram
cv2.rectangle(diagram_copy, top_left_diagram, bottom_right_diagram, (0, 0, 255), 2)
# Draw line to show angle on diagram
cv2.line(diagram_copy, point1_diagram, component_center_diagram, (0, 0, 255), 2)
cv2.putText(diagram_copy, f'Angle: {angle_diagram:.2f}', (component_center_diagram[0] + 10, component_center_diagram[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
# Show the images
cv2.imshow('Matched components on PCB', pcb_copy)
cv2.imshow('Matched components on Diagram', diagram_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
These are the photos i used (the diagram and the pcb photo are 1:1, i overlapped them and drew some symbols):