Face Tracker usando OpenCV y Arduino

Face Tracker usando OpenCV y Arduino © GPL3+

Rastree su rostro usando el reconocimiento facial de OpenCV.

Componentes y suministros

Ph a000066 iso (1) ztbmubhmho
Arduino UNO
× 1
cámara USB
× 1
SG90 180 grados SG90 micro servo
Micro servomotor SG90
× 2
11026 02
Alambres de unión (genérico)
× 8
12002 04
Protoboard (genérico)
× 1

Aplicaciones y servicios en línea

Pitón 3.8
idea web
IDE de Arduino
73318 301258139977848 644841747 n
OpenCV

Acerca de este proyecto

El reconocimiento facial es una herramienta muy útil integrada en muchos dispositivos modernos para detectar rostros humanos con fines de seguimiento, biometría y reconocimiento de actividad humana. En este proyecto, utilicé los clasificadores en cascada Harr de OpenCV para detectar rostros humanos y el servomecanismo de movimiento horizontal/vertical para rastrear el rostro del usuario usando Arduino UNO.

¿Cómo funciona?

La detección de rostros identifica y ubica rostros humanos e ignora todos los objetos de fondo, como cortinas, ventanas, árboles, etc. OpenCV usa la cascada de clasificadores de Harr donde cada fotograma del video pasa por etapas de clasificadores y si el fotograma pasa por todos los clasificadores, el rostro está presente; de ​​lo contrario, el fotograma se elimina del clasificador, es decir, el rostro no se detecta.

OpenCV devuelve las coordenadas cartesianas de la imagen tras la detección junto con la altura y el ancho. A partir de estas coordenadas, se pueden calcular las coordenadas del centro de la imagen usando x+ancho/2 e y+alto/2.

 

Estas coordenadas se pasan al Arduino UNO usando la biblioteca pyserial cuando se detecta la cara. El servo conectado al Arduino proporciona un mecanismo de giro/inclinación donde la cámara está conectada a uno de los servos. Cuando las coordenadas de la cara están alejadas del centro, el servo se alineará 2 grados (incremento o disminución) para devolverlo al centro de la pantalla.

detectar cara

He utilizado ‘haarcascade_frontalface_default.xml’ que es un modelo preentrenado para detectar rostros humanos y se puede descargar desde Git-Hub(aquí). Al descargar, el archivo xml se puede cargar usando cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

La función utilizada para la detección de rostros es cv2.CascadeClassifier.detectMultiScale() con valor de ‘factor de escala’ en 1.1 (predeterminado) y valor de ‘minNeighbour’ en 6. Esto devuelve las coordenadas cartesianas de la imagen con alto y ancho. El aumento de ‘minNeighbour’ puede mejorar la detección de rostros pero sacrificar las velocidades de tiempo de ejecución, lo que daría como resultado una respuesta servo retrasada. Por lo tanto, el valor 6 parecía óptimo.

Para tener un reconocimiento facial preciso, se recomendaría un fondo liso ya que me enfrenté a una detección falsa debido a las cortinas en el fondo.

Cálculo de coordenadas

OpenCV devuelve las coordenadas de la cara en términos de valores de píxeles. De manera predeterminada, la resolución de video se establece en 640*480. Las coordenadas describen los valores de píxel superior izquierdo (x e y), así como la altura y el ancho. Usé las coordenadas del centro de la cara como referencia y puedo calcularlo usando x+ancho/2 y y+alto/2 y puedo verlo como un punto verde. Estas coordenadas se envían al arduino para mover el ángulo de la cámara.

El cuadrado en el centro del marco blanco describe el área en la que debería estar el centro de la cara, es decir, el punto verde. Si está fuera de la región cuadrada cuando se mueve la cara, el servo alineará la cámara para llevarla dentro de la región.

 

Enviar datos en serie a Arduino

Encontré esta parte difícil porque probé muchas formas de enviar las coordenadas secuencialmente al arduino, pero la respuesta fue lenta. Después de pasar horas averiguándolo, comencé a buscar proyectos similares en línea hasta que encontré este proyecto (aquí). Esto me hizo consciente de la función Serial Serial.parseInt() que toma entradas enteras de una serie entrante de bytes. Mi enfoque para enviar datos en serie es similar al que se usa en este proyecto.

Python envía las coordenadas del centro en una sola cadena. Por ejemplo: «X100Y200», el valor 100 después de X representa la coordenada x central y 200 representa la coordenada y central.

Diseño de servos

Adjunté el servo de cambio horizontal al eje del servo de cambio vertical en el que está montada la cámara. Todos los archivos adjuntos están hechos con bandas de goma simples (no lo recomendaría ya que usé material existente disponible en casa).

 

Como estoy usando 2 servos para el seguimiento, se recomendaría un suministro adicional de 9 V (a través de un adaptador) al Arduino para proporcionar suficiente corriente para ambos servos. En su ausencia noté en ellos una especie de vibración sin que se movieran.

bibliotecas e instalaciones

Este proyecto requiere pisérico y opencv bibliotecas que descargué usando pip. Mi versión actual de python y OpenCV es 3.8 y 4.4.0, así que asegúrese de tener una versión similar o superior. También asegúrese de que el archivo XML para la detección de rostros esté guardado en el mismo directorio que contiene el script de python.

El script de python también requiere alguna modificación (en la línea 9) ingresando el puerto COM correcto de su arduino antes de la ejecución.

Aquí hay un video (gif) capturado por la cámara que sigue mi rostro.

codificado

codigo arduinoarduino
//Face Tracker using OpenCV and Arduino
//by Shubham Santosh

#include<Servo.h>

Servo x, y;
int width = 640, height = 480;  // total resolution of the video
int xpos = 90, ypos = 90;  // initial positions of both Servos
void setup() {

  Serial.begin(9600);
  x.attach(9);
  y.attach(10);
  // Serial.print(width);
  //Serial.print("\t");
  //Serial.println(height);
  x.write(xpos);
  y.write(ypos);
}
const int angle = 2;   // degree of increment or decrement

void loop() {
  if (Serial.available() > 0)
  {
    int x_mid, y_mid;
    if (Serial.read() == 'X')
    {
      x_mid = Serial.parseInt();  // read center x-coordinate
      if (Serial.read() == 'Y')
        y_mid = Serial.parseInt(); // read center y-coordinate
    }
    /* adjust the servo within the squared region if the coordinates
        is outside it
    */
    if (x_mid > width / 2 + 30)
      xpos += angle;
    if (x_mid < width / 2 - 30)
      xpos -= angle;
    if (y_mid < height / 2 + 30)
      ypos -= angle;
    if (y_mid > height / 2 - 30)
      ypos += angle;


    // if the servo degree is outside its range
    if (xpos >= 180)
      xpos = 180;
    else if (xpos <= 0)
      xpos = 0;
    if (ypos >= 180)
      ypos = 180;
    else if (ypos <= 0)
      ypos = 0;

    x.write(xpos);
    y.write(ypos);

    // used for testing
    //Serial.print("\t");
    // Serial.print(x_mid);
    // Serial.print("\t");
    // Serial.println(y_mid);
  }
}
secuencias de comandos de PythonPitón
#Face tracker using OpenCV and Arduino
#by Shubham Santosh

import cv2
import serial,time
face_cascade= cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap=cv2.VideoCapture(1)
#fourcc= cv2.VideoWriter_fourcc(*'XVID')
ArduinoSerial=serial.Serial('com7',9600,timeout=0.1)
#out= cv2.VideoWriter('face detection4.avi',fourcc,20.0,(640,480))
time.sleep(1)

while cap.isOpened():
    ret, frame= cap.read()
    frame=cv2.flip(frame,1)  #mirror the image
    #print(frame.shape)
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    faces= face_cascade.detectMultiScale(gray,1.1,6)  #detect the face
    for x,y,w,h in faces:
        #sending coordinates to Arduino
        string='X{0:d}Y{1:d}'.format((x+w//2),(y+h//2))
        print(string)
        ArduinoSerial.write(string.encode('utf-8'))
        #plot the center of the face
        cv2.circle(frame,(x+w//2,y+h//2),2,(0,255,0),2)
        #plot the roi
        cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),3)
    #plot the squared region in the center of the screen
    cv2.rectangle(frame,(640//2-30,480//2-30),
                 (640//2+30,480//2+30),
                  (255,255,255),3)
    #out.write(frame)
    cv2.imshow('img',frame)
    #cv2.imwrite('output_img.jpg',frame)
    '''for testing purpose
    read= str(ArduinoSerial.readline(ArduinoSerial.inWaiting()))
    time.sleep(0.05)
    print('data from arduino:'+read)
    '''
    # press q to Quit
    if cv2.waitKey(10)&0xFF== ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

diagramas

Esquemático
Conecte una fuente de alimentación adicional de 9V a Arduino.
rastreador facial bb bova3qa9oa

Fuente Arduino.cc