#python #sql #database #opencv #face-detection
#python #sql #База данных #opencv #распознавание лиц
Вопрос:
Я работаю над программным обеспечением для распознавания лиц в качестве хобби, чтобы узнать больше о том, как использовать OpenCV.
Мое программное обеспечение включает в себя функцию для обнаружения и генерации 20 изображений набора данных и сохраняет их с идентификатором пользователя, которого я назначил в базе данных, затем обучает его и добавляет в мой файл «.trainedData.yml», который я использую для распознавания лиц.
У меня есть база данных SQL, в которой я храню профили людей и использую свою веб-камеру для съемки видео.
Когда я запускаю текущее программное обеспечение, в каждом кадре я проверяю уровень достоверности, и если он достаточно хорош, я просматриваю базу данных, чтобы вернуть информацию о найденном профиле. После этого я вызываю функцию для вставки в базу данных данных, чтобы я мог отслеживать, когда и где было обнаружено лицо.
Проблема: этот запрос на вставку обрабатывается каждый кадр, создавая множество вставок, а иногда даже сбой, когда одновременно выполняется несколько вставок.
Есть ли способ сделать это более эффективным без необходимости вставлять данные в каждый кадр и, возможно, делать это каждые 5 или 10 секунд?
Пожалуйста, найдите мой код ниже
Заранее благодарю,
import cv2
from dbconnect import mySQL
import geocoder
faceDetect=cv2.CascadeClassifier('Classifiershaarcascade_frontalface_alt.xml')
cam = cv2.VideoCapture(0)
rec = cv2.face.LBPHFaceRecognizer_create()
rec.read(r'trainnertrainningData.yml')
def getProfile(Id):
mySQL.execute("SELECT * FROM people where id =" str(Id))
cursor = mySQL.fetchall()
print(cursor)
profile = None
for row in cursor:
profile = row
#mySQL.close()
return profile
def insertProfile(Id):
try:
query = "insert into memberLocation values (null," str(Id) ", now(), 'LOCATION DETECTED')"
print(query)
mySQL.execute(query)
print("Entry inserted successfuly")
mySQL.commit()
except:
print("Failed to insert user " str(Id))
def draw_border(frame, pt1, pt2, color, thickness, r, d):
x1,y1 = pt1
x2,y2 = pt2
# Top left
cv2.line(frame, (x1 r, y1), (x1 r d, y1), color, thickness)
cv2.line(frame, (x1, y1 r), (x1, y1 r d), color, thickness)
cv2.ellipse(frame, (x1 r, y1 r), (r, r), 180, 0, 90, color, thickness)
# Top right
cv2.line(frame, (x2 - r, y1), (x2 - r - d, y1), color, thickness)
cv2.line(frame, (x2, y1 r), (x2, y1 r d), color, thickness)
cv2.ellipse(frame, (x2 - r, y1 r), (r, r), 270, 0, 90, color, thickness)
# Bottom left
cv2.line(frame, (x1 r, y2), (x1 r d, y2), color, thickness)
cv2.line(frame, (x1, y2 - r), (x1, y2 - r - d), color, thickness)
cv2.ellipse(frame, (x1 r, y2 - r), (r, r), 90, 0, 90, color, thickness)
# Bottom right
cv2.line(frame, (x2 - r, y2), (x2 - r - d, y2), color, thickness)
cv2.line(frame, (x2, y2 - r), (x2, y2 - r - d), color, thickness)
cv2.ellipse(frame, (x2 - r, y2 - r), (r, r), 0, 0, 90, color, thickness)
video_capture = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_SIMPLEX
while True:
# try to get coordinates
# g = geocoder.ip('me') # coordinates are way off correct but pulling internet service location not current location
# print(g.latlng)
# Capture frame-by-frame
ret, frame = video_capture.read()
if ret==False:
continue
frame = cv2.flip(frame, 1) # Flip image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceDetect.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (x, y, w, h) in faces:
draw_border(frame, (x, y), (x w, y h), (255, 0, 105),4, 15, 10)
#cv2.rectangle(frame, (x,y), (x w, y h), (0,0,255), 2)
roi_gray = gray[y:y h, x:x w]
roi_color = frame[y:y h, x:x w]
nbr_predicted, conf = rec.predict(gray[y:y h, x:x w])
if conf < 70:
profile=getProfile(nbr_predicted)
if profile != None:
cv2.putText(frame, "Confidence Level: " str(round(conf,2)) "%", (x, y h 30), font, 0.4, (255, 0, 105), 1)
cv2.putText(frame, "Name: " str(profile[1]), (x, y h 50), font, 0.4, (255, 0, 105), 1)
cv2.putText(frame, "Age: " str(profile[2]), (x, y h 70), font, 0.4, (255, 0, 105), 1)
cv2.putText(frame, "Gender: " str(profile[3]), (x, y h 90), font, 0.4, (255, 0, 105), 1)
#call function to insert into database
insertProfile(nbr_predicted)
else:
cv2.putText(frame, "Confidence Level: " str(round(conf,2)) "%", (x, y h 30), font, 0.4, (0, 0, 255), 1)
cv2.putText(frame, "Name: Unknown", (x, y h 50), font, 0.4, (0, 0, 255), 1)
cv2.putText(frame, "Age: Unknown", (x, y h 70), font, 0.4, (0, 0, 255), 1)
cv2.putText(frame, "Gender: Unknown", (x, y h 90), font, 0.4, (0, 0, 255), 1)
# Display the resulting frame
cv2.imshow('frame', frame)
if cv2.waitKey(1) amp; 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Комментарии:
1. Вы можете перерисовывать данные каждые 5 секунд, чтобы наложить изображение. И примените это наложение к кадру камеры.
Ответ №1:
Вы можете составить список, в котором собирать nbr_predicted
экземпляры, добавить счетчик для каждого успешного распознавания и параметр (each_N_passes); затем выполнять пакетные вставки при каждом N распознаваниях:
nbr_predicted_list = []
passes = 0
batchStep = 10
while True:
...
if conf < 70:
#Instead of this:
#call function to insert into database
#insertProfile(nbr_predicted)
#DO:
passes
nbr_predicted_list.append(nbr_predicted)
if passes % batchPasses == 0:
for pr in nbr_predicted_list:
insertProfile(pr)
nbr_predicted_list.clear()
Кроме того, попробуйте увеличить время задержки: if cv2.waitKey(1) amp; 0xFF == ord('q'):
, если максимальная частота кадров не является критической.
Измените его, чтобы сказать:
cv2.waitKey(delay)
Где:
delay = 1000/frameRate # ms
(Фактическая частота кадров будет ниже из-за времени распознавания и т. Д.)
…
Также может быть уменьшено количество транзакций, если вы можете проверять повторяющиеся профили и не вставлять их дважды в пакет (если это желательно), а также если вы кэшируете профили после чтения с идентификатором в getProfile (если они постоянны во время выполнения).
Если они кэшируются, при следующем вызове возьмите идентификатор из словаря и верните профиль без транзакции SQL.
Если требуется скорость, попробуйте также удалить чрезмерные вызовы печати (или сделайте их с максимально коротким выводом и меньшим количеством новых строк / прокрутки терминала), ведение журнала может быть быстрее.
Более сложное решение может использовать поток или многопроцессорную обработку. Также одним из способов предотвращения условий гонки для вставок может быть добавление короткого cv.waitKey или sleep на 1 миллисекунду или что-то еще между каждым вызовом в БД; хотя это лучше в потоке.
Обратите внимание, что если вы слишком сильно задерживаете доступ к SQL и собираете слишком много вставок кандидатов (скажем, используя максимум 30 кадров в секунду, задержка 33 и 10 секунд, если каждый кадр имеет распознавание: 300 элементов), и если вы сразу отправляете их в основной поток, это может привести к блокировке, и это приведет к сбою.может «дросселировать» частоту кадров видео во время этих передач.
…
Другой общей идеей может быть функция вставки в БД для получения не одного, а многих собранных элементов данных, а затем один вызов этой функции для вставки многих элементов одновременно: возможно, сама команда SQL и схема базы данных могут быть такими, что одна ВСТАВКА добавляет много строк, если это возможноустраните узкое место со слишком большим количеством простых одиночных транзакций.
Например, многие элементы данных могут быть добавлены сразу в промежуточную таблицу в виде строк varchar с элементами, закодированными в формате CSV и т. Д. В виде строк. Затем какая-нибудь более сложная команда SQL или просто другой скрипт в другом процессе или потоке могут просмотреть эту таблицу, выбрать новые строки (ВЫБЕРИТЕ * где время… после некоторой последней выборки текущего времени или некоторого идентификатора и т. Д.) Проанализируйте их, А затем вставьте проанализированные элементы в другую «окончательную» таблицу с «несжатой» структурой по умолчанию, Добавив при необходимости режим ожидания и т. Д.