Una guia per a la detecció de cares a Python

Bloc

Una guia per a la detecció de cares a Python

Una guia per a la detecció de cares a Python

En aquest tutorial, veurem com crear i llançar un algorisme de detecció de cares a Python mitjançant OpenCV i Dlib.

També afegirem algunes funcions per detectar els ulls i la boca en diverses cares alhora. Aquest article recorrerà les implementacions més bàsiques de detecció de cares, inclosos els classificadors en cascada, les finestres HOG i les CNN de Deep Learning.

Cobrirem la detecció de cares mitjançant:

  • Classificadors Haar Cascade mitjançant OpenCV
  • Histograma de degradats orientats mitjançant Dlib
  • Xarxes neuronals convolucionals que utilitzen Dlib

Es pot trobar el dipòsit Github d’aquest article aquí

Introducció

Utilitzarem OpenCV, una biblioteca de codi obert per a visió per ordinador, escrita en C / C ++, que té interfícies en C ++, Python i Java. És compatible amb Windows, Linux, MacOS, iOS i Android. Alguns dels nostres treballs també requeriran l’ús de Dlib, un modern conjunt d’eines C ++ que conté algorismes d’aprenentatge automàtic i eines per crear programari complex.

Requisits

El primer pas és instal·lar OpenCV i Dlib. Executeu l'ordre següent:

pip install opencv-python pip install dlib

En funció de la vostra versió, el fitxer s’instal·larà aquí:

/usr/local/lib/python3.7/site-packages/cv2

Camí d'importacions i models

Crearem un fitxer portàtil / python Jupyter i començarem amb:

import cv2 import matplotlib.pyplot as plt import dlib from imutils import face_utils font = cv2.FONT_HERSHEY_SIMPLEX

I. Classificadors en cascada

Al principi explorarem els classificadors Cascade.

I.1. Teoria

El classificador en cascada, o cascada de classificadors impulsats que treballen amb característiques semblants al haar, és un cas especial d’aprenentatge de conjunt, anomenat boosting. Normalment es basa Adaboost classificadors (i altres models com Real Adaboost, Gentle Adaboost o Logitboost).

Els classificadors en cascada es formen sobre uns quants centenars d’imatges d’exemple d’imatges que contenen l’objecte que volem detectar i d’altres imatges que no contenen aquestes imatges.

Com podem detectar si hi ha una cara o no? Hi ha un algorisme, anomenat marc de detecció d'objectes Viola-Jones, que inclou tots els passos necessaris per a la detecció de cares en viu:

L'original paper es va publicar el 2001.

I.1.a. Selecció de funcions Haar

Hi ha algunes característiques comunes que trobem a les cares humanes més habituals:

  • una regió dels ulls foscos en comparació amb les galtes superiors

  • una regió de pont nas brillant en comparació amb els ulls

  • alguna ubicació específica d’ulls, boca, nas ...

Les característiques s’anomenen Haar Features. El procés d'extracció de funcions serà així:

Característiques del cabell

En aquest exemple, la primera característica mesura la diferència d'intensitat entre la regió dels ulls i una regió de les galtes superiors. El valor de la característica es calcula simplement sumant els píxels de l'àrea negra i restant els píxels de l'àrea blanca.

A continuació, apliquem aquest rectangle com a nucli de convolució, sobre tota la nostra imatge. Per ser exhaustius, hauríem d’aplicar totes les dimensions i posicions possibles de cada nucli. Les imatges simples de 24 * 24 solen donar lloc a més de 160.000 funcions, cadascuna formada per una suma / resta de valors de píxels. Computacionalment seria impossible la detecció de cares en viu. Llavors, com accelerem aquest procés?

  • un cop identificada la bona regió per un rectangle, no serveix de res passar la finestra sobre una regió completament diferent de la imatge. Això es pot aconseguir mitjançant Adaboost.

  • calculeu les característiques del rectangle utilitzant el principi de la imatge integral, que és molt més ràpid. Ho tractarem a la següent secció.

Hi ha diversos tipus de rectangles que es poden aplicar per a l'extracció de les funcions de Haar. Segons el document original:

  • la característica de dos rectangles és la diferència entre la suma dels píxels dins de dues regions rectangulars, que s’utilitza principalment per detectar arestes (a, b)

  • la característica de tres rectangles calcula la suma dins de dos rectangles exteriors restats de la suma en un rectangle central, utilitzat principalment per detectar línies (c, d)

  • la característica de quatre rectangles calcula la diferència entre parells diagonals de rectangle (e)

Rectangles de cabell

Ara que s'han seleccionat les funcions, les apliquem al conjunt d'imatges d'entrenament mitjançant la classificació Adaboost, que combina un conjunt de classificadors febles per crear un model de conjunt precís. Amb 200 funcions (en lloc de 160.000 inicialment), s’aconsegueix una precisió del 95%. Els autors de l’article han seleccionat 6’000 funcions.

I.1.b. La imatge integral

El càlcul de les característiques del rectangle en un estil de nucli convolucional pot ser llarg, molt llarg. Per aquest motiu, els autors, Viola i Jones, van proposar una representació intermèdia per a la imatge: la imatge integral. El paper de la imatge integral és permetre calcular qualsevol suma rectangular simplement, utilitzant només quatre valors. Veurem com funciona!

Suposem que volem determinar les característiques del rectangle en un determinat píxel amb coordenades (x, y). A continuació, la imatge integral del píxel en la suma dels píxels a sobre i a l'esquerra del píxel donat.

on ii (x, y) és la imatge integral i i (x, y) és la imatge original.

Quan es calcula tota la imatge integral, hi ha una forma que es repeteix que només requereix una passada sobre la imatge original. De fet, podem definir el següent parell de recurrències:

on s (x, y) s (x, y) és la suma acumulada de la fila i s (x − 1) = 0, ii (−1, y) = 0.

Com pot ser útil? Bé, considerem una regió D per a la qual ens agradaria estimar la suma dels píxels. Hem definit altres 3 regions: A, B i C.

  • El valor de la imatge integral al punt 1 és la suma dels píxels del rectangle A.

    numpy lògic_i
  • El valor al punt 2 és ?? A + B

  • El valor al punt 3 és ?? A + C

  • El valor del punt 4 és ?? A + B + C + D.

Per tant, la suma de píxels a la regió D es pot calcular simplement com: 4 + 1− (2 + 3).

I en una sola passada, hem calculat el valor dins d’un rectangle utilitzant només 4 referències de matriu.

Simplement s’ha de tenir en compte que els rectangles són funcions bastant simples a la pràctica, però suficients per a la detecció de cares. Els filtres orientables solen ser més flexibles quan es tracta de problemes complexos.

Filtres orientables

I.1c. Aprendre la funció de classificació amb Adaboost

Donat un conjunt d’imatges d’entrenament etiquetades (positives o negatives), Adaboost s’utilitza per:

  • seleccioneu un petit conjunt de funcions

  • i formar el classificador

Com que la majoria de les funcions entre els 160’000 se suposa que són força irrellevants, l’algoritme d’aprenentatge feble al voltant del qual construïm un model de reforç està dissenyat per seleccionar la característica de rectangle únic que divideix els millors exemples negatius i positius.

I.1.d. Classificador en cascada

Tot i que el procés descrit anteriorment és força eficient, queda un problema important. En una imatge, la major part de la imatge és una regió que no és cara. Donar la mateixa importància a cada regió de la imatge no té cap sentit, ja que ens hauríem de centrar principalment en les regions que tenen més probabilitats de contenir una imatge. Viola i Jones van aconseguir una taxa de detecció augmentada alhora que reduïen el temps de càlcul mitjançant classificadors en cascada.

La idea clau és rebutjar les subfinestres que no contenen cares mentre s’identifiquen les regions que sí. Com que la tasca consisteix a identificar correctament la cara, volem minimitzar la taxa de falsos negatius, és a dir, les subfinestres que contenen una cara i que no s’han identificat com a tals.

S’aplica una sèrie de classificadors a cada subfinestra. Aquests classificadors són arbres de decisió simples:

  • si el primer classificador és positiu, passem al segon
  • si el segon classificador és positiu, passem al tercer
  • ...

Qualsevol resultat negatiu en algun moment condueix al rebuig de la subfinestra perquè pot contenir una cara. El classificador inicial elimina la majoria d’exemples negatius a un cost computacional baix, i els classificadors següents eliminen exemples negatius addicionals però requereixen més esforç computacional.

Els classificadors s’entrenen utilitzant Adaboost i ajustant el llindar per minimitzar la taxa de falsos. En entrenar aquest model, les variables són les següents:

  • el nombre d’etapes de classificació

  • el nombre de funcions de cada etapa

  • el llindar de cada etapa

Per sort, a OpenCV, tot aquest model ja està entrenat prèviament per a la detecció de cares.

Si voleu obtenir més informació sobre les tècniques d’augment, us convido a consultar el meu article sobre Adaboost .

recuperar compte aol desactivat

I.2. Importacions

El següent pas és localitzar els pesos prèviament entrenats. Utilitzarem models predeterminats predeterminats per detectar cara, ulls i boca. En funció de la vostra versió de Python, els fitxers haurien d’estar ubicats en algun lloc d’aquí:

/usr/local/lib/python3.7/site-packages/cv2/data

Un cop identificats, declararem els classificadors Cascade d’aquesta manera:

cascPath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml' eyePath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml' smilePath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml' faceCascade = cv2.CascadeClassifier(cascPath) eyeCascade = cv2.CascadeClassifier(eyePath) smileCascade = cv2.CascadeClassifier(smilePath)

I.3. Detecta la cara en una imatge

Abans d’implementar l’algoritme de detecció de cares en temps real, provem una versió senzilla d’una imatge. Podem començar carregant una imatge de prova:

# Load the image gray = cv2.imread('face_detect_test.jpeg'>

Test image

Then, we detect the face and we add a rectangle around it :

# Detect faces faces = faceCascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, flags=cv2.CASCADE_SCALE_IMAGE ) # For each face for (x, y, w, h) in faces: # Draw rectangle around the face cv2.rectangle(gray, (x, y), (x+w, y+h), (255, 255, 255), 3) 

Aquí hi ha una llista dels paràmetres més comuns del detectMultiScale funció:

  • scaleFactor: paràmetre que especifica quant es redueix la mida de la imatge a cada escala de la imatge.

  • minNeighbors: paràmetre que especifica quants veïns hauria de tenir cada rectangle candidat per conservar-lo.

  • minSize: mida mínima possible de l'objecte. S’ignoren els objectes més petits que això.

  • maxSize: mida màxima possible de l'objecte. Els objectes més grans que aquests són ignorats.

Finalment, mostreu el resultat:

plt.figure(figsize=(12,8)) plt.imshow(gray, cmap='gray') plt.show()

La detecció de cares funciona bé a la nostra imatge de prova. Passem ara a temps real.

I.4. Detecció de cares en temps real

Passem a la implementació de Python de la detecció facial en viu. El primer pas és llançar la càmera i capturar el vídeo. A continuació, transformarem la imatge en una imatge d’escala de grisos. S'utilitza per reduir la dimensió de la imatge d'entrada. De fet, en lloc de 3 punts per píxel que descriuen el vermell, el verd i el blau, apliquem una simple transformació lineal:

Això s’implementa per defecte a OpenCV.

video_capture = cv2.VideoCapture(0) while True: # Capture frame-by-frame ret, frame = video_capture.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

Ara farem servir el faceCascade variable definida anteriorment, que conté un algoritme entrenat prèviament, i apliqueu-la a la imatge d'escala de grisos.

faces = faceCascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE )

Per a cada cara detectada, dibuixarem un rectangle al voltant de la cara:

for (x, y, w, h) in faces: if w > 250 : cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3) roi_gray = gray[y:y+h, x:x+w] roi_color = frame[y:y+h, x:x+w]

Per a cada boca detectada, dibuixa un rectangle al seu voltant:

smile = smileCascade.detectMultiScale( roi_gray, scaleFactor= 1.16, minNeighbors=35, minSize=(25, 25), flags=cv2.CASCADE_SCALE_IMAGE ) for (sx, sy, sw, sh) in smile: cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2) cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1)

Per a cada ull detectat, dibuixa un rectangle al seu voltant:

eyes = eyeCascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1)

A continuació, compteu el nombre total de cares i mostreu la imatge general:

cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2) # Display the resulting frame cv2.imshow('Video', frame)

I implementeu una opció de sortida quan volem aturar la càmera prement q :

if cv2.waitKey(1) & 0xFF == ord('q'): break

Finalment, quan tot estigui acabat, deixeu anar la captura i destruiu totes les finestres. Hi ha alguns problemes per eliminar Windows a Mac, que poden requerir matar Python des del Gestor d’activitats més endavant.

video_capture.release() cv2.destroyAllWindows()

I.5. Embolicant-lo

import cv2 cascPath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml' eyePath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml' smilePath = '/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml' faceCascade = cv2.CascadeClassifier(cascPath) eyeCascade = cv2.CascadeClassifier(eyePath) smileCascade = cv2.CascadeClassifier(smilePath) font = cv2.FONT_HERSHEY_SIMPLEX video_capture = cv2.VideoCapture(0) while True: # Capture frame-by-frame ret, frame = video_capture.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(200, 200), flags=cv2.CASCADE_SCALE_IMAGE ) # Draw a rectangle around the faces for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3) roi_gray = gray[y:y+h, x:x+w] roi_color = frame[y:y+h, x:x+w] cv2.putText(frame,'Face',(x, y), font, 2,(255,0,0),5) smile = smileCascade.detectMultiScale( roi_gray, scaleFactor= 1.16, minNeighbors=35, minSize=(25, 25), flags=cv2.CASCADE_SCALE_IMAGE ) for (sx, sy, sw, sh) in smile: cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2) cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1) eyes = eyeCascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1) cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2) # Display the resulting frame cv2.imshow('Video', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # When everything is done, release the capture video_capture.release() cv2.destroyAllWindows()

I.6. Resultats

He fet un ràpid YouTube il·lustració de l'algorisme de detecció de cares.

II. Histograma de gradients orientats (HOG) a Dlib

Dlib ofereix el segon instrument més popular per a la detecció de cares i utilitza un concepte anomenat Histograma de gradients orientats (HOG). Es tracta d’una implementació de l’original paper de Dalal i Triggs .

II.1. Teoria

La idea darrere de HOG és extreure característiques en un vector i alimentar-les en un algorisme de classificació, com ara una màquina vectorial de suport, que avaluarà si una cara (o qualsevol objecte que l’entreni per reconèixer realment) estigui present o no en una regió. .

Les característiques extretes són la distribució (histogrames) de les direccions dels gradients (gradients orientats) de la imatge. Els degradats solen ser grans al voltant de les vores i les cantonades i ens permeten detectar aquestes regions.

Al document original, el procés es va implementar per a la detecció del cos humà i la cadena de detecció era la següent:

II.1.a. Preprocessament

En primer lloc, les imatges d’entrada han de tenir la mateixa mida (retallar i redimensionar les imatges). Els pegats que aplicarem requereixen una relació d'aspecte d'1: 2, de manera que les dimensions de les imatges d'entrada poden ser 64x128 o 100x200 per exemple.

II.1.b. Calculeu les imatges de degradat

El primer pas és calcular els gradients horitzontals i verticals de la imatge aplicant els nuclis següents:

Nuclis per calcular els degradats

El gradient d’una imatge sol eliminar informació no essencial.

El gradient de la imatge que estàvem considerant més amunt es pot trobar d'aquesta manera a Python:

gray = cv2.imread('images/face_detect_test.jpeg'>

We have not pre-processed the image before though.

II.1.c. Compute the HOG

The image is then divided into 8x8 cells to offer a compact representation and make our HOG more robust to noise. Then, we compute a HOG for each of those cells.

To estimate the direction of a gradient inside a region, we simply build a histogram among the 64 values of the gradient directions (8x8) and their magnitude (another 64 values) inside each region. The categories of the histogram correspond to angles of the gradient, from 0 to 180°. Ther are 9 categories overall : 0°, 20°, 40°… 160°.

The code above gave us 2 information :

  • direction of the gradient

  • and magnitude of the gradient

When we build the HOG, there are 3 subcases :

  • the angle is smaller than 160° and not halfway between 2 classes. In such case, the angle will be added in the right category of the HOG

  • the angle is smaller than 160° and exactly between 2 classes. In such case, we consider an equal contribution to the 2 nearest classes and split the magnitude in 2

  • the angle is larger than 160°. In such case, we consider that the pixel contributed proportionally to 160° and to 0°.

The HOG looks like this for each 8x8 cell :

HoG

II.1.d. Block normalization

Finally, a 16x16 block can be applied in order to normalize the image and make it invariant to lighting for example. This is simply achieved by dividing each value of the HOG of size 8x8 by the L2-norm of the HOG of the 16x16 block that contains it, which is in fact a simple vector of length 9*4 = 36

II.3. Detecció de cares en temps real

Com anteriorment, l'algorisme és bastant fàcil d'implementar. També implementem una versió més lleugera detectant només la cara. Dlib també fa que sigui molt fàcil detectar els punts clau de la cara, però és un altre tema.

face_detect = dlib.get_frontal_face_detector() rects = face_detect(gray, 1) for (i, rect) in enumerate(rects): (x, y, w, h) = face_utils.rect_to_bb(rect) cv2.rectangle(gray, (x, y), (x + w, y + h), (255, 255, 255), 3) plt.figure(figsize=(12,8)) plt.imshow(gray, cmap='gray') plt.show()

III. Xarxa Neural Convolucional a Dlib

Aquest darrer mètode es basa en xarxes neuronals convolucionals (CNN). També implementa un fitxer paper a la detecció d'objectes de marge màxim (MMOD) per obtenir resultats millorats.

què és la representació progressiva

III.1. Una mica de teoria

La Xarxa Neural Convolucional (CNN) és una xarxa neuronal que s’utilitza principalment per a la visió per ordinador. Ofereixen un tractament previ automatitzat de la imatge i una part densa de la xarxa neuronal. Les CNN són tipus especials de xarxes neuronals per al processament de dades amb topologia semblant a una quadrícula. L’arquitectura de la CNN s’inspira en l’escorça visual dels animals.

En enfocaments anteriors, una gran part del treball consistia a seleccionar els filtres per tal de crear les funcions per tal d’extreure la major informació possible de la imatge. Amb l’augment de l’aprenentatge profund i les capacitats de càlcul més grans, aquest treball ja es pot automatitzar. El nom de les xarxes CNN prové del fet que combinem l'entrada inicial de la imatge amb un conjunt de filtres. El paràmetre a triar continua sent el nombre de filtres a aplicar i la dimensió dels filtres. La dimensió del filtre s’anomena longitud del pas. Els valors típics del pas es troben entre 2 i 5.

La sortida de la CNN en aquest cas específic és una classificació binària, que pren el valor 1 si hi ha una cara, 0 en cas contrari.

III.2. Detecta la cara en una imatge

Alguns elements canvien en la implementació.

El primer pas és descarregar el model pre-entrenat aquí . Moveu els pesos a la vostra carpeta i definiu video_capture = cv2.VideoCapture(0) flag = 0 while True: ret, frame = video_capture.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) rects = face_detect(gray, 1) for (i, rect) in enumerate(rects): (x, y, w, h) = face_utils.rect_to_bb(rect) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow('Video', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break video_capture.release() cv2.destroyAllWindows() :

dnnDaceDetector

Aleshores, de manera similar al que hem fet fins ara:

dnnFaceDetector = dlib.cnn_face_detection_model_v1('mmod_human_face_detector.dat')

III.3. Detecció de cares en temps real

Finalment, implementarem la versió en temps real de la detecció de cares CNN:

rects = dnnFaceDetector(gray, 1) for (i, rect) in enumerate(rects): x1 = rect.rect.left() y1 = rect.rect.top() x2 = rect.rect.right() y2 = rect.rect.bottom() # Rectangle around the face cv2.rectangle(gray, (x1, y1), (x2, y2), (255, 255, 255), 3) plt.figure(figsize=(12,8)) plt.imshow(gray, cmap='gray') plt.show()

IV. Quina triar?

És una pregunta difícil, però només passarem per dues mètriques importants:

Pel que fa a la velocitat, HoG sembla ser l’algoritme més ràpid, seguit del classificador Haar Cascade i les CNN.

No obstant això, les xarxes CNN de Dlib solen ser l'algorisme més precís. HoG té un bon rendiment, però té problemes per identificar les cares petites. Els classificadors HaarCascade tenen un rendiment tan bo com el HoG en general.

Personalment he utilitzat principalment HoG en els meus projectes personals a causa de la seva rapidesa per a la detecció de cares en viu.

Es pot trobar el dipòsit Github d’aquest article aquí .

Conclusió : Espero que us hagi agradat aquest tutorial ràpid sobre OpenCV i Dlib per a la detecció de cares. No dubteu a deixar cap comentari si teniu alguna pregunta / comentari.

V. Fonts:

  • HOG
  • DLIB
  • Viola-Jones Paper
  • Detecció de cares 1
  • Detecció de cares 2
  • Detecció de cares 3
  • DetectMultiScale
  • Viola-Jones

Aquest article es va publicar originalment en aquest bloc: https://maelfabien.github.io/tutorials/face-detection/#

============================================

Gràcies per llegir

Si us ha agradat aquest missatge, compartiu-lo amb tots els vostres amics de programació.

Segueix-nos a Facebook | Twitter

Per llegir més

Completa Python Bootcamp: passa de zero a heroi a Python 3

Machine Learning A-Z ™: Python i R pràctics en ciència de dades

Python i Django Full Stack Developer Web Bootcamp

Classe magistral completa de Python

Tutorial de programació de Python | Curs complet de Python per a principiants 2019

Els 10 marcs Python principals per al desenvolupament web el 2019

☞ Python per a l’anàlisi financera i el comerç algorítmic

Construint un rascador web simultani amb Python i Selenium

#python #opencv # machine-learning