• 人脸特征标注——OpenCV


    导入必要的库

    import tkinter as tk: 导入Tkinter库,并将其重命名为tk。
    from tkinter import filedialog: 从Tkinter中导入文件对话框功能。
    import cv2: 导入OpenCV库
    from PIL import Image, ImageTk: 从PIL库导入Image和ImageTk模块,用于处理图像。
    from tkinter import messagebox: 从Tkinter中导入消息框功能,用于显示消息提示框。
    import dlib:导入dlib库,这个库用于人脸检测和关键点标注。

    import tkinter as tk
    from tkinter import filedialog
    import cv2
    from PIL import Image, ImageTk
    from tkinter import messagebox
    import dlib
    

    创建窗口

    创建了一个Tkinter窗口实例win,设置窗口标题为"特征标注",大小为800x650像素。

    win = tk.Tk()
    win.title("特征标注")
    win.geometry("800x650")
    

    显示原始图片和标注后的图片

    创建了两个空的标签控件image_label_originalimage_label_landmarks,用于显示原始图像和带有标注的图像。

    mage_label_original = tk.Label(win)
    image_label_landmarks = tk.Label(win)
    

    存储用户选择的图片路径

    初始化一个变量selected_image_path,用于存储用户选择的图片路径。

    selected_image_path = None
    

    字体样式和大小

    定义了字体样式my_font,使用Times New Roman字体,大小为20。

    my_font = ("Times New Roman", 20)
    

    定义了select_image函数

    global selected_image_path: 声明selected_image_path为全局变量,以便在函数内部修改其值。

    selected_image_path = filedialog.askopenfilename():
    使用文件对话框让用户选择一个图像文件,并将选择的文件路径存储在selected_image_path变量中。

    if selected_image_path:: 检查是否成功选择了图像文件。

    img = cv2.imread(selected_image_path):
    使用OpenCV的imread()函数读取选择的图像文件,并将其存储在img变量中。

    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB):
    将BGR格式的图像转换为RGB格式,便于后续处理。

    img_pil = Image.fromarray(img_rgb): 将RGB格式的图像数据转换为PIL图像对象。

    img_pil = img_pil.resize((300, 300), Image.Resampling.LANCZOS):
    调整图像大小为300x300像素,使用LANCZOS插值方法保持图像质量。

    img_tk = ImageTk.PhotoImage(image=img_pil):
    将PIL图像对象转换为Tkinter图像对象,用于在GUI中显示。

    image_label_original.config(image=img_tk): 在原始图像标签控件上配置显示图像。

    image_label_original.image = img_tk: 更新原始图像标签的图像数据,确保图像正确显示在GUI中。

    def select_image():
        global selected_image_path
        selected_image_path = filedialog.askopenfilename()
    
        if selected_image_path:
            img = cv2.imread(selected_image_path)
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            img_pil = Image.fromarray(img_rgb)
            img_pil = img_pil.resize((300, 300), Image.Resampling.LANCZOS)
            img_tk = ImageTk.PhotoImage(image=img_pil)
    
            image_label_original.config(image=img_tk)
            image_label_original.image = img_tk
    

    定义了annotate_landmarks()函数

    if selected_image_path:: 检查是否已选择图像文件。

    img = cv2.imread(selected_image_path):
    使用OpenCV的imread()函数读取已选择的图像文件。

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY): 将图像转换为灰度图像,便于人脸检测。

    detector = dlib.get_frontal_face_detector(): 创建一个人脸检测器对象。

    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat"):
    创建一个人脸关键点预测器对象,加载已经训练好的68个关键点模型。

    faces = detector(gray, 1): 使用人脸检测器检测输入图像中的人脸,并将结果存储在faces中。

    if len(faces) > 0:: 检查是否检测到了人脸。

    landmarks = predictor(gray, faces[0]): 使用关键点预测器获取第一个检测到的人脸的关键点坐标。

    for n in range(0, 68):: 遍历68个人脸关键点。

    x = landmarks.part(n).x: 获取第n个关键点的x坐标。

    y = landmarks.part(n).y: 获取第n个关键点的y坐标。

    cv2.circle(img, (x, y), 1, (255, 0, 0), -1): 在图像上绘制一个圆圈表示关键点的位置。

    img_rgb_landmarks = cv2.cvtColor(img, cv2.COLOR_BGR2RGB):
    将图像从BGR颜色空间转换为RGB颜色空间,这是因为OpenCV读取图像时默认使用BGR颜色通道。

    img_pil_landmarks = Image.fromarray(img_rgb_landmarks):
    使用PIL的Image.fromarray()函数将OpenCV格式的图像转换为PIL图像对象。

    img_pil_landmarks = img_pil_landmarks.resize((300, 300), Image.Resampling.LANCZOS): 调整PIL图像的大小为(300,
    300),使用LANCZOS插值方法来保持图像质量。

    img_tk_landmarks = ImageTk.PhotoImage(image=img_pil_landmarks):
    将PIL图像转换为Tkinter GUI所需的PhotoImage对象。

    image_label_landmarks.config(image=img_tk_landmarks):
    在image_label_landmarks标签控件上配置显示标注后的图像。

    image_label_landmarks.image = img_tk_landmarks:
    更新image_label_landmarks标签控件的图像数据,确保图像正确显示在GUI中。

    messagebox.showinfo("提示", "未检测到人脸"): 如果未检测到人脸,则在弹出窗口中显示相应提示信息。

    messagebox.showinfo("提示", "请先选择一张图片"): 如果未选择图像,则在弹出窗口中显示相应提示信息。

    def annotate_landmarks():
        if selected_image_path:
            img = cv2.imread(selected_image_path)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
            detector = dlib.get_frontal_face_detector()
            predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
            faces = detector(gray, 1)
    
            if len(faces) > 0:
                landmarks = predictor(gray, faces[0])
                for n in range(0, 68):
                    x = landmarks.part(n).x
                    y = landmarks.part(n).y
                    cv2.circle(img, (x, y), 1, (255, 0, 0), -1)
    
                img_rgb_landmarks = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                img_pil_landmarks = Image.fromarray(img_rgb_landmarks)
                img_pil_landmarks = img_pil_landmarks.resize((300, 300), Image.Resampling.LANCZOS)
                img_tk_landmarks = ImageTk.PhotoImage(image=img_pil_landmarks)
                image_label_landmarks.config(image=img_tk_landmarks)
                image_label_landmarks.image = img_tk_landmarks
            else:
                messagebox.showinfo("提示", "未检测到人脸")
        else:
            messagebox.showinfo("提示", "请先选择一张图片")
    

    设置按钮

    button_select = tk.Button(win, text="选择图片", font=my_font, command=select_image, fg='black')
    创建一个名为button_select的按钮,显示文本为"选择图片",应用自定义字体my_font,点击按钮时执行select_image函数,文本颜色为黑色。

    button_detect = tk.Button(win, text="标注人脸", font=my_font, command=annotate_landmarks, fg='black')
    创建一个名为button_detect的按钮,显示文本为"标注人脸",应用自定义字体my_font,点击按钮时执行annotate_landmarks函数,文本颜色为黑色。

    button_select = tk.Button(win, text="选择图片", font=my_font, command=select_image, fg='black')
    button_detect = tk.Button(win, text="标注人脸", font=my_font, command=annotate_landmarks, fg='black')
    

    调整图片标签的位置

    button_height = 40 : 定义一个名为button_height的变量,值为40,表示按钮的高度为40像素。

    button_select.place(x=150, y=50)
    :将button_select按钮放置在窗口中x坐标为150像素,y坐标为50像素的位置。

    button_detect.place(x=450, y=50)
    将button_detect按钮放置在窗口中x坐标为450像素,y坐标为50像素的位置。

    # 计算按钮的高度,并据此调整图片标签的位置
    button_height = 40  # 假设按钮的高度为40像素
    button_select.place(x=150, y=50)
    button_detect.place(x=450, y=50)
    

    设置图片位置

    image_label_original.place(x=50, y=100)
    将原始图片标签image_label_original放置在窗口中x坐标为50像素,y坐标为100像素的位置。

    image_label_landmarks.place(x=420, y=100)
    将人脸标记图片标签image_label_landmarks放置在窗口中x坐标为420像素,y坐标为100像素的位置。

    # 将图片标签放置在按钮下方
    image_label_original.place(x=50, y=100)
    image_label_landmarks.place(x=420, y=100)
    

    主事件循环

    win.mainloop() :进入主事件循环,显示窗口并等待用户操作。

    win.mainloop()
    

    运行显示:

    在这里插入图片描述

    全部代码

    import tkinter as tk
    from tkinter import filedialog
    import cv2
    from PIL import Image, ImageTk
    from tkinter import messagebox
    import dlib
    
    win = tk.Tk()
    win.title("特征标注")
    win.geometry("800x650")
    
    image_label_original = tk.Label(win)
    image_label_landmarks = tk.Label(win)
    
    selected_image_path = None
    
    my_font = ("Times New Roman", 20)
    
    def select_image():
        global selected_image_path
        selected_image_path = filedialog.askopenfilename()
    
        if selected_image_path:
            img = cv2.imread(selected_image_path)
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            img_pil = Image.fromarray(img_rgb)
            img_pil = img_pil.resize((300, 300), Image.Resampling.LANCZOS)
            img_tk = ImageTk.PhotoImage(image=img_pil)
    
            image_label_original.config(image=img_tk)
            image_label_original.image = img_tk
    
    def annotate_landmarks():
        if selected_image_path:
            img = cv2.imread(selected_image_path)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
            detector = dlib.get_frontal_face_detector()
            predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
            faces = detector(gray, 1)
    
            if len(faces) > 0:
                landmarks = predictor(gray, faces[0])
                for n in range(0, 68):
                    x = landmarks.part(n).x
                    y = landmarks.part(n).y
                    cv2.circle(img, (x, y), 1, (255, 0, 0), -1)
    
                img_rgb_landmarks = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                img_pil_landmarks = Image.fromarray(img_rgb_landmarks)
                img_pil_landmarks = img_pil_landmarks.resize((300, 300), Image.Resampling.LANCZOS)
                img_tk_landmarks = ImageTk.PhotoImage(image=img_pil_landmarks)
                image_label_landmarks.config(image=img_tk_landmarks)
                image_label_landmarks.image = img_tk_landmarks
            else:
                messagebox.showinfo("提示", "未检测到人脸")
        else:
            messagebox.showinfo("提示", "请先选择一张图片")
    
    button_select = tk.Button(win, text="选择图片", font=my_font, command=select_image, fg='black')
    button_detect = tk.Button(win, text="标注人脸", font=my_font, command=annotate_landmarks, fg='black')
    
    # 计算按钮的高度,并据此调整图片标签的位置
    button_height = 40  # 假设按钮的高度为40像素
    button_select.place(x=150, y=50)
    button_detect.place(x=450, y=50)
    
    # 将图片标签放置在按钮下方
    image_label_original.place(x=50, y=100)
    image_label_landmarks.place(x=420, y=100)
    
    win.mainloop()
    
    
  • 相关阅读:
    react-router-dom v6的几个方法
    5.2Unix/Linux上的五种IO模型
    Qt元对象系统 day5
    cmake学习笔记 二
    《uni-app》表单组件-Button按钮
    力扣二分查找:第一个错误的版本
    flask中的操作数据库的插件Flask-SQLAlchemy
    Linux多线程篇【5】——线程池
    Rainbond的 Gateway API 插件制作实践
    MSF派生给另外MSF,meterpreter派生给另外meterpreter,Metasploit
  • 原文地址:https://blog.csdn.net/2301_76794217/article/details/139781780