import cv2
import numpy as np
from tkinter import Tk, Button, Canvas, ALL
from threading import Thread
from PIL import Image, ImageTk
# 初始化摄像头
capture = cv2.VideoCapture(0)
# 定义全局变量
canvas_width, canvas_height = 800, 600
capture_area = None
similarity_threshold = 0.7
# 创建主窗口
root = Tk()
root.title("Image Capture and Comparison")
# 创建两个画布
canvas = Canvas(root, width=canvas_width // 2, height=canvas_height)
canvas.pack(side="left")
static_canvas = Canvas(root, width=canvas_width // 2, height=canvas_height)
static_canvas.pack(side="right")
# 捕捉按钮
capture_button = Button(root, text="Capture", command=lambda: Thread(target=on_click, args=(None,)).start())
capture_button.pack(side="bottom")
def update_ui():
"""线程1:更新UI"""
while True:
ret, frame = capture.read()
if not ret:
break
# 调整帧大小以适应画布
frame = cv2.resize(frame, (canvas_width // 2, canvas_height))
# 将OpenCV图像转换为PIL图像,并创建一个PhotoImage对象
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
photo = ImageTk.PhotoImage(image=Image.fromarray(img))
# 清除旧图像并绘制新图像
canvas.delete(ALL)
canvas.create_image(0, 0, image=photo, anchor='nw')
root.update()
def process_image():
"""线程2:处理图像"""
global capture_area
while True:
ret, frame = capture.read()
if not ret or capture_area is None:
continue
# 对输入帧进行模板匹配
result = cv2.matchTemplate(frame, capture_area, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > similarity_threshold:
# 计算中心点位置
center = (max_loc[0] + capture_area.shape[1] // 2,
max_loc[1] + capture_area.shape[0] // 2)
# 在图像上绘制中心点和矩形区域
cv2.circle(frame, center, 5, (0, 0, 255), -1)
cv2.rectangle(frame, max_loc, (max_loc[0] + capture_area.shape[1], max_loc[1] + capture_area.shape[0]), (0, 0, 255), 2)
# 将处理后的图像显示在左侧画布
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (canvas_width // 2, canvas_height))
photo = ImageTk.PhotoImage(image=Image.fromarray(img))
canvas.delete(ALL)
canvas.create_image(0, 0, image=photo, anchor='nw')
root.update()
def on_click(event):
"""处理鼠标点击事件,选择静态区域"""
global capture_area
def update_selection(event, x, y):
global x1, y1
x1, y1 = event.x, event.y
static_canvas.delete(ALL)
static_canvas.create_rectangle(x, y, x1, y1, outline="red")
def finalize_selection(event, x1, y1):
global capture_area
img = cv2.cvtColor(np.array(ImageGrab.grab((canvas_width // 2, 0, canvas_width, canvas_height))), cv2.COLOR_BGR2RGB)
capture_area = img[min(y, y1):max(y, y1), min(x, x1):max(x, x1)]
static_canvas.delete(ALL)
static_canvas.create_image(0, 0, image=ImageTk.PhotoImage(Image.fromarray(capture_area)), anchor='nw')
static_canvas.unbind("<B1-Motion>")
static_canvas.unbind("<ButtonRelease-1>")
x, y = event.x, event.y
static_canvas.bind("<B1-Motion>", lambda e: update_selection(e, x, y))
static_canvas.bind("<ButtonRelease-1>", lambda e: finalize_selection(e, x, y))
if __name__ == "__main__":
# 启动两个线程
Thread(target=update_ui).start()
Thread(target=process_image).start()
# 进入主循环
root.mainloop()
# 释放资源
capture.release()
'''
使用多线程分别处理UI更新和图像处理。
左侧动态区显示实时图像。
右侧静态区显示捕获的图像,并可以通过鼠标框选特征区域。
模板匹配找出与右侧特征区域相似的区域,并在左侧图像上绘制出来。
用户可以设置相似度阈值(在本例中固定为0.7)
'''