Все знают такую функцию в фото-аппаратах, как распознавание лиц? Никогда не задумывались, как она работает? Никогда не хотелось сделать что-то подобное? Например, чтобы ваш компьютер выходил из спящего режима, как только кто-то к нему сел? Применений можно найти море, а тут я расскажу как это сделать.
Мы живём в счастливую для лентяев эпоху - вам уже не нужно купаться в сложной математической теории. Всё сделано за вас, по крайней мере на таком элементарном уровне. Распознавание лиц происходит по признакам Хаара. "Эталон" лица уже давно создан и хорошо обучен, находится он в файле haarcascade_frontalface_alt.xml . Там находится, так называемая, модель лица, а именно "Идеальное" лицо в виде примитивов Хаара :
Первый бой (вывод видео на экран) :
Для начала давайте на экран выведем видео поток. С помощью OpenCV это делается элементарно.
import cv2
cam = cv2.VideoCapture(0)
while 1:
_,frame =cam.read()
cv2.imshow("features", frame)
if cv2.waitKey(10) == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break
Работает? Классно!
Код прост:
Я создаю объект камеры, которая подхватит первую попавшуюся(ваша web-ка)
И всё последующее время я буду читать 1 кадр из камеры и выводить его на экран, каждые десять миллисекунд опрашивать клавиатуру, и, если нажата клавиша с кодом 27(Esc) ,то выйду из бесконечного цикла прямо в ОС.
HaarDetectObjects принимает 3 параметра ( где_искать,что искать, где_хранить_промежуточные_данные)
где_хранить_промежуточные_данные - область памяти, которую можно выделить функцией CreateMemStorage.
Уже что-то.
Попытаемся понять, как работает наша камера:
Обратите внимание, что треугольники ACB и DCE подобны. Что это значит?
Уберём из рисунка лишнее и добавим необходимое:
Я создаю объект камеры, которая подхватит первую попавшуюся(ваша web-ка)
И всё последующее время я буду читать 1 кадр из камеры и выводить его на экран, каждые десять миллисекунд опрашивать клавиатуру, и, если нажата клавиша с кодом 27(Esc) ,то выйду из бесконечного цикла прямо в ОС.
Битва вторая( использование микроскопа по назначению):
Использовать OpenCV для вывода видео на экран - забивание гвоздей микроскопом. Не будем столь брутальны - начнём распознавание лиц:
import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')
def detect(image):
bitmap = cv.fromarray(image)
faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
if faces:
for (x,y,w,h),n in faces:
pass
cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),2)
return image
if __name__ == "__main__":
cam = cv2.VideoCapture(0)
while 1:
_,frame =cam.read()
frame = numpy.asarray(detect(frame))
cv2.imshow("features", frame)
if cv2.waitKey(10) == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break
HaarDetectObjects принимает 3 параметра ( где_искать,что искать, где_хранить_промежуточные_данные)
где_хранить_промежуточные_данные - область памяти, которую можно выделить функцией CreateMemStorage.
Уже что-то.
Последний бой ( проявите каплю своего творчества):
Если, проделав это всё, вы гордо скажите, что вы программист, я плюну вам в лицо. Что вы сделали? Ну хоть малость своих мыслей тут? Мы использовали стандартные функции для совершения достаточно тривиальных действий - ни капли математического аппарата. Давайте-же прибавим! А что тут можно сделать? Определим расстояние до лица!Попытаемся понять, как работает наша камера:
Обратите внимание, что треугольники ACB и DCE подобны. Что это значит?
Уберём из рисунка лишнее и добавим необходимое:
А значит это то , что отношение DE/CH равно отношению AB/FC. Поднеся линейку в 10 сантиметров к веб-камере так, чтоб она поместилась полностью, и измерив расстояние до веб-камеры от линейки, мы можем узнать отношение высоты матрицы нашей камеры к её фокусному расстоянию.( у меня это 1.6) .
Средняя высота лица человека - 15 сантиметров.
Получив из OpenCV размер квадрата лица, просто вычислить, сколько процентов всей высоты кадра оно занимает. Несложно додуматься, что Если лицо влезает в камеру всеми своими 15 сантиметрами , то до веб-камеры - (AB/FC)*12. Если лицо занимает меньше 100% пространства, то оно более удалено. Давайте определим , насколько...
Средняя высота лица человека - 15 сантиметров.
Получив из OpenCV размер квадрата лица, просто вычислить, сколько процентов всей высоты кадра оно занимает. Несложно додуматься, что Если лицо влезает в камеру всеми своими 15 сантиметрами , то до веб-камеры - (AB/FC)*12. Если лицо занимает меньше 100% пространства, то оно более удалено. Давайте определим , насколько...
Что нам отсюда известно?
Мы знаем, отношение AB/FE - это есть наше фокальное расстояние, обозначим его как focal.
реальные размеры AB.
Нам надо узнать расстояние FG.
Треугольники AFB и DFC подобны, значит FE/FG=AB/DC. Из этого равенства видно, что если FG увеличивается в M раз, то либо DC увеличивается в M раз, либо AB уменьшается в M раз. AB уменьшится не может - это реальный размер лица, он всегда 15 сантиметров, А вот DC - может, это размер лица на фотографии, чем лицо дальше, тем размер его меньше. Исходя из этого, можно сделать вывод, что если DC уменьшилось в M раз( или на N%) ,то и FG уменьшилось так же в M раз( или на N%). Если DC у нас равно AB, то GF = EF, если DC меньше AB в M раз (илиN%),то и FG
Теперь ближе к коду:
Как видите, я задаю отношение размера матрицы к фокальному расстоянию и размер лица человека, и, исходя из этого, считаю его удалённость, в зависимости от процентов занимаемого им места на экране.
Вот и все пироги, ничего сложного. В следующий раз я предоставлю программу для детектирования любого объекта, стоит вам его выделить мышкой.
Мы знаем, отношение AB/FE - это есть наше фокальное расстояние, обозначим его как focal.
реальные размеры AB.
Нам надо узнать расстояние FG.
Треугольники AFB и DFC подобны, значит FE/FG=AB/DC. Из этого равенства видно, что если FG увеличивается в M раз, то либо DC увеличивается в M раз, либо AB уменьшается в M раз. AB уменьшится не может - это реальный размер лица, он всегда 15 сантиметров, А вот DC - может, это размер лица на фотографии, чем лицо дальше, тем размер его меньше. Исходя из этого, можно сделать вывод, что если DC уменьшилось в M раз( или на N%) ,то и FG уменьшилось так же в M раз( или на N%). Если DC у нас равно AB, то GF = EF, если DC меньше AB в M раз (илиN%),то и FG
Теперь ближе к коду:
import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')
c=1.6
Sr=15
def detect(image):
bitmap = cv.fromarray(image)
faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
if faces:
for (x,y,w,h),n in faces:
k=float(w)/bitmap.cols
S = Sr*c/k
cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),3)
cv2.putText(image,'S=%s'%(S),(x,y-10), cv2.FONT_HERSHEY_PLAIN, 1.0,(255,255,255))
return image
if __name__ == "__main__":
cam = cv2.VideoCapture(0)
while 1:
_,frame =cam.read()
frame = numpy.asarray(detect(frame))
cv2.imshow("features", frame)
if cv2.waitKey(1) == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break
Как видите, я задаю отношение размера матрицы к фокальному расстоянию и размер лица человека, и, исходя из этого, считаю его удалённость, в зависимости от процентов занимаемого им места на экране.
Вот и все пироги, ничего сложного. В следующий раз я предоставлю программу для детектирования любого объекта, стоит вам его выделить мышкой.
Спасибо за статью, интересно написано.
ОтветитьУдалитьСпасибоньки!
ОтветитьУдалить