Тема: AHK: Dlib распознование лиц (Face recognition)
smbape создал библиотеку dlib com для autoit.
https://www.autoitscript.com/forum/topi … -dlib-udf/
Она примечательна тем, что может распознавать лица.
Пример получения 128D vector лица:
https://github.com/smbape/node-autoit-d … nition.au3
Для выполния кода нужно скачать модель отсюда:
https://github.com/davisking/dlib-model … ks.dat.bz2
разархивировать её, после чего путь к этой модели указать в predictor_path.
Также скачать модель отсюда:
https://github.com/davisking/dlib-model … v1.dat.bz2
разархивировать её, после чего путь к этой модели указать в face_rec_model_path.
Также нужно указать путь к папке с картинками.
faces_folder_path := A_ScriptDir "\examples\faces"
opencv_world_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_world470.dll"
opencv_ffmpeg_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_videoio_ffmpeg470_64.dll"
autoit_opencv_com_path := A_ScriptDir "\autoit-opencv-com\autoit_opencv_com470.dll"
autoit_dlib_com_path := A_ScriptDir "\autoit-dlib-com\autoit_dlib_com-19.24-470.dll"
predictor_path := A_ScriptDir "\dlib-models\shape_predictor_5_face_landmarks.dat"
face_rec_model_path := A_ScriptDir "\dlib-models\dlib_face_recognition_resnet_model_v1.dat"
hOpencv := DllCall("LoadLibrary", "str", opencv_world_path, "ptr")
hOpencvFfmpeg := DllCall("LoadLibrary", "str", opencv_ffmpeg_path, "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", autoit_opencv_com_path, "ptr")
hDlibCom := DllCall("LoadLibrary", "str", autoit_dlib_com_path, "ptr")
ComObjCreate := Func("_ComObjCreate").Bind(autoit_opencv_com_path, autoit_dlib_com_path)
; Load all the models we need: a detector to find the faces, a shape predictor
; to find face landmarks so we can precisely localize the face, and finally the
; face recognition model.
dlib := ComObjCreate.Call("Dlib.dlib")
detector := dlib.get_frontal_face_detector()
sp := ComObjCreate.Call("Dlib.dlib.shape_predictor").create(predictor_path)
facerec := ComObjCreate.Call("Dlib.dlib.face_recognition_model_v1").create(face_rec_model_path)
win := ComObjCreate.Call("Dlib.dlib.image_window")
; Now process all the images
Loop, Files, %faces_folder_path%\*
{
img := dlib.load_rgb_image(A_LoopFileLongPath)
win.clear_overlay()
win.set_image(img)
; Ask the detector to find the bounding boxes of each face. The 1 in the
; second argument indicates that we should upsample the image 1 time. This
; will make everything bigger and allow us to detect more faces.
dets := detector.call(img, 1)
msgbox % "Number of faces detected: " dets.MaxIndex()+1
; Now process each face we found.
loop % dets.MaxIndex()+1
{
d := dets[A_Index-1]
msgbox % "left: " d.left() "`ntop: " d.top() "`nright: " d.right() "`nbottom: " d.bottom()
; Get the landmarks/parts for the face in box d.
shape := sp.call(img, d)
; Draw the face landmarks on the screen so we can see what face is currently being processed.
win.clear_overlay()
win.add_overlay(d)
win.add_overlay(shape)
; Compute the 128D vector that describes the face in img identified by
; shape. In general, if two face descriptor vectors have a Euclidean
; distance between them less than 0.6 then they are from the same
; person, otherwise they are from different people. Here we just print
; the vector to the screen.
face_descriptor := facerec.compute_face_descriptor(img, shape)
msgbox % face_descriptor.ToString()
; It should also be noted that you can also call this function like this:
; face_descriptor := facerec.compute_face_descriptor(img, shape, 100, 0.25)
; The version of the call without the 100 gets 99.13% accuracy on LFW
; while the version with 100 gets 99.38%. However, the 100 makes the
; call 100x slower to execute, so choose whatever version you like. To
; explain a little, the 3rd argument tells the code how many times to
; jitter/resample the image. When you set it to 100 it executes the
; face descriptor extraction 100 times on slightly modified versions of
; the face and returns the average result. You could also pick a more
; middle value, such as 10, which is only 10x slower but still gets an
; LFW accuracy of 99.3%.
; 4th value (0.25) is padding around the face. If padding == 0 then the chip will
; be closely cropped around the face. Setting larger padding values will result a looser cropping.
; In particular, a padding of 0.5 would double the width of the cropped area, a value of 1.
; would triple it, and so forth.
; There is another overload of compute_face_descriptor that can take
; as an input an aligned image.
; Note that it is important to generate the aligned image as
; dlib.get_face_chip would do it i.e. the size must be 150x150,
; centered and scaled.
; Here is a sample usage of that
; Let's generate the aligned image using get_face_chip
face_chip := dlib.get_face_chip(img, shape)
; Now we simply pass this chip (aligned image) to the api
face_descriptor_from_prealigned_image := facerec.compute_face_descriptor(face_chip)
msgbox % face_descriptor_from_prealigned_image.ToString()
}
}
msgbox done
_ComObjCreate(opencvPath, dlibPath, comobject)
{
if InStr(comobject, "opencv")
path := opencvPath
else
path := dlibPath
DllCall(path "\DllActivateManifest")
comobject := ComObjCreate(comobject)
DllCall(path "\DllDeactivateActCtx")
return comobject
}
Как можно с этим поиграться:
1) В папку с картинками лиц кидаем пару и сохраняем их под именными названиями, например у меня Baiden.jpg, Obama.jpg, Tramp.jpg и Nadya.jpg.
2) В скрипте указываем путь к папке для сохранения полученных векторов - facesData_folder_path.
Запускаем скрипт, который создаст/пересоздаст векторы.
faces_folder_path := A_ScriptDir "\examples\faces"
facesData_folder_path := A_ScriptDir "\examples\data"
opencv_world_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_world470.dll"
opencv_ffmpeg_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_videoio_ffmpeg470_64.dll"
autoit_opencv_com_path := A_ScriptDir "\autoit-opencv-com\autoit_opencv_com470.dll"
autoit_dlib_com_path := A_ScriptDir "\autoit-dlib-com\autoit_dlib_com-19.24-470.dll"
predictor_path := A_ScriptDir "\dlib-models\shape_predictor_5_face_landmarks.dat"
face_rec_model_path := A_ScriptDir "\dlib-models\dlib_face_recognition_resnet_model_v1.dat"
setbatchlines -1
hOpencv := DllCall("LoadLibrary", "str", opencv_world_path, "ptr")
hOpencvFfmpeg := DllCall("LoadLibrary", "str", opencv_ffmpeg_path, "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", autoit_opencv_com_path, "ptr")
hDlibCom := DllCall("LoadLibrary", "str", autoit_dlib_com_path, "ptr")
ComObjCreate := Func("_ComObjCreate").Bind(autoit_opencv_com_path, autoit_dlib_com_path)
dlib := ComObjCreate.Call("Dlib.dlib")
detector := dlib.get_frontal_face_detector()
sp := ComObjCreate.Call("Dlib.dlib.shape_predictor").create(predictor_path)
facerec := ComObjCreate.Call("Dlib.dlib.face_recognition_model_v1").create(face_rec_model_path)
Loop, Files, %faces_folder_path%\*
{
img := dlib.load_rgb_image(A_LoopFileLongPath)
dets := detector.call(img, 0)
if (dets.MaxIndex()+1 = 0)
{
msgbox error: cannot detect face in %A_LoopFileLongPath%
continue
}
if (dets.MaxIndex()+1 > 1)
{
msgbox error: several faces detected in %A_LoopFileLongPath%
continue
}
shape := sp.call(img, dets[0])
face_descriptor := facerec.compute_face_descriptor(img, shape)
Data_path := facesData_folder_path "\" RegexReplace(A_LoopFileName, "\Q." A_LoopFileExt "\E$") ".txt"
Filedelete, % Data_path
Fileappend, % face_descriptor.ToString(), % Data_path
}
msgbox done
_ComObjCreate(opencvPath, dlibPath, comobject)
{
if InStr(comobject, "opencv")
path := opencvPath
else
path := dlibPath
DllCall(path "\DllActivateManifest")
comobject := ComObjCreate(comobject)
DllCall(path "\DllDeactivateActCtx")
return comobject
}
Затем запускаем следующий скрипт нажимаем f11 и выбираем картинку.
При совпадении скрипт выдаст нам имя данного человека.
facesData_folder_path := A_ScriptDir "\examples\data"
opencv_world_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_world470.dll"
opencv_ffmpeg_path := A_ScriptDir "\opencv-4.7.0-windows\opencv\build\x64\vc16\bin\opencv_videoio_ffmpeg470_64.dll"
autoit_opencv_com_path := A_ScriptDir "\autoit-opencv-com\autoit_opencv_com470.dll"
autoit_dlib_com_path := A_ScriptDir "\autoit-dlib-com\autoit_dlib_com-19.24-470.dll"
predictor_path := A_ScriptDir "\dlib-models\shape_predictor_5_face_landmarks.dat"
face_rec_model_path := A_ScriptDir "\dlib-models\dlib_face_recognition_resnet_model_v1.dat"
setbatchlines -1
hOpencv := DllCall("LoadLibrary", "str", opencv_world_path, "ptr")
hOpencvFfmpeg := DllCall("LoadLibrary", "str", opencv_ffmpeg_path, "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", autoit_opencv_com_path, "ptr")
hDlibCom := DllCall("LoadLibrary", "str", autoit_dlib_com_path, "ptr")
ComObjCreate := Func("_ComObjCreate").Bind(autoit_opencv_com_path, autoit_dlib_com_path)
dlib := ComObjCreate.Call("Dlib.dlib")
detector := dlib.get_frontal_face_detector()
sp := ComObjCreate.Call("Dlib.dlib.shape_predictor").create(predictor_path)
facerec := ComObjCreate.Call("Dlib.dlib.face_recognition_model_v1").create(face_rec_model_path)
oData := {}
Loop, Files, %facesData_folder_path%\*
{
128D_vector := []
fileread, data, % A_LoopFileLongPath
Loop, parse, data, `n, `r
128D_vector.Push(A_LoopField)
key := RegexReplace(A_LoopFileName, "\Q." A_LoopFileExt "\E$")
oData[key ""] := 128D_vector
}
return
f11::
FileSelectFile, image_path
if (image_path = "")
return
win := ComObjCreate.Call("Dlib.dlib.image_window")
img := dlib.load_rgb_image(image_path)
dets := detector.call(img, 0)
loop % dets.MaxIndex()+1
{
d := dets[A_Index-1]
shape := sp.call(img, d)
win.clear_overlay()
win.set_image(img)
win.add_overlay(d)
win.add_overlay(shape)
face_descriptor := facerec.compute_face_descriptor(img, shape)
person := Euclidean_distance(face_descriptor, oData)
msgbox % person
}
return
_ComObjCreate(opencvPath, dlibPath, comobject)
{
if InStr(comobject, "opencv")
path := opencvPath
else
path := dlibPath
DllCall(path "\DllActivateManifest")
comobject := ComObjCreate(comobject)
DllCall(path "\DllDeactivateActCtx")
return comobject
}
Euclidean_distance(oPoint, oData, threshold:=0.6)
{
for key, value in oData
{
sum := 0
for index, item in value
sum += (oPoint.item[A_Index-1]-item)**2
if (sqrt(sum) < threshold)
return key
}
return "no found"
}