Obj_Detection_Edge_V3

import tkinter as tk
from tkinter import font
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.font3 = font.Font(family='SimSun', size=14)  # 缩小的字体

        # 创建三个框架
        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.button_delete_all = tk.Button(self.center_frame, text="删除所有选定区域", command=self.delete_selected_region)
        self.button_delete_all.pack(pady=(10, 0))

        # 中间下方的标签用于显示缩略图
        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, scrollregion=(0, 0, 640, 480))
        hbar = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL)
        hbar.pack(side=tk.BOTTOM, fill=tk.X)
        hbar.config(command=self.canvas_left.xview)
        vbar = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL)
        vbar.pack(side=tk.RIGHT, fill=tk.Y)
        vbar.config(command=self.canvas_left.yview)
        self.canvas_left.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
        self.canvas_left.pack(pady=(10, 0))

        # 图像存储
        self.image_to_compare = None
        self.target_regions = []  # 存储所有目标区域及其阈值
        self.selection_start = None
        self.selection_end = None
        self.selection_tag = None
        self.entries_layout = []  # 用于追踪输入框的位置
        self.entry_width = 100  # 假设每个输入框的宽度
        self.entry_height = 30  # 假设每个输入框的高度
        self.current_x = 10  # 初始X位置
        self.current_y = 10  # 初始Y位置

        # 开启摄像头
        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_regions:
                for idx, (region, threshold) in enumerate(self.target_regions):
                    edges = self.detect_edges(frame, region, threshold)
                    self.display_results(frame, edges, region, idx+1)
            
        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(self.selection_tag)
            self.selection_end = (event.x, event.y)
            self.selection_tag = 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]:
            new_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]))
            specific_threshold = tk.StringVar(value=str(self.threshold_slider.get()))
            entry = tk.Entry(self.center_frame, textvariable=specific_threshold, width=10)
            entry.pack(side=tk.TOP, padx=(self.current_x, 0), pady=(0, 10))
            self.current_x += self.entry_width + 10  # 间距为10像素
            if self.current_x > self.center_frame.winfo_width() - self.entry_width:
                self.current_x = 10  # 重置X位置
                self.current_y += self.entry_height + 10  # 更新Y位置
            self.entries_layout.append(entry)
            self.target_regions.append((new_region, specific_threshold))
            self.canvas_left.delete(self.selection_tag)
            self.canvas_left.create_rectangle(
                new_region[0], new_region[1],
                new_region[0] + new_region[2], new_region[1] + new_region[3],
                outline="blue", tags="selection_rect"
            )
            self.log("目标区域选定")

    def detect_edges(self, frame, region, threshold=None):
        # 截取目标区域
        target_region = frame[
            region[1]:region[1] + region[3],
            region[0]:region[0] + region[2]
        ]
        # 将图像转换为灰度图像
        gray = cv2.cvtColor(target_region, cv2.COLOR_RGB2GRAY)
        # 使用Canny算法检测边缘
        low_threshold = int(threshold.get()) if threshold else 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, region, index):
        # 在实时画面上框选目标区域
        cv2.rectangle(frame, (region[0], region[1]),
                      (region[0] + region[2], region[1] + region[3]),
                      (255, 0, 0), 2)
        # 显示编号(半透明)
        cv2.putText(frame, str(index), (region[0], region[1]-10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0, 128), 2)
        # 在目标区域中心显示黄色十字线及坐标
        center_x = region[0] + region[2] // 2
        center_y = region[1] + region[3] // 2
        cv2.line(frame, (center_x - 5, center_y), (center_x + 5, center_y), (0, 255, 255), 2)
        cv2.line(frame, (center_x, center_y - 5), (center_x, center_y + 5), (0, 255, 255), 2)
        # 显示坐标
        cv2.putText(frame, f"({center_x}, {center_y})", (region[0] + region[2] - 60, region[1] - 10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 255), 1)
        # 在目标区域内绘制边缘
        edges_array = np.array(edges_img)
        edges_array = cv2.cvtColor(edges_array, cv2.COLOR_GRAY2RGB)
        frame[region[1]:region[1] + region[3],
              region[0]:region[0] + 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 delete_selected_region(self):
        if self.target_regions:
            self.canvas_left.delete("selection_rect")
            for entry in self.entries_layout:
                entry.destroy()
            self.entries_layout.clear()
            self.target_regions.clear()
            self.current_x = 10  # 重置X位置
            self.current_y = 10  # 重置Y位置
            self.log("所有选定区域已删除")

    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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值