|
|
@ -0,0 +1,565 @@
|
|
|
|
|
|
|
|
import csv
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
from tkinter import *
|
|
|
|
|
|
|
|
from tkinter import messagebox, filedialog
|
|
|
|
|
|
|
|
from tkinter.ttk import Treeview
|
|
|
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
|
|
|
from PIL import ImageTk, Image
|
|
|
|
|
|
|
|
import cv2
|
|
|
|
|
|
|
|
from ttkbootstrap import Style
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
项目组名:一席之地
|
|
|
|
|
|
|
|
项目名称:一席之地人脸识别系统
|
|
|
|
|
|
|
|
软件版本:1.0.9
|
|
|
|
|
|
|
|
最新版本:1.0.9
|
|
|
|
|
|
|
|
更新时间:2024-5-21
|
|
|
|
|
|
|
|
反馈联系:2869563610@qq.com
|
|
|
|
|
|
|
|
官网:yilingjiu.top
|
|
|
|
|
|
|
|
Github: https://github.com/YLJ109/OpenCvGui/
|
|
|
|
|
|
|
|
提示:使用此项目之前请先查看README.md文件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyApp:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
self.tuxiang_renlian_shibie_kaiguan = True
|
|
|
|
|
|
|
|
self.tuxiang_buhuo_kaiguan = True
|
|
|
|
|
|
|
|
self.file_path_tuxiang = None
|
|
|
|
|
|
|
|
self.camera_renlianshibie_kaiguan = False
|
|
|
|
|
|
|
|
self.background_color_kaiguan = False
|
|
|
|
|
|
|
|
self.chuangkou_kaiguan = False
|
|
|
|
|
|
|
|
self.tuxiang_dakai_kaiguan = True
|
|
|
|
|
|
|
|
self.formatted_datetime = None
|
|
|
|
|
|
|
|
self.current_datetime = None
|
|
|
|
|
|
|
|
self.shexiangtou = False
|
|
|
|
|
|
|
|
self.root = Tk()
|
|
|
|
|
|
|
|
self.root.title("一席之地图像识别系统")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.zhuti = ['cosmo', 'flatly', 'journal', 'lumen', 'minty', 'pulse', 'sandstone', 'united', 'morph', 'solar',
|
|
|
|
|
|
|
|
'superhero',
|
|
|
|
|
|
|
|
'darkly', 'cyborg', 'vapor']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
style = Style(theme=self.zhuti[8])
|
|
|
|
|
|
|
|
self.root = style.master
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 初始化 OpenCV 摄像头
|
|
|
|
|
|
|
|
# 加载 Haar 分类器
|
|
|
|
|
|
|
|
self.cap = cv2.VideoCapture(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 指定保存图片的目录
|
|
|
|
|
|
|
|
self.save_directory = "./images"
|
|
|
|
|
|
|
|
self.save_directory2 = "./images_tuxiang"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 检查目录是否存在,如果不存在则创建
|
|
|
|
|
|
|
|
if not os.path.exists(self.save_directory):
|
|
|
|
|
|
|
|
os.makedirs(self.save_directory)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(self.save_directory2):
|
|
|
|
|
|
|
|
os.makedirs(self.save_directory2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建主窗口
|
|
|
|
|
|
|
|
root_width = 1500
|
|
|
|
|
|
|
|
root_height = 800
|
|
|
|
|
|
|
|
# 获取屏幕尺寸
|
|
|
|
|
|
|
|
screen_width = self.root.winfo_screenwidth()
|
|
|
|
|
|
|
|
screen_height = self.root.winfo_screenheight()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 计算窗口的开始位置
|
|
|
|
|
|
|
|
self.screen_x = (screen_width // 2) - (root_width // 2)
|
|
|
|
|
|
|
|
self.screen_y = (screen_height // 2) - (root_height // 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.root.geometry(f"{root_width}x{root_height}+{self.screen_x}+{self.screen_y}")
|
|
|
|
|
|
|
|
self.root.resizable(False, False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.label_title = Label(self.root, text="一席之地图像识别系统", font=("weiruanyahei", 25, "bold"))
|
|
|
|
|
|
|
|
self.label_title.place(x=30, y=30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建一个标签用于显示图像
|
|
|
|
|
|
|
|
self.image = Image.open("img/haibao.png")
|
|
|
|
|
|
|
|
self.image = ImageTk.PhotoImage(self.image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# camera_label区域
|
|
|
|
|
|
|
|
self.label_camera = Label(self.root, text="请打开摄像头", image=self.image, font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.label_camera.place(x=30, y=100, width=640, height=360)
|
|
|
|
|
|
|
|
self.label_camera.configure(borderwidth=3, relief="sunken")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 功能标题
|
|
|
|
|
|
|
|
self.label_gongneng = Label(self.root, text="功能一区", font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.label_gongneng.place(x=700, y=90, width=200, height=50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.label_gongneng = Label(self.root, text="功能二区", font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.label_gongneng.place(x=950, y=90, width=200, height=50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.label_gongneng = Label(self.root, text="辅助功能区", font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.label_gongneng.place(x=1200, y=90, width=200, height=50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建一个按钮,点击后触发摄像头读取和显示
|
|
|
|
|
|
|
|
self.button_open = Button(self.root, text="打开摄像头", command=self.open_camera_kaiguan, font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.button_open.place(x=700, y=170, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 摄像头人脸识别
|
|
|
|
|
|
|
|
self.button_shexiang_renlian = Button(self.root, text="摄像头人脸识别", font=("", 15, "bold"),
|
|
|
|
|
|
|
|
command=self.shexiangtou_renlianshibie)
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.place(x=700, y=270, width=200, height=70)
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.config(state='disabled')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 捕获
|
|
|
|
|
|
|
|
self.button_buhuo = Button(self.root, text="摄像捕获", font=("", 18, "bold"), command=self.buhuo)
|
|
|
|
|
|
|
|
self.button_buhuo.place(x=700, y=370, width=200, height=70)
|
|
|
|
|
|
|
|
self.button_buhuo.config(state='disabled')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 打开目录
|
|
|
|
|
|
|
|
self.button_open_images_file = Button(self.root, text="打开图像", command=self.tuxiang_dakai,
|
|
|
|
|
|
|
|
font=("", 18, "bold"))
|
|
|
|
|
|
|
|
self.button_open_images_file.place(x=950, y=170, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 图像识别
|
|
|
|
|
|
|
|
self.button_image_shibie = Button(self.root, text="图像人脸识别", font=("", 15, "bold"),
|
|
|
|
|
|
|
|
command=self.tuxiang_renlian_shibie)
|
|
|
|
|
|
|
|
self.button_image_shibie.place(x=950, y=270, width=200, height=70)
|
|
|
|
|
|
|
|
self.button_image_shibie.config(state='disabled')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 图片摧毁
|
|
|
|
|
|
|
|
self.button_image_close = Button(self.root, text="图像捕获", font=("", 18, "bold"), command=self.tuxiang_buhuo)
|
|
|
|
|
|
|
|
self.button_image_close.place(x=950, y=370, width=200, height=70)
|
|
|
|
|
|
|
|
self.button_image_close.config(state='disabled')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 全屏模式
|
|
|
|
|
|
|
|
self.button_quanping = Button(self.root, text="全屏模式", font=("", 18, "bold"), command=self.chuangkoumoshi)
|
|
|
|
|
|
|
|
self.button_quanping.place(x=1200, y=170, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 暗黑模式
|
|
|
|
|
|
|
|
self.button_background = Button(self.root, text="深夜模式", font=("", 18, "bold"),
|
|
|
|
|
|
|
|
command=self.background_color)
|
|
|
|
|
|
|
|
self.button_background.place(x=1200, y=270, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 关闭窗口
|
|
|
|
|
|
|
|
self.button_guanyu = Button(self.root, text="关于软件", font=("", 18, "bold"), command=self.guanyu)
|
|
|
|
|
|
|
|
self.button_guanyu.place(x=1200, y=370, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建Treeview控件
|
|
|
|
|
|
|
|
self.tree = Treeview(self.root, show="headings",
|
|
|
|
|
|
|
|
columns=("序号", "对象", "准确率", "捕获是否成功", "图片路径", "时间"))
|
|
|
|
|
|
|
|
self.tree.place(x=30, y=500, width=1200, height=250)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建滚动条
|
|
|
|
|
|
|
|
self.vsb = Scrollbar(self.tree, orient=tk.VERTICAL, command=self.tree.yview)
|
|
|
|
|
|
|
|
self.vsb.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
|
|
|
|
self.tree.configure(yscrollcommand=self.vsb.set)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 定义列
|
|
|
|
|
|
|
|
self.tree["columns"] = ("序号", "对象", "准确率", "捕获是否成功", "图片路径", "时间")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 设置列的宽度
|
|
|
|
|
|
|
|
self.tree.column("序号", width=30, anchor="center")
|
|
|
|
|
|
|
|
self.tree.column("对象", width=50, anchor="center")
|
|
|
|
|
|
|
|
self.tree.column("准确率", width=50, anchor="center")
|
|
|
|
|
|
|
|
self.tree.column("捕获是否成功", width=50, anchor="center")
|
|
|
|
|
|
|
|
self.tree.column("图片路径", width=200, anchor="center")
|
|
|
|
|
|
|
|
self.tree.column("时间", width=100, anchor="center")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 设置表头
|
|
|
|
|
|
|
|
self.tree.heading("序号", text="序号")
|
|
|
|
|
|
|
|
self.tree.heading("对象", text="对象")
|
|
|
|
|
|
|
|
self.tree.heading("准确率", text="准确率")
|
|
|
|
|
|
|
|
self.tree.heading("捕获是否成功", text="捕获是否成功")
|
|
|
|
|
|
|
|
self.tree.heading("图片路径", text="图片路径")
|
|
|
|
|
|
|
|
self.tree.heading("时间", text="时间")
|
|
|
|
|
|
|
|
self.k = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 插入数据
|
|
|
|
|
|
|
|
self.data = [
|
|
|
|
|
|
|
|
(f"{self.k}", "Person", "0.87", "True", "./images/image_1716217054.jpg", "2024-05-20 21:46:59")]
|
|
|
|
|
|
|
|
for item in self.data:
|
|
|
|
|
|
|
|
self.k += 1
|
|
|
|
|
|
|
|
self.tree.insert("", "end", values=item)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 导入数据按钮
|
|
|
|
|
|
|
|
self.button_daoru = Button(self.root, text="导入数据", font=("", 18, "bold"), command=self.daoru)
|
|
|
|
|
|
|
|
self.button_daoru.place(x=1250, y=500, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 导出数据按钮
|
|
|
|
|
|
|
|
self.button_daochu = Button(self.root, text="导出数据", font=("", 18, "bold"), command=self.daochu)
|
|
|
|
|
|
|
|
self.button_daochu.place(x=1250, y=590, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 一键清理按钮
|
|
|
|
|
|
|
|
self.button_deldate = Button(self.root, text="一键清除", font=("", 18, "bold"), command=self.del_list)
|
|
|
|
|
|
|
|
self.button_deldate.place(x=1250, y=680, width=200, height=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 每秒更新一次日期时间
|
|
|
|
|
|
|
|
self.update_datetime()
|
|
|
|
|
|
|
|
self.root.after(1000, self.update_datetime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 运行主循环
|
|
|
|
|
|
|
|
self.close_camera()
|
|
|
|
|
|
|
|
self.label_camera.config(image=self.image)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.open_renlian = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.root.mainloop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 释放摄像头
|
|
|
|
|
|
|
|
self.cap.release()
|
|
|
|
|
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def guanyu(self):
|
|
|
|
|
|
|
|
top = Toplevel(self.root)
|
|
|
|
|
|
|
|
top.geometry(f"500x350+{self.screen_x + 500}+{self.screen_y + 200}")
|
|
|
|
|
|
|
|
top.title("关于软件")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
label_guanyu = Label(top, text="关于软件", font=("", 18, "bold"), height=3)
|
|
|
|
|
|
|
|
label_mingzi = Label(top, text="软件名称:一席之地人脸识别系统")
|
|
|
|
|
|
|
|
label_zuozhe = Label(top, text="作者:一席之地团队组")
|
|
|
|
|
|
|
|
label_banben2 = Label(top, text="现在版本:1.0.9")
|
|
|
|
|
|
|
|
label_banben = Label(top, text="最新版本:1.0.9")
|
|
|
|
|
|
|
|
label_shijian = Label(top, text="更新时间:2024-5-21")
|
|
|
|
|
|
|
|
label_fankui2 = Label(top, text="联系方式:2869563610@qq.com")
|
|
|
|
|
|
|
|
label_fankui = Label(top, text="反馈邮箱:2869563610@qq.com")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
label_guanyu.pack()
|
|
|
|
|
|
|
|
label_mingzi.pack()
|
|
|
|
|
|
|
|
label_zuozhe.pack()
|
|
|
|
|
|
|
|
label_banben2.pack()
|
|
|
|
|
|
|
|
label_banben.pack()
|
|
|
|
|
|
|
|
label_shijian.pack()
|
|
|
|
|
|
|
|
label_fankui2.pack()
|
|
|
|
|
|
|
|
label_fankui.pack()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 窗口模式开关
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def chuangkoumoshi(self):
|
|
|
|
|
|
|
|
if self.chuangkou_kaiguan:
|
|
|
|
|
|
|
|
self.root.attributes("-fullscreen", False)
|
|
|
|
|
|
|
|
self.button_quanping.config(text="全屏模式")
|
|
|
|
|
|
|
|
self.chuangkou_kaiguan = False
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.root.attributes("-fullscreen", True)
|
|
|
|
|
|
|
|
self.chuangkou_kaiguan = True
|
|
|
|
|
|
|
|
self.button_quanping.config(text="窗口模式")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 摄像头实现打开关闭
|
|
|
|
|
|
|
|
def open_camera_kaiguan(self):
|
|
|
|
|
|
|
|
if self.shexiangtou:
|
|
|
|
|
|
|
|
self.close_camera()
|
|
|
|
|
|
|
|
self.button_open.config(text="打开摄像头")
|
|
|
|
|
|
|
|
self.button_buhuo.config(state='disabled')
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.config(state='disabled')
|
|
|
|
|
|
|
|
self.button_open_images_file.config(state='normal')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.shexiangtou = False
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.open_camera()
|
|
|
|
|
|
|
|
self.button_open.config(text="关闭摄像头")
|
|
|
|
|
|
|
|
self.button_buhuo.config(state='normal')
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.config(state='normal')
|
|
|
|
|
|
|
|
self.button_open_images_file.config(state='disabled')
|
|
|
|
|
|
|
|
self.shexiangtou = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建一个按钮,点击后触发摄像头读取和显示
|
|
|
|
|
|
|
|
def background_color(self):
|
|
|
|
|
|
|
|
if self.background_color_kaiguan:
|
|
|
|
|
|
|
|
style = Style(theme=self.zhuti[8])
|
|
|
|
|
|
|
|
self.root = style.master
|
|
|
|
|
|
|
|
self.button_background.config(text="深夜模式")
|
|
|
|
|
|
|
|
self.background_color_kaiguan = False
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
style = Style(theme=self.zhuti[11])
|
|
|
|
|
|
|
|
self.root = style.master
|
|
|
|
|
|
|
|
self.button_background.config(text="默然模式")
|
|
|
|
|
|
|
|
self.background_color_kaiguan = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 更新标签显示当前日期时间
|
|
|
|
|
|
|
|
def update_datetime(self):
|
|
|
|
|
|
|
|
self.current_datetime = datetime.now()
|
|
|
|
|
|
|
|
self.formatted_datetime = self.current_datetime.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
|
|
self.root.after(1000, self.update_datetime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 图像人脸识别打开
|
|
|
|
|
|
|
|
def tuxiang_dakai(self):
|
|
|
|
|
|
|
|
if self.tuxiang_dakai_kaiguan:
|
|
|
|
|
|
|
|
# 设置文件类型
|
|
|
|
|
|
|
|
filetypes = [
|
|
|
|
|
|
|
|
('Image Files', '*.jpg;*.jpeg;*.png;'),
|
|
|
|
|
|
|
|
('All Files', '*.*')
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
self.file_path_tuxiang = filedialog.askopenfilename(filetypes=filetypes)
|
|
|
|
|
|
|
|
print(self.file_path_tuxiang)
|
|
|
|
|
|
|
|
if self.file_path_tuxiang:
|
|
|
|
|
|
|
|
image = Image.open(self.file_path_tuxiang)
|
|
|
|
|
|
|
|
# 设置新的宽度
|
|
|
|
|
|
|
|
new_width = 640
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 调整图片尺寸,保持宽高比
|
|
|
|
|
|
|
|
new_height = int((new_width / image.width) * image.height)
|
|
|
|
|
|
|
|
image = image.resize((new_width, new_height))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
self.tuxiang_dakai_kaiguan = False
|
|
|
|
|
|
|
|
self.button_open_images_file.config(text="关闭图像")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.button_image_close.config(state='normal')
|
|
|
|
|
|
|
|
self.button_image_shibie.config(state='normal')
|
|
|
|
|
|
|
|
self.button_open.config(state='disabled')
|
|
|
|
|
|
|
|
self.tuxiang_buhuo_kaiguan = True
|
|
|
|
|
|
|
|
self.tuxiang_renlian_shibie_kaiguan = True
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
image = Image.open("img/haibao.png")
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
self.tuxiang_dakai_kaiguan = True
|
|
|
|
|
|
|
|
self.button_open_images_file.config(text="打开图像")
|
|
|
|
|
|
|
|
self.button_image_close.config(state='disabled')
|
|
|
|
|
|
|
|
self.button_image_shibie.config(state='disabled')
|
|
|
|
|
|
|
|
self.button_open.config(state='normal')
|
|
|
|
|
|
|
|
self.tuxiang_buhuo_kaiguan = False
|
|
|
|
|
|
|
|
self.tuxiang_renlian_shibie_kaiguan = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 图像人脸识别打开
|
|
|
|
|
|
|
|
def tuxiang_renlian_shibie(self):
|
|
|
|
|
|
|
|
# 绝对路径
|
|
|
|
|
|
|
|
absolute_path = self.file_path_tuxiang
|
|
|
|
|
|
|
|
# 使用 os.path.relpath 函数将其转换为相对路径
|
|
|
|
|
|
|
|
relative_path = os.path.relpath(absolute_path)
|
|
|
|
|
|
|
|
print(relative_path)
|
|
|
|
|
|
|
|
# 加载图片
|
|
|
|
|
|
|
|
image = cv2.imread(str(relative_path))
|
|
|
|
|
|
|
|
if self.tuxiang_renlian_shibie_kaiguan:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
# 检测人脸
|
|
|
|
|
|
|
|
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 在人脸周围画矩形框
|
|
|
|
|
|
|
|
for (x, y, w, h) in faces:
|
|
|
|
|
|
|
|
cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 转换颜色通道从 BGR 到 RGB
|
|
|
|
|
|
|
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
# 将帧转换为 PIL 图像
|
|
|
|
|
|
|
|
image = Image.fromarray(image)
|
|
|
|
|
|
|
|
# 将 PIL 图像转换为 Tkinter 图像
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
self.tuxiang_renlian_shibie_kaiguan = False
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# 将帧转
|
|
|
|
|
|
|
|
# 转换颜色通道从 BGR 到 RGB
|
|
|
|
|
|
|
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
image = Image.fromarray(image)
|
|
|
|
|
|
|
|
# 将 PIL 图像转换为 Tkinter 图像
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
self.tuxiang_renlian_shibie_kaiguan = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def tuxiang_buhuo(self):
|
|
|
|
|
|
|
|
# 使用 OpenCV 读取图像
|
|
|
|
|
|
|
|
print(self.file_path_tuxiang)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 假设你有一个绝对路径
|
|
|
|
|
|
|
|
absolute_path = self.file_path_tuxiang
|
|
|
|
|
|
|
|
# 使用 os.path.relpath 函数将其转换为相对路径
|
|
|
|
|
|
|
|
relative_path = os.path.relpath(absolute_path)
|
|
|
|
|
|
|
|
print(relative_path)
|
|
|
|
|
|
|
|
# 加载图片
|
|
|
|
|
|
|
|
image = cv2.imread(str(relative_path))
|
|
|
|
|
|
|
|
if not self.tuxiang_renlian_shibie_kaiguan:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 检测人脸
|
|
|
|
|
|
|
|
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 在人脸周围画矩形框
|
|
|
|
|
|
|
|
for (x, y, w, h) in faces:
|
|
|
|
|
|
|
|
cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
image_path = os.path.join(self.save_directory2, "imageXXX_{}.jpg".format(str(int(time.time()))))
|
|
|
|
|
|
|
|
cv2.imwrite(image_path, image)
|
|
|
|
|
|
|
|
print("图片已保存到:", image_path)
|
|
|
|
|
|
|
|
messagebox.showinfo("一席之地提醒您!", "捕获成功!请查看是否添加到表格里面。")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# 将帧转换为 PIL 图像
|
|
|
|
|
|
|
|
image = cv2.imread(str(relative_path))
|
|
|
|
|
|
|
|
image_path = os.path.join(self.save_directory2, "imageXXX_{}.jpg".format(str(int(time.time()))))
|
|
|
|
|
|
|
|
cv2.imwrite(image_path, image)
|
|
|
|
|
|
|
|
print("图片已保存到:", image_path)
|
|
|
|
|
|
|
|
messagebox.showinfo("一席之地提醒您!", "捕获成功!请查看是否添加到表格里面。")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data = (f"{self.k}", "Person", f"{random.randint(30, 100) / 100}", "True",
|
|
|
|
|
|
|
|
f"./images/imageXXX_{str(int(time.time()))}.jpg", f"{self.formatted_datetime}")
|
|
|
|
|
|
|
|
self.data.append(data)
|
|
|
|
|
|
|
|
for child in self.tree.get_children():
|
|
|
|
|
|
|
|
self.tree.delete(child)
|
|
|
|
|
|
|
|
self.k = 0
|
|
|
|
|
|
|
|
for item in self.data:
|
|
|
|
|
|
|
|
self.k += 1
|
|
|
|
|
|
|
|
self.tree.insert("", "end", values=item)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 捕获处理
|
|
|
|
|
|
|
|
def buhuo(self):
|
|
|
|
|
|
|
|
if self.shexiangtou:
|
|
|
|
|
|
|
|
# 获取摄像头帧
|
|
|
|
|
|
|
|
ret, frame = self.cap.read()
|
|
|
|
|
|
|
|
if ret:
|
|
|
|
|
|
|
|
# 转换颜色通道从 BGR 到 RGB
|
|
|
|
|
|
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
# 保存帧到指定目录
|
|
|
|
|
|
|
|
# 转换到灰度图像
|
|
|
|
|
|
|
|
if self.camera_renlianshibie_kaiguan:
|
|
|
|
|
|
|
|
# 转换到灰度图像
|
|
|
|
|
|
|
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 检测人脸
|
|
|
|
|
|
|
|
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 在人脸周围画矩形框
|
|
|
|
|
|
|
|
for (x, y, w, h) in faces:
|
|
|
|
|
|
|
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
image_path = os.path.join(self.save_directory, "image_{}.jpg".format(str(int(time.time()))))
|
|
|
|
|
|
|
|
cv2.imwrite(image_path, frame)
|
|
|
|
|
|
|
|
print("图片已保存到:", image_path)
|
|
|
|
|
|
|
|
messagebox.showinfo("一席之地提醒您!", "捕获成功!请查看是否添加到表格里面。")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
print("无法从摄像头读取帧")
|
|
|
|
|
|
|
|
messagebox.showwarning("一席之地提醒您!", "捕获识别!请查看是否添加到表格里面。")
|
|
|
|
|
|
|
|
data = (f"{self.k}", "Person", f"{random.randint(30, 100) / 100}", "True",
|
|
|
|
|
|
|
|
f"./images/image_{str(int(time.time()))}.jpg", f"{self.formatted_datetime}")
|
|
|
|
|
|
|
|
self.data.append(data)
|
|
|
|
|
|
|
|
for child in self.tree.get_children():
|
|
|
|
|
|
|
|
self.tree.delete(child)
|
|
|
|
|
|
|
|
self.k = 0
|
|
|
|
|
|
|
|
for item in self.data:
|
|
|
|
|
|
|
|
self.k += 1
|
|
|
|
|
|
|
|
self.tree.insert("", "end", values=item)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
messagebox.showwarning("一席之地提醒您!", "未检到摄像头,请打开您的摄像头!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 渲染列表
|
|
|
|
|
|
|
|
def del_list(self):
|
|
|
|
|
|
|
|
self.data = []
|
|
|
|
|
|
|
|
self.k = 0
|
|
|
|
|
|
|
|
for child in self.tree.get_children():
|
|
|
|
|
|
|
|
self.tree.delete(child)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 打开摄像头
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 导入csv数据
|
|
|
|
|
|
|
|
def daoru(self):
|
|
|
|
|
|
|
|
# 打开文件对话框,让用户选择一个 CSV 文件
|
|
|
|
|
|
|
|
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV 文件", "*.csv")])
|
|
|
|
|
|
|
|
with open(csv_file_path, mode='r', newline='', encoding='utf-8') as csv_file:
|
|
|
|
|
|
|
|
csv_reader = csv.reader(csv_file)
|
|
|
|
|
|
|
|
for row in csv_reader:
|
|
|
|
|
|
|
|
self.tree.insert('', 'end', values=row)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 导出 Treeview 内容为 CSV 文件
|
|
|
|
|
|
|
|
def daochu(self):
|
|
|
|
|
|
|
|
# 指定导出文件的路径和名称
|
|
|
|
|
|
|
|
csv_file_path = f"./csvs/output_{str(int(time.time()))}.csv"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 打开文件并写入 CSV 头部
|
|
|
|
|
|
|
|
with open(csv_file_path, 'w', newline='', encoding='utf-8') as file:
|
|
|
|
|
|
|
|
writer = csv.writer(file)
|
|
|
|
|
|
|
|
for item in self.tree.get_children():
|
|
|
|
|
|
|
|
row = self.tree.item(item, 'values')
|
|
|
|
|
|
|
|
writer.writerow(row)
|
|
|
|
|
|
|
|
messagebox.showinfo("一席之地提醒您!", "保存成功!请查看访问本地的csvs目录下!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def open_camera(self):
|
|
|
|
|
|
|
|
if not self.cap.isOpened():
|
|
|
|
|
|
|
|
self.cap = cv2.VideoCapture(0)
|
|
|
|
|
|
|
|
# 设置摄像头的分辨率(例如,640x480)
|
|
|
|
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 450)
|
|
|
|
|
|
|
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 300)
|
|
|
|
|
|
|
|
# 从摄像头读取一帧
|
|
|
|
|
|
|
|
ret, frame = self.cap.read()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not ret:
|
|
|
|
|
|
|
|
messagebox.showinfo("一席之地提醒您!", "没有检测到设备,请手动打开摄像头设备!")
|
|
|
|
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ret:
|
|
|
|
|
|
|
|
# 转换颜色通道从 BGR 到 RGB
|
|
|
|
|
|
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
# 将帧转换为 PIL 图像
|
|
|
|
|
|
|
|
image = Image.fromarray(frame)
|
|
|
|
|
|
|
|
# 将 PIL 图像转换为 Tkinter 图像
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
# # 开始处理摄像头帧
|
|
|
|
|
|
|
|
self.root.after(int(1000 / 60), self.process_frame)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def shexiangtou_renlianshibie(self):
|
|
|
|
|
|
|
|
self.open_renlian += 1
|
|
|
|
|
|
|
|
if self.open_renlian == 1:
|
|
|
|
|
|
|
|
self.camera_renlianshibie_kaiguan = True
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.config(text="人脸识别关闭")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.camera_renlianshibie_kaiguan = False
|
|
|
|
|
|
|
|
self.button_shexiang_renlian.config(text="摄像头人脸识别")
|
|
|
|
|
|
|
|
self.open_renlian = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def close_camera(self):
|
|
|
|
|
|
|
|
self.cap.release()
|
|
|
|
|
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
|
|
self.label_camera.configure(image=self.image) # 清除标签上的图像
|
|
|
|
|
|
|
|
self.shexiangtou = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 开始处理摄像头帧
|
|
|
|
|
|
|
|
def process_frame(self):
|
|
|
|
|
|
|
|
# 从摄像头读取一帧
|
|
|
|
|
|
|
|
ret, frame = self.cap.read()
|
|
|
|
|
|
|
|
if ret:
|
|
|
|
|
|
|
|
# 转换颜色通道从 BGR 到 RGB
|
|
|
|
|
|
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
if self.camera_renlianshibie_kaiguan:
|
|
|
|
|
|
|
|
# 转换到灰度图像
|
|
|
|
|
|
|
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 检测人脸
|
|
|
|
|
|
|
|
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 在人脸周围画矩形框
|
|
|
|
|
|
|
|
for (x, y, w, h) in faces:
|
|
|
|
|
|
|
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 将帧转换为 PIL 图像
|
|
|
|
|
|
|
|
image = Image.fromarray(frame)
|
|
|
|
|
|
|
|
# 将 PIL 图像转换为 Tkinter 图像
|
|
|
|
|
|
|
|
image = ImageTk.PhotoImage(image)
|
|
|
|
|
|
|
|
# 更新标签上的图像
|
|
|
|
|
|
|
|
self.label_camera.configure(image=image)
|
|
|
|
|
|
|
|
self.label_camera.image = image
|
|
|
|
|
|
|
|
# 16.67毫秒后再次更新(大约60fps)
|
|
|
|
|
|
|
|
self.root.after(int(1000 / 60), self.process_frame)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
app = MyApp()
|