import tkinter as tk
from tkinter import font, filedialog
from PIL import Image, ImageTk
import cv2
import numpy as np
import time
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("Obj_Detection")
self.geometry('1200x600')
# 字体设置
self.font = font.Font(family='SimSun', size=28)
self.font2 = font.Font(family='SimSun', size=18)
# 创建三个框架
self.left_frame = tk.Frame(self, width=640, height=600)
self.center_frame = tk.Frame(self, width=266, height=600)
self.right_frame = tk.Frame(self, width=266, height=600)
self.left_frame.grid(row=0, column=0, padx=1, pady=1)
self.center_frame.grid(row=0, column=1, padx=1, pady=1)
self.right_frame.grid(row=0, column=2, padx=1, pady=1)
# 左侧实时画面标签
self.label_left = tk.Label(self.left_frame, text="实时画面", font=self.font)
self.label_left.pack(pady=(10, 0))
# 实时显示检测结果
self.label2_left = tk.Label(self.left_frame, text="准备开始检测", font=self.font2)
self.label2_left.pack(pady=(10, 0))
# 中间目标图案标签
self.label_center_top = tk.Label(self.center_frame, text="目标图案", font=self.font)
self.label_center_top.pack(pady=(10, 0))
# 右侧Log标签
self.label_right_top = tk.Label(self.right_frame, text="Log 记录", font=self.font)
self.label_right_top.pack(pady=(10, 0))
self.log_text = tk.Text(self.right_frame, height=20, width=30)
self.log_text.pack(pady=(10, 0))
self.log("系统初始化完成")
# 按钮用于截图
self.button_capture = tk.Button(self.center_frame, text="截图后开启检测", command=self.start_capture)
self.button_capture.pack(pady=(10, 0))
# 设置相似度阈值
self.threshold_label = tk.Label(self.center_frame, text="边缘检测阈值:")
self.threshold_label.pack(pady=(10, 0))
self.threshold_slider = tk.Scale(self.center_frame, from_=0, to=255, resolution=1, orient=tk.HORIZONTAL)
self.threshold_slider.set(100)
self.threshold_slider.pack(pady=(0, 10))
# 中间下方的标签用于显示缩略图
self.label_center_bottom = tk.Label(self.center_frame, text="缩略图")
self.label_center_bottom.pack(pady=(10, 0))
# 用于显示图像的Canvas
self.canvas_left = tk.Canvas(self.left_frame, width=640, height=480)
self.canvas_left.pack(pady=(10, 0))
# 图像存储
self.image_to_compare = None
self.target_region = None
self.selection_start = None
self.selection_end = None
# 开启摄像头
self.cap = cv2.VideoCapture(0)
self.update_frame()
def update_frame(self):
ret, frame = self.cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(frame)
img_tk = ImageTk.PhotoImage(image=img)
self.canvas_left.create_image(0, 0, anchor=tk.NW, image=img_tk)
self.canvas_left.img = img_tk
# 如果有目标区域,则进行边缘检测并框选
if self.target_region is not None:
edges = self.detect_edges(frame)
self.display_results(frame, edges)
self.after(15, self.update_frame)
def start_capture(self):
ret, frame = self.cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.image_to_compare = Image.fromarray(frame)
self.image_to_compare.thumbnail((640, 480))
img_tk = ImageTk.PhotoImage(self.image_to_compare)
self.label_center_bottom.config(image=img_tk)
self.label_center_bottom.img = img_tk
self.log("截图成功")
self.canvas_left.bind("<Button-1>", self.on_click)
self.canvas_left.bind("<B1-Motion>", self.on_drag)
self.canvas_left.bind("<ButtonRelease-1>", self.on_release)
def on_click(self, event):
self.selection_start = (event.x, event.y)
def on_drag(self, event):
if self.selection_start:
self.canvas_left.delete("selection_rect")
self.canvas_left.create_rectangle(
self.selection_start[0], self.selection_start[1],
event.x, event.y,
outline="blue", tags="selection_rect"
)
def on_release(self, event):
if self.selection_start and event.x != self.selection_start[0] and event.y != self.selection_start[1]:
self.target_region = (min(event.x, self.selection_start[0]), min(event.y, self.selection_start[1]),
abs(event.x - self.selection_start[0]), abs(event.y - self.selection_start[1]))
self.canvas_left.delete("selection_rect")
self.canvas_left.create_rectangle(
self.target_region[0], self.target_region[1],
self.target_region[0] + self.target_region[2], self.target_region[1] + self.target_region[3],
outline="blue", tags="selection_rect"
)
self.log("目标区域选定")
def detect_edges(self, frame):
# 截取目标区域
if self.target_region:
target_region = frame[
self.target_region[1]:self.target_region[1] + self.target_region[3],
self.target_region[0]:self.target_region[0] + self.target_region[2]
]
# 将图像转换为灰度图像
gray = cv2.cvtColor(target_region, cv2.COLOR_RGB2GRAY)
# 使用Canny算法检测边缘
low_threshold = self.threshold_slider.get()
high_threshold = low_threshold * 3 # Canny通常建议高阈值是低阈值的两到三倍
edges = cv2.Canny(gray, low_threshold, high_threshold)
# 将边缘图像转换回PIL格式以便在GUI中显示
edges_img = Image.fromarray(edges)
return edges_img
def display_results(self, frame, edges_img):
if self.target_region and edges_img:
# 在实时画面上框选目标区域
cv2.rectangle(frame, (self.target_region[0], self.target_region[1]),
(self.target_region[0] + self.target_region[2], self.target_region[1] + self.target_region[3]),
(255, 0, 0), 2)
# 在目标区域内绘制边缘
edges_array = np.array(edges_img)
edges_array = cv2.cvtColor(edges_array, cv2.COLOR_GRAY2RGB)
frame[self.target_region[1]:self.target_region[1] + self.target_region[3],
self.target_region[0]:self.target_region[0] + self.target_region[2]] = edges_array
img = Image.fromarray(frame)
img_tk = ImageTk.PhotoImage(image=img)
self.canvas_left.create_image(0, 0, anchor=tk.NW, image=img_tk)
self.canvas_left.img = img_tk
def log(self, message):
current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
self.log_text.insert(tk.END, f"{current_time}: {message}\n")
self.log_text.see(tk.END)
if __name__ == "__main__":
app = Application()
app.mainloop()