FaceRecognition-GUI-APP icon indicating copy to clipboard operation
FaceRecognition-GUI-APP copied to clipboard

Problem while training the dataset

Open theoptimist76 opened this issue 4 years ago • 5 comments
trafficstars

I did some changes with the code too, but not the functional part but the training of datasets output the error as:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\{name}\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "d:\{path}\system.py", line 198, in trainmodel
    train_classifer(self.controller.active_name)
  File "d:\{path}\create_classifier.py", line 11, in train_classifer
    path = os.path.abspath.join(os.getcwd() + "/data/" + name + "/")
AttributeError: 'function' object has no attribute 'join'

theoptimist76 avatar Sep 23 '21 17:09 theoptimist76

I did some changes with the code too, but not the functional part but the training of datasets output the error as:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\{name}\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "d:\{path}\system.py", line 198, in trainmodel
    train_classifer(self.controller.active_name)
  File "d:\{path}\create_classifier.py", line 11, in train_classifer
    path = os.path.abspath.join(os.getcwd() + "/data/" + name + "/")
AttributeError: 'function' object has no attribute 'join'

try

os.path.abspath(".").join("/data/" + name + "/")

phudinhtruongk18 avatar Sep 24 '21 05:09 phudinhtruongk18

Could you address this issue too ?

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\{name}\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "d:\{path}\system.py", line 198, in trainmodel
    train_classifer(self.controller.active_name)
  File "d:\{path}\create_classifier.py", line 37, in train_classifer
    clf.train(faces, ids)
cv2.error: OpenCV(4.5.2) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-sgoydvi3\opencv_contrib\modules\face\src\lbph_faces.cpp:362: error:
(-210:Unsupported format or combination of formats) Empty training data was given. You'll need more than one sample to learn a model. 
in function 'cv::face::LBPH::train

theoptimist76 avatar Sep 24 '21 17:09 theoptimist76

Could you address this issue too ?

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\{name}\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "d:\{path}\system.py", line 198, in trainmodel
    train_classifer(self.controller.active_name)
  File "d:\{path}\create_classifier.py", line 37, in train_classifer
    clf.train(faces, ids)
cv2.error: OpenCV(4.5.2) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-sgoydvi3\opencv_contrib\modules\face\src\lbph_faces.cpp:362: error:
(-210:Unsupported format or combination of formats) Empty training data was given. You'll need more than one sample to learn a model. 
in function 'cv::face::LBPH::train

Make sure that after you add a user, a repo created in the data folder with the username.

=> the issue here coming from the script can't find any data to train the model, so the app it's not capturing any data

also when you are in the phase of capturing the data, make sure that the app is detecting the face and its counting how many data captured so far.

joeVenner avatar Sep 25 '21 21:09 joeVenner

I am sure that after I add a user, a repo is created in the data folder with the username. The question is : When I am in the phase of capturing data how can I make sure that the app is detecting the face and its counting how many data are captured so far?

Files:

system.py =>

from Detector import main_app
from create_classifier import train_classifer
from create_dataset import start_capture
import tkinter as tk
from tkinter import  font as tkf
from tkinter import messagebox, PhotoImage

names = set()

 Full UI WorkPage

class MainUI(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        global names
        with open("Detected Names/nameslist.txt", "r") as f:
            x = f.read()
            z = x.rstrip().split(" ")
            for i in z:
                names.add(i)
        self.title_font = tkf.Font(family='Helvetica', size=19, weight="bold")
        self.title("Face Recognition by 6th Sem")
        self.resizable(False, False)
        self.geometry("700x360")
        self.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.active_name = None
        container = tk.Frame(self)
        container.grid(sticky="")
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}
        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame("StartPage")

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

    def on_closing(self):

        # if messagebox.askokcancel("Quit", "Are you sure?"):
        #     global names
        #     f = open("nameslist.txt", "a+")
        #     for i in names:
        #         f.write(i + " ")
        self.destroy()


 Making first page UI

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        render = PhotoImage(file='files/homepagepic.png')
        img = tk.Label(self, image=render)
        img.image = render
        img.grid(row=1, column=0, rowspan=2, sticky="nsew")
        render1 = PhotoImage(file='files/cosmos.png')
        img1 = tk.Label(self, image=render1)
        img1.image = render1
        img1.grid(row=1, column=1, rowspan=2, sticky="nsew")
        render2 = PhotoImage(file='files/homepagepic.png')
        img2 = tk.Label(self, image=render2)
        img2.image = render2
        img2.grid(row=1, column=2, rowspan=2, sticky="nsew")
        label1 = tk.Label(self, text="Face Recognition System", font=self.controller.title_font, fg="#263942")
        label1.grid(row=0, columnspan=6, sticky="ew")
        # line1= Canvas.create_line(15, 25, 200, 25)
        button1 = tk.Button(self, text="Register a new User", fg="#ffffff", bg="#263942",
                            command=lambda: self.controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Check existing User", fg="#ffffff", bg="#263942",
                            command=lambda: self.controller.show_frame("PageTwo"))
        button3 = tk.Button(self, text="        Quit       ", fg="#ffffff", bg="red", command=self.on_closing)
        button1.grid(row=5, column=0, ipady=3, ipadx=7)
        button2.grid(row=5, column=1, ipady=3, ipadx=7)
        button3.grid(row=5, column=2, ipady=3, ipadx=32)

    def on_closing(self):
        # if messagebox.askokcancel("Quit", "Are you sure?"):
        #     global names
        #     with open("nameslist.txt", "w") as f:
        #         for i in names:
        #             f.write(i + " ")
        self.controller.destroy()


 Making register page of user

class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label1 = tk.Label(self, text="Face Recognition System", font=self.controller.title_font, fg="#263942")
        label1.grid(row=0, columnspan=8,sticky="ew", padx=50, ipadx=100)
        render1 = PhotoImage(file='files/cosmos.png')
        img1 = tk.Label(self, image=render1)
        img1.image = render1
        img1.grid(row=1, column=4, rowspan=2, columnspan=2, sticky="nsew")
        tk.Label(self, text="Enter the name", fg="#263942", font='Helvetica 13 bold').grid(row=5, column=4, pady=10,
                                                                                           padx=5)
        self.user_name = tk.Entry(self, borderwidth=2, bg="lightgrey", font='Helvetica 12')
        self.user_name.grid(row=5, column=5, pady=10, padx=10)
        self.buttoncanc = tk.Button(self, text="    Cancel     ", bg="red", fg="#ffffff",
                                    command=lambda: controller.show_frame("StartPage"))
        self.buttonext = tk.Button(self, text="      Next       ", fg="#ffffff", bg="#263942", command=self.start_training)
        self.buttoncanc.grid(row=6, column=4, pady=10, ipadx=5, ipady=4)
        self.buttonext.grid(row=6, column=5, pady=10, ipadx=5, ipady=4, sticky="e")

    def start_training(self):
        global names
        if self.user_name.get() == "None":
            messagebox.showerror("Error", "Name cannot be 'None'")
            return
        elif self.user_name.get() in names:
            messagebox.showerror("Error", "User already exists!")
            return
        elif len(self.user_name.get()) == 0:
            messagebox.showerror("Error", "Name cannot be empty!")
            return
        name = self.user_name.get()
        names.add(name)
        self.controller.active_name = name
        self.controller.frames["PageTwo"].refresh_names()
        self.controller.show_frame("PageThree")


 Making face detection page

class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        global names
        self.controller = controller
        tk.Label(self, text="Select user", fg="#263942", font='Helvetica 12 bold').grid(row=0, column=0, padx=10,
                                                                                        pady=10)
        self.buttoncanc = tk.Button(self, text="Cancel", command=lambda: controller.show_frame("StartPage"),
                                    bg="#ffffff", fg="#263942")
        self.menuvar = tk.StringVar(self)
        self.dropdown = tk.OptionMenu(self, self.menuvar, *names)
        self.dropdown.config(bg="lightgrey")
        self.dropdown["menu"].config(bg="lightgrey")
        self.buttonext = tk.Button(self, text="Next", command=self.nextfoo, fg="#ffffff", bg="#263942")
        self.dropdown.grid(row=0, column=1, ipadx=8, padx=10, pady=10)
        self.buttoncanc.grid(row=1, ipadx=5, ipady=4, column=0, pady=10)
        self.buttonext.grid(row=1, ipadx=5, ipady=4, column=1, pady=10)

    def nextfoo(self):
        if self.menuvar.get() == "None":
            messagebox.showerror("ERROR", "Name cannot be 'None'")
            return
        self.controller.active_name = self.menuvar.get()
        self.controller.show_frame("PageFour")

    def refresh_names(self):
        global names
        self.menuvar.set('')
        self.dropdown['menu'].delete(0, 'end')
        for name in names:
            self.dropdown['menu'].add_command(label=name, command=tk._setit(self.menuvar, name))


 Image capturing and testing

class PageThree(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.numimglabel = tk.Label(self, text="Number of images captured = 0", font='Helvetica 12 bold', fg="#263942")
        self.numimglabel.grid(row=0, column=0, columnspan=2, sticky="ew", pady=10)
        self.capturebutton = tk.Button(self, text="Capture Data Set", fg="#ffffff", bg="#263942", command=self.capimg)
        self.trainbutton = tk.Button(self, text="Train The Model", fg="#ffffff", bg="#263942", command=self.trainmodel)
        self.buttoncanc = tk.Button(self, text="     Back     ", bg="red", fg="#ffffff",
                                    command=lambda: controller.show_frame("StartPage"))
        self.capturebutton.grid(row=1, column=0, ipadx=5, ipady=4, padx=10, pady=20)
        self.trainbutton.grid(row=1, column=1, ipadx=5, ipady=4, padx=10, pady=20)
        self.buttoncanc.grid(row=2, ipadx=5, ipady=4, column=0, pady=10)

    def capimg(self):
        self.numimglabel.config(text=str("Captured Images = 0 "))
        messagebox.showinfo("INSTRUCTIONS", "We will Capture 100 pic of your Face.")
        x = start_capture(self.controller.active_name)
        self.controller.num_of_images = x
        self.numimglabel.config(text=str("Number of images captured = " + str(x)))

    def trainmodel(self):
        if self.controller.num_of_images < 100:
            messagebox.showerror("ERROR", "No enough Data, Capture at least 100 images!")
            return
        train_classifer(self.controller.active_name)
        messagebox.showinfo("SUCCESS", "The model has been successfully trained!")
        self.controller.show_frame("PageFour")


 Initializing webcam 

class PageFour(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="Face Recognition", font='Helvetica 16 bold')
        label.grid(row=0, column=0, sticky="ew")
        button1 = tk.Button(self, text="Recognize Face", command=self.openwebcam, fg="#ffffff", bg="#263942")
        button4 = tk.Button(self, text="Go to Home Page", command=lambda: self.controller.show_frame("StartPage"),
                            bg="#ffffff", fg="#263942")
        buttoncanc = tk.Button(self, text="Back", bg="red", fg="#ffffff",
                               command=lambda: controller.show_frame("PageTwo"))
        button1.grid(row=1, column=0, sticky="ew", ipadx=5, ipady=4, padx=10, pady=10)
        button4.grid(row=1, column=1, sticky="ew", ipadx=5, ipady=4, padx=10, pady=10)
        buttoncanc.grid(row=1, column=2, sticky="ew", ipadx=5, ipady=4, padx=10, pady=10)

    def openwebcam(self):
        main_app(self.controller.active_name)


app = MainUI()
app.iconphoto(True, tk.PhotoImage(file='files/icon.ico'))
app.mainloop()

create_classifier.py

import cv2
import os
import numpy as np
from PIL import Image


 Method to train custom classifier to recognize face

def train_classifer(name):
    # Read all the images in custom data-set
    path = os.path.abspath(".").join("/data/" + name + "/")

    faces = []
    ids = []
    pictures = {}

  Store images in a numpy format and ids of the user on the same index in imageNp and id lists

    for files in os.walk(path):
        pictures = files

    for pic in pictures:
        imgpath = path + pic
        img = Image.open(imgpath).convert('L')
        imageNp = np.array(img, 'uint8')
        id = int(pic.split(name)[0])
        # names[name].append(id)
        faces.append(imageNp)
        ids.append(id)

    ids = np.array(ids)

    Train and save classifier

    clf = cv2.face.LBPHFaceRecognizer_create()
    clf.train(faces, ids)
    clf.write("./data/classifiers/" + name + "_classifier.xml")

create_dataset.py

import cv2
import os


def start_capture(name):
    path = "./data/" + name
    num_of_images = 0
    detector = cv2.CascadeClassifier(
        "./data/haarcascade_frontalface_default.xml")
    try:
        os.makedirs(path)
    except:
        print('Directory Already Created')

    # vid = cv2.VideoCapture(0)
    vid = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    while True:

        ret, img = vid.read()
        new_img = None
        grayimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        face = detector.detectMultiScale(
            image=grayimg, scaleFactor=1.1, minNeighbors=5)
        for x, y, w, h in face:
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 0), 2)
            cv2.putText(img, "Face Detected", (x, y - 5),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255))
            cv2.putText(img, str(str(num_of_images) + " images captured"), (x, y + h + 20), cv2.FONT_HERSHEY_SIMPLEX,
                        0.8, (0, 0, 255))
            new_img = img[y:y + h, x:x + w]
        cv2.imshow("FaceDetection", img)
        key = cv2.waitKey(1) & 0xFF

        try:
            cv2.imwrite(str(path + "/" + name + '_' +
                        str(num_of_images) + ".jpg"), new_img)
            num_of_images += 1
        except:
            pass
        if key == ord("q") or key == 27 or num_of_images == 100:
            break
    cv2.destroyAllWindows()
    return num_of_images

detector.py

import cv2
from time import sleep
from PIL import Image


def main_app(name):
    face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_default.xml')
    recognizer = cv2.face.LBPHFaceRecognizer_create()
    recognizer.read(f"./data/classifiers/{name}_classifier.xml")
    cap = cv2.VideoCapture(0)
    pred = 0
    while True:
        ret, frame = cap.read()
        # default_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)

        for (x, y, w, h) in faces:

            roi_gray = gray[y:y + h, x:x + w]

            id, confidence = recognizer.predict(roi_gray)
            confidence = 100 - int(confidence)
            pred = 0
            if confidence > 50:
                # if u want to print confidence level
                confidence = 100 - int(confidence)
                pred += +1
                text = name.upper()
                font = cv2.FONT_HERSHEY_PLAIN
                frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
                frame = cv2.putText(frame, text, (x, y - 4), font, 1, (0, 255, 0), 1, cv2.LINE_AA)

            else:
                pred += -1
                text = "UnknownFace"
                font = cv2.FONT_HERSHEY_PLAIN
                frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
                frame = cv2.putText(frame, text, (x, y - 4), font, 1, (0, 0, 255), 1, cv2.LINE_AA)

        cv2.imshow("image", frame)

        if cv2.waitKey(20) & 0xFF == ord('q'):
            print(pred)
            if pred > 0:
                dim = (124, 124)
                img = cv2.imread(f".\\data\\{name}\\{pred}{name}.jpg", cv2.IMREAD_UNCHANGED)
                resized = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
                cv2.imwrite(f".\\data\\{name}\\50{name}.jpg", resized)
                Image1 = Image.open(f".\\files\\2.png")

                # make a copy the image so that the
                # original image does not get affected
                Image1copy = Image1.copy()
                Image2 = Image.open(f".\\data\\{name}\\50{name}.jpg")
                Image2copy = Image2.copy()

                # paste image giving dimensions
                Image1copy.paste(Image2copy, (195, 114))

                # save the image
                Image1copy.save("end.png")
                frame = cv2.imread("end.png", 1)

                cv2.imshow("Result", frame)
                cv2.waitKey(5000)
            break

    cap.release()
    cv2.destroyAllWindows()

theoptimist76 avatar Sep 27 '21 13:09 theoptimist76

easy thing, only by looking if there is any blue square around the face as you will find below, and as soon as the app detects the face it will add a counter below the square to count how many captured data.

image

joeVenner avatar Sep 28 '21 20:09 joeVenner