Tensorflow Keras 模型无法与 Tkinter GUI 一起使用

问题描述 投票:0回答:1

我创建了一个张量流面部表情识别模型和一个 tkinter gui 来实现它。 GUI 可以自行工作,但是当我尝试将模型实现到 GUI 中时,网络摄像头冻结,并且任何上传视频和图像的按钮都停止工作。我不知道我做错了什么。

这是模型和 GUI 的结合:


import tensorflow as tf
import tkinter as tk
from tkinter import filedialog
from tkinter import font
from PIL import Image, ImageTk
import cv2
import numpy as np
import urllib.request

print("OpenCV version:", cv2.__version__)
print("NumPy version:", np.__version__)

face_cascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
face_cascade_name = "haarcascade_frontalface_default.xml"
urllib.request.urlretrieve(face_cascade_url, face_cascade_name)
facec = cv2.CascadeClassifier(face_cascade_name)

print("check1")


class FacialExpressionModel:
    EMOTIONS_LIST = ["Angry", "Disgusted", "Fearful", "Happy", "Neutral", "Sad", "Surprised"]

    def __init__(self, model_file):
        self.model = tf.keras.models.load_model(model_file)
        self.model.make_predict_function()

    def predict_emotion(self, img):
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray_img, 1.3, 5)
        emotions = []

        for (x, y, w, h) in faces:
            roi = gray_img[y:y + h, x:x + w]
            roi = cv2.resize(roi, (48, 48))
            roi = np.expand_dims(roi, axis=0)
            roi = np.expand_dims(roi, axis=-1)
            preds = self.model.predict(roi)
            emotion = FacialExpressionModel.EMOTIONS_LIST[np.argmax(preds)]
            emotions.append(emotion)

        return emotions



class VideoCamera:
    def __init__(self, root):
        self.video = cv2.VideoCapture(0)
        self.root = root
        self.canvas = tk.Canvas(self.root, width=377, height=377)
        self.canvas.place(x=10, y=10)
        self.running = True
        self.canvas.pack()
        self.uploaded_image = None
        self.uploaded_video = None

        self.model = FacialExpressionModel("C:/New folder/face_emotion_net.h5")

        self.create_widgets()

        # Start updating the video feed
        self.update_video_feed()

    def create_widgets(self):
        self.instructions_button = tk.Button(self.root, text="Instructions", command=self.showInstructions)
        self.instructions_button.place(x=400, y=10, width=191, height=61)

        self.start_stop_button = tk.Button(self.root, text="Start/Stop Webcam", command=self.startStopWebcam)
        self.start_stop_button.place(x=400, y=260, width=200, height=50)

        self.upload_video_button = tk.Button(self.root, text="Upload Video", command=self.uploadVideo)
        self.upload_video_button.place(x=400, y=80, width=88, height=70)

        self.upload_image_button = tk.Button(self.root, text="Upload Image", command=self.uploadImage)
        self.upload_image_button.place(x=500, y=80, width=90, height=70)

        self.message_label = tk.Label(self.root, text="If program is to work, please turn on\n webcam feed or upload a photo/video.")
        self.message_label.place(x=390, y=160)

    def showInstructions(self):
        # Create a new Toplevel window
        instructions_window = tk.Toplevel(self.root)
        instructions_window.title("Instructions")

        # Define instructions text
        instructions_text = "How To Use This Program:\n1. This is a deep learning facial expression recogition system that detects one of 7 emotions: Angry, Disgusted, Fearful, Happy, Neutral, Sad, and Surprised. \n2. Either turn on the webcam feed or upload a photo/video.\n3. Press 'Start/Stop Webcam' to start or stop the webcam feed.\n4. Use 'Upload Video' button to upload a video file.\n5. Use 'Upload Image' button to upload an image file.\n5. Follow the facial expression recognition in the main window and have fun!"

        # Add Label widget to display instructions text
        instructions_label = tk.Label(instructions_window, text=instructions_text)
        instructions_label.pack(padx=10, pady=10, anchor="center")

    def startStopWebcam(self):
        if self.running:
            self.video.release()
            self.running = False
        else:
            self.video = cv2.VideoCapture(0)
            self.running = True

    def uploadVideo(self):
        video_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4;*.avi;*.mkv")])
        if video_path:
            self.uploaded_video = cv2.VideoCapture(video_path)
            self.video = None
            self.uploaded_image = None

    def uploadImage(self):
        image_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg;*.png;*.gif;*.jfif")])
        if image_path:
            self.uploaded_image = Image.open(image_path)
            self.video = None
            self.uploaded_video = None

    def get_frame(self):
        if self.uploaded_image is not None:
            fr = np.array(self.uploaded_image)
            fr = cv2.resize(fr, (377, 377))
        elif self.uploaded_video is not None:
            ret, fr = self.uploaded_video.read()
            if not ret:
                return np.zeros((377, 377, 3), dtype=np.uint8)
            fr = cv2.resize(fr, (377, 377))
        elif self.video is not None:
            ret, fr = self.video.read()
            if not ret:
                return np.zeros((377, 377, 3), dtype=np.uint8)
            fr = cv2.resize(fr, (377, 377))
        else:
            return np.zeros((377, 377, 3), dtype=np.uint8)

        gray_fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
        faces = facec.detectMultiScale(gray_fr, 1.3, 5)

        for (x, y, w, h) in faces:
            fc = gray_fr[y:y + h, x:x + w]
            roi = cv2.resize(fc, (48, 48))
            pred = self.model.predict_emotion(roi[np.newaxis, :, :, np.newaxis])
            emotion = FacialExpressionModel.EMOTIONS_LIST[np.argmax(pred)]

            cv2.putText(fr, emotion, (x, y), font, 1, (255, 255, 0), 2)
            cv2.rectangle(fr, (x, y), (x + w, y + h), (255, 0, 0), 2)  # Draw rectangle around detected face

        return fr

    def update_video_feed(self):
        frame = self.get_frame()
        if frame is not None:
            img = Image.fromarray(frame)
            imgtk = ImageTk.PhotoImage(image=img)
            self.canvas.imgtk = imgtk  # Keep a reference to prevent garbage collection
            self.canvas.delete("all")
            self.canvas.create_image(0, 0, anchor=tk.NW, image=imgtk)

        if self.running:
            self.root.after(10, self.update_video_feed)  # Update every 10 milliseconds
        else:
            self.video.release()


print("check2")
# Load Haarcascade XML file
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

print("check3")
# Start Tkinter main event loop
root = tk.Tk()
root.title("Facial Expression Recognition")

camera = VideoCamera(root)
root.mainloop()


这是独立的工作 GUI:

import tensorflow as tf
import tkinter as tk
from tkinter import filedialog
from tkinter import font
from PIL import Image, ImageTk
import cv2
import numpy as np
import urllib.request

print("OpenCV version:", cv2.__version__)
print("NumPy version:", np.__version__)

face_cascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
face_cascade_name = "haarcascade_frontalface_default.xml"
urllib.request.urlretrieve(face_cascade_url, face_cascade_name)
facec = cv2.CascadeClassifier(face_cascade_name)

print("check1")


class VideoCamera:
    def __init__(self, root):
        self.video = cv2.VideoCapture(0)
        self.root = root
        self.canvas = tk.Canvas(self.root, width=377, height=377)
        self.canvas.place(x=10, y=10)
        self.running = True
        self.canvas.pack()
        self.uploaded_image=None
        self.uploaded_video=None
        #self.label = label

        self.create_widgets()

        # Start updating the video feed
        self.update_video_feed()


    def create_widgets(self):
        self.instructions_button = tk.Button(self.root, text="Instructions", command=self.showInstructions)
        self.instructions_button.place(x=400, y=10, width=191, height=61)

        self.start_stop_button = tk.Button(self.root, text="Start/Stop Webcam", command=self.startStopWebcam)
        self.start_stop_button.place(x=400, y=260, width=200, height=50)

        self.upload_video_button = tk.Button(self.root, text="Upload Video", command=self.uploadVideo)
        self.upload_video_button.place(x=400, y=80, width=88, height=70)

        self.upload_image_button = tk.Button(self.root, text="Upload Image", command=self.uploadImage)
        self.upload_image_button.place(x=500, y=80, width=90, height=70)

        self.message_label = tk.Label(self.root, text="If program is to work, please turn on\n webcam feed or upload a photo/video.")
        self.message_label.place(x=390, y=160)


    def showInstructions(self):
        # Create a new Toplevel window
        instructions_window = tk.Toplevel(self.root)
        instructions_window.title("Instructions")

        # Define instructions text
        instructions_text = "How To Use This Program:\n1. This is a deep learning facial expression recogition system that detects on of 7 emotions: Anger, Disgust, Fear, Happiness, Neutral, Sadness and Surprise. \n2. Either turn on the webcam feed or upload a photo/video.\n3. Press 'Start/Stop Webcam' to start or stop the webcam feed.\n4. Use 'Upload Video' button to upload a video file.\n5. Use 'Upload Image' button to upload an image file.\n5. Follow the facial expression recognition in the main window and have fun!"

        # Add Label widget to display instructions text
        instructions_label = tk.Label(instructions_window, text=instructions_text)
        instructions_label.pack(padx=10, pady=10, anchor="center")


    def startStopWebcam(self):
        if self.running:
            self.video.release()
            self.running = False
        else:
            self.video = cv2.VideoCapture(0)
            self.running = True

    def uploadVideo(self):
        video_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4;*.avi;*.mkv")])
        if video_path:
            self.uploaded_video = cv2.VideoCapture(video_path)
            self.video = None
            self.uploaded_image = None


    def uploadImage(self):
        image_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg;*.png;*.gif;*.jfif")])
        if image_path:
            self.uploaded_image = Image.open(image_path)
            self.video = None
            self.uploaded_video = None
    
    def get_frame(self):
        if self.uploaded_image is not None:
            fr = np.array(self.uploaded_image)
            fr = cv2.resize(fr,(377,377))
            gray_fr = cv2.cvtColor(fr, cv2.COLOR_RGB2GRAY)
            faces = facec.detectMultiScale(gray_fr, 1.3, 5)
            
            for (x, y, w, h) in faces:
                cv2.rectangle(fr, (x, y), (x+w, y+h), (255, 0, 0), 2)  # Draw rectangle around detected face
            return fr if fr is not None else np.zeros((377, 377, 3), dtype=np.uint8)
            
        elif self.uploaded_video is not None:
            _, fr = self.uploaded_video.read()
            if fr is None:
                return np.zeros((377, 377, 3), dtype=np.uint8)
            fr = cv2.resize(fr,(377,377))
            gray_fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
            faces = facec.detectMultiScale(gray_fr, 1.3, 5)
            for (x, y, w, h) in faces:
                cv2.rectangle(fr, (x, y), (x+w, y+h), (255, 0, 0), 2)  # Draw rectangle around detected face
            return fr
    
        elif self.video is not None:
            _, fr = self.video.read()
            if fr is None:
                return np.zeros((480, 640, 3), dtype=np.uint8)
            gray_fr = cv2.cvtColor(fr, cv2.COLOR_BGR2GRAY)
            faces = facec.detectMultiScale(gray_fr, 1.3, 5)
            for (x, y, w, h) in faces:
                cv2.rectangle(fr, (x, y), (x+w, y+h), (255, 0, 0), 2)  # Draw rectangle around detected face
            return fr
    
        else:
            return np.zeros((480, 640, 3), dtype=np.uint8)


    
    

    def update_video_feed(self):
        frame = self.get_frame()
        if frame is not None:
            img = Image.fromarray(frame)
            imgtk = ImageTk.PhotoImage(image=img)
            self.canvas.imgtk = imgtk  # Keep a reference to prevent garbage collection
            self.canvas.delete("all")
            self.canvas.create_image(0, 0, anchor=tk.NW, image=imgtk)


        if self.running:
            self.root.after(10, self.update_video_feed)  # Update every 10 milliseconds
        else:
            self.video.release()

print("check2")
# Load Haarcascade XML file
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')


print("check3")
# Start Tkinter main event loop
root = tk.Tk()
root.title("Facial Expression Recognition")

camera = VideoCamera(root)
root.mainloop()

当相机冻结时我也会收到此错误消息:

gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.9.0) d:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function '__cdecl cv::impl::`anonymous-namespace'::CvtHelper<struct cv::impl::`anonymous namespace'::Set<3,4,-1>,struct cv::impl::A0x59191d0d::Set<1,-1,-1>,struct cv::impl::A0x59191d0d::Set<0,2,5>,4>::CvtHelper(const class cv::_InputArray &,const class cv::_OutputArray &,int)'
> Invalid number of channels in input image:
>     'VScn::contains(scn)'
> where
>     'scn' is 1

它也不会将检测框放在脸部周围

python opencv tkinter keras deep-learning
1个回答
0
投票

在一张已经处于灰度(有一个通道)的图像上调用

cv2.cvtColor()
时,我遇到了类似的问题。该函数原本需要多通道图像,但提供了单通道图像(在您提到的错误中)。

话虽这么说,如果给

predict_emotion
一个灰度图像并尝试再次转换为灰度图像,则可能会导致错误。

实施这样的检查怎么样:

if len(img.shape) == 3 and img.shape[2] == 3:
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
    gray_img = img

如果图像已经是单通道的,这将确保跳过到灰度的转换。

© www.soinside.com 2019 - 2024. All rights reserved.