Обнаружение лиц на Python с использованием OpenCV и MySQL
Я пишу программу для распознавания лиц, где данные берутся из MySQL, и сделал её с использованием pymysql, но знания pymysql и OpenCV 3.0+ хромают. Я подгонял под нужную мне СУБД и версию OpenCV коды с этого сайта: https://dev.to/pranay749254/simple-face-recognizing-system-using-python-and-opencv
Причём, первые два благополучно создали фотки и yml-образ, но на этапе распознавания начались проблемы с выводом данных на экран: программа чуть-чуть подвигалась, а потом зависла и выдала ошибки, связанные с putText и индексами строки profile. Сначала попробовал ключи, соответствующие названиям столбцов, на что компилятор "сказал", что нужны значения числового, а не кортежного типа, потом попробовал индексы с цифрами, как в примерах, но появилась ошибка, причину которой я не знаю. Как правильно из БД извлечь строки и разбить их по нужным ключам, а потом передать их в putText?
insert_or_update.py
import cv2
import numpy as np
import pymysql
from pymysql.cursors import DictCursor
faceDetect = cv2.CascadeClassifier('haarcascade_frontalface_default.xml');
cam = cv2.VideoCapture(0);
def insertOrUpdate(Id, Name, Age, Gen, CR):
conn = pymysql.connect(host='localhost', user='root', password='', db='facebase', charset='utf8mb4', cursorclass=DictCursor)
with conn.cursor() as cursor:
cmd = "SELECT * FROM people WHERE ID=%s"
cursor.execute(cmd, Id)
count_row = cursor.rowcount
if (count_row > 0):
with conn.cursor() as cursor:
cmd = "UPDATE people SET Name=%s, Age=%s, Gender=%s, CR=%s WHERE ID=%s"
cursor.execute(cmd, (Name, Age, Gen, CR, Id))
conn.commit()
else:
with conn.cursor() as cursor:
cmd = "INSERT INTO people(ID, Name, Age, Gender, CR) Values(%s, %s, %s, %s, %s)"
cursor.execute(cmd, (Id, Name, Age, Gen, CR))
conn.commit()
conn.close()
Id = input('Enter User Id')
name = input('Enter User Name')
age = input('Enter User Age')
gen = input('Enter User Gender')
cr = input('Enter User Criminal Records')
insertOrUpdate(Id, name, age, gen, cr)
sampleNum = 0
while(True):
ret, img = cam.read();
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceDetect.detectMultiScale(gray, 1.3, 5);
for(x, y, w, h) in faces:
sampleNum = sampleNum + 1;
cv2.imwrite("dataSet/User." + str(Id) + "." + str(sampleNum) + ".jpg", gray[y:y+h, x:x+w])
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.waitKey(100);
cv2.imshow("Face", img);
cv2.waitKey(1);
if(sampleNum > 20):
break;
cam.release()
cv2.destroyAllWindows()
training.py
import os
import cv2
import numpy as np
from PIL import Image
recognizer = cv2.face.LBPHFaceRecognizer_create();
path = 'dataSet'
def getImagesWithID(path):
imagepaths = [os.path.join(path, f) for f in os.listdir(path)]
faces=[]
IDs=[]
for imagepath in imagepaths:
faceImg = Image.open(imagepath).convert('L');
faceNp = np.array(faceImg, 'uint8')
ID = int(os.path.split(imagepath)[-1].split('.')[1])
faces.append(faceNp)
IDs.append(ID)
cv2.imshow("training", faceNp)
cv2.waitKey(10)
return np.array(IDs), faces
IDs, faces = getImagesWithID(path)
recognizer.train(faces, IDs)
recognizer.write('recognizer/trainningData.yml')
cv2.destroyAllWindows()
recognition.py
import cv2
import numpy as np
import os
import pymysql
from pymysql.cursors import DictCursor
faceDetect = cv2.CascadeClassifier('haarcascade_frontalface_default.xml');
cam = cv2.VideoCapture(0);
rec = cv2.face.LBPHFaceRecognizer_create();
rec.read("recognizer/trainningData.yml")
font = cv2.FONT_HERSHEY_SIMPLEX
def getProfile(id):
conn = pymysql.connect(host='localhost', user='root', password='', db='facebase', charset='utf8mb4', cursorclass=DictCursor)
with conn.cursor() as cursor:
cmd = "SELECT * FROM people WHERE ID=%s"
cursor.execute(cmd, id)
rows = cursor.fetchall()
profile = None
for row in rows:
profile = row
conn.close()
return profile
while(True):
ret, img = cam.read();
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceDetect.detectMultiScale(gray, 1.3, 5);
for(x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
id, conf = rec.predict(gray[y:y+h, x:x+w])
profile = getProfile(id)
if(profile != None):
cv2.putText(img, "Name : " + str(profile[1]), (x, y+h+20), font, (0, 255, 0), 2);
cv2.putText(img, "Age : " + str(profile[2]), (x, y+h+45), font, (0, 255, 0), 2);
cv2.putText(img, "Gender : " + str(profile[3]), (x, y+h+70), font, (0, 255, 0), 2);
cv2.putText(img, "Criminal Records : " + str(profile[4]), (x, y+h+95), font, (0, 0, 255), 2);
cv2.imshow("Face", img);
if(cv2.waitKey(1)==ord('q')):
break;
cam.release()
cv2.destroyAllWindows()
Ошибки:
D:\Python\python.exe C:/face_detection_mysql/recognition.py
Traceback (most recent call last):
File "C:/face_detection_mysql/recognition.py", line 34, in <module>
cv2.putText(img, "Name : " + str(profile[1]), (x, y+h+20), font, (0, 255, 0), 2);
KeyError: 1
[ WARN:0] global C:\projects\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (674) SourceReaderCB::~SourceReaderCB terminating async callback
Process finished with exit code -805306369 (0xCFFFFFFF)
Просто вывести строку могу, а присвоить profile, вернуть из функции и поместить в putText - нет, так как нужен тип действительных чисел вместо кортежа.
test_output.py
import cv2
import numpy as np
import os
import pymysql
def getProfile(id):
conn = pymysql.connect(host='localhost', user='root', password='', db='facebase', charset='utf8mb4')
with conn.cursor() as cursor:
cmd = "SELECT * FROM people WHERE ID=%s"
cursor.execute(cmd, id)
for row in cursor:
print(row)
conn.close()
getProfile(1)
Результат:
D:\Python\python.exe C:/face_detection_mysql/test_output.py
(1, 'Vladimir', 23, 'M', 'None')
Process finished with exit code 0
recognition.py
import cv2
import numpy as np
import os
import pymysql
faceDetect = cv2.CascadeClassifier('haarcascade_frontalface_default.xml');
cam = cv2.VideoCapture(0);
rec = cv2.face.LBPHFaceRecognizer_create();
rec.read("recognizer/trainningData.yml")
font = cv2.FONT_HERSHEY_SIMPLEX
def getProfile(id):
conn = pymysql.connect(host='localhost', user='root', password='', db='facebase', charset='utf8mb4')
with conn.cursor() as cursor:
cmd = "SELECT * FROM people WHERE ID=%s"
cursor.execute(cmd, id)
profile = None
for row in cursor:
profile = row
conn.close()
return profile
while(True):
ret, img = cam.read();
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceDetect.detectMultiScale(gray, 1.3, 5);
for(x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
id, conf = rec.predict(gray[y:y+h, x:x+w])
profile = getProfile(id)
if(profile != None):
cv2.putText(img, "Name : " + str(profile[1]), (x, y+h+20), font, (0, 255, 0), 2);
cv2.putText(img, "Age : " + str(profile[2]), (x, y+h+45), font, (0, 255, 0), 2);
cv2.putText(img, "Gender : " + str(profile[3]), (x, y+h+70), font, (0, 255, 0), 2);
cv2.putText(img, "Criminal Records : " + str(profile[4]), (x, y+h+95), font, (0, 0, 255), 2);
cv2.imshow("Face", img);
if(cv2.waitKey(1)==ord('q')):
break;
cam.release()
cv2.destroyAllWindows()
Результат:
D:\Python\python.exe C:/face_detection_mysql/recognition.py
Traceback (most recent call last):
File "C:/face_detection_mysql/recognition.py", line 32, in <module>
cv2.putText(img, "Name : " + str(profile[1]), (x, y+h+20), font, (0, 255, 0), 2);
TypeError: must be real number, not tuple
[ WARN:0] global C:\projects\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (674) SourceReaderCB::~SourceReaderCB terminating async callback
Process finished with exit code -805306369 (0xCFFFFFFF)
Как вернуть массив строк, если в видеопотоке будет несколько лиц? Также я путаюсь в этих индексах - почему к элементам массива profile нельзя обратиться по названиям столбцов?
Попробовал раскидать значения ключей строки по разным переменным с помощью fetchone - та же проблема: просто вывести могу, а загнать в putText - нет по той же самой причине. Даже явное преобразование в строку посредством str() не помогло.
recognition.py
import cv2
import numpy as np
import os
import pymysql
faceDetect = cv2.CascadeClassifier('haarcascade_frontalface_default.xml');
cam = cv2.VideoCapture(0);
rec = cv2.face.LBPHFaceRecognizer_create();
rec.read("recognizer/trainningData.yml")
font = cv2.FONT_HERSHEY_SIMPLEX
def getProfile(id):
conn = pymysql.connect(host='localhost', user='root', password='', db='facebase', charset='utf8mb4')
name = None
age = None
gen = None
cr = None
with conn.cursor() as cursor:
cmd = "SELECT * FROM people WHERE ID=%s"
cursor.execute(cmd, id)
id, name, age, gen, cr = cursor.fetchone()
conn.close()
return id, name, age, gen, cr
while(True):
ret, img = cam.read();
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceDetect.detectMultiScale(gray, 1.3, 5);
for(x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
id, conf = rec.predict(gray[y:y+h, x:x+w])
id, name, age, gen, cr = getProfile(id)
if(name != None and age != None and gen != None and cr != None):
cv2.putText(img, "Name : " + str(name), (x, y+h+20), font, (0, 255, 0), 2);
cv2.putText(img, "Age : " + str(age), (x, y+h+45), font, (0, 255, 0), 2);
cv2.putText(img, "Gender : " + str(gen), (x, y+h+70), font, (0, 255, 0), 2);
cv2.putText(img, "Criminal Records : " + str(cr), (x, y+h+95), font, (0, 0, 255), 2);
cv2.imshow("Face", img);
if(cv2.waitKey(1)==ord('q')):
break;
cam.release()
cv2.destroyAllWindows()
Ошибки:
D:\Python\python.exe C:/face_detection_mysql/recognition.py
Traceback (most recent call last):
File "C:/face_detection_mysql/recognition.py", line 34, in <module>
cv2.putText(img, "Name : " + str(name), (x, y+h+20), font, (0, 255, 0), 2);
TypeError: must be real number, not tuple
[ WARN:0] global C:\projects\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (674) SourceReaderCB::~SourceReaderCB terminating async callback
Process finished with exit code -805306369 (0xCFFFFFFF)




