Open theoptimist76 opened 2 years ago
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 + "/")
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
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.
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?
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()
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.
I did some changes with the code too, but not the functional part but the training of datasets output the error as: