1 (изменено: Malcev, 2023-03-10 16:21:52)

Тема: 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"
}

Тема для обсуждения