ESP32CAM 人臉識別追蹤


引言

  總體實現的流程:ESP32cam作為客戶端,pc作為服務端通過mqtt協議建立通信,將采集的圖像在電腦端顯示人臉識別的方法使用的是opencv,並通過mqtt傳輸指令給esp32cam控制舵機雲台轉動。

  客戶端程序

 

#include <WebServer.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <esp32cam.h>

const char* WIFI_SSID = "wifi的名稱";
const char* WIFI_PASS = "wifi的密碼";

WebServer server(80);

static auto loRes = esp32cam::Resolution::find(320, 240);
static auto hiRes = esp32cam::Resolution::find(800, 600);

void callback(char* topic, byte* payload, unsigned int length) ;

bool stopEngine = true;

//初始化mqtt類對象
WiFiClient espClient;
PubSubClient mqtt_client(espClient);

const char* mqttServer = "broker.emqx.io";
const int mqttPort = 1883;
const char* mqttUser = "";
const char* mqttPassword = "";

int servo_y = 8;
int servo_z = 9;
int servo_y_pin = 14;
int servo_z_pin = 13;
int pos_z = 90 , pos_y = 90;

void serveJpg()
{
  auto frame = esp32cam::capture();
  if (frame == nullptr) {
    Serial.println("CAPTURE FAIL");
    server.send(503, "", "");
    return;
  }
  //Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),
  //static_cast<int>(frame->size()));

  server.setContentLength(frame->size());
  server.send(200, "image/jpeg");
  WiFiClient client = server.client();
  frame->writeTo(client);
}

void handleJpgHi()
{
  if (!esp32cam::Camera.changeResolution(hiRes)) {
    Serial.println("SET-HI-RES FAIL");
  }
  serveJpg();
}

int calculatePWM( int degree)
{ 
  const float deadZone = 6.4;
  const float max = 32;
  if (degree < 0)
    degree = 0;
  if (degree > 180)
    degree = 180;
  return ( int)(((max - deadZone) / 180) * degree + deadZone);
}

void mqtt_connet(){
    mqtt_client.setServer(mqttServer,mqttPort);
    mqtt_client.setCallback(callback);
      while (!mqtt_client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (mqtt_client.connect(mqttServer, mqttUser, mqttPassword )) {

      Serial.println("connected");

    } else {

      Serial.print("failed with state ");
      Serial.print(mqtt_client.state());
      delay(2000);
    }
  }
  mqtt_client.subscribe("POSITION");
}
void callback(char* topic, byte* payload, unsigned int length) {
  String payloadStr = "";
  for (int i=0; i<length; i++) {
    payloadStr += (char)payload[i];
  }
  Serial.println(payloadStr);

  if(payloadStr.equals("RIGHT")){
    pos_z --;
  
  }else if(payloadStr.equals("LEFT")){
    pos_z ++;
  }
  
  if(payloadStr.equals("UP")){  
    pos_y --;

  }else if(payloadStr.equals("DOWN")){
    pos_y ++;
  }

  if(pos_z >= 180) pos_z = 180;
  if(pos_z <= 0) pos_z = 0; 
  if(pos_y >= 180) pos_y = 180;
  if(pos_y <= 0) pos_y = 0; 
  Serial.printf("pos_z: %d pos_y: %d \n",pos_z,pos_y);
  ledcWrite(servo_z,calculatePWM(pos_z));
  ledcWrite(servo_y,calculatePWM(pos_y));
}

void setup()
{
  Serial.begin(115200);
  ledcSetup(servo_y, 50, 8); 
  ledcSetup(servo_z, 50, 8); 
  ledcAttachPin(servo_y_pin, servo_y);      
  ledcAttachPin(servo_z_pin, servo_z); 

  {
    using namespace esp32cam;
    Config cfg;
    cfg.setPins(pins::AiThinker);
    cfg.setResolution(hiRes);
    cfg.setBufferCount(2);
    cfg.setJpeg(80);

    bool ok = Camera.begin(cfg);
    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
  }

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  Serial.print("http://");
  Serial.println(WiFi.localIP());
  Serial.println("  /cam-hi.jpg");
  server.on("/cam-hi.jpg", handleJpgHi);
  mqtt_connet();
  server.begin();
}

void loop()
{
  server.handleClient();
  mqtt_client.loop();

}

 

服務端程序

import cv2
import time
import urllib.request
import numpy as np
import paho.mqtt.client as mqtt

url='http://192.168.0.106/cam-hi.jpg'
cv2.namedWindow("Berhasil", cv2.WINDOW_AUTOSIZE)
face=cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

mqttBroker = "broker.emqx.io"
client = mqtt.Client("Cleaning-Robot",clean_session=True,userdata=None)
client.connect(mqttBroker,1883)

while True:
    imgresponse=urllib.request.urlopen(url)
    start = time.time()
    imgnp=np.array(bytearray(imgresponse.read()),dtype=np.uint8)
    img=cv2.imdecode(imgnp,-1)
    rows , cols , _ = img.shape
    conter_x = (int)(rows / 2)
    conter_y = (int)(cols / 2)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    faces = face.detectMultiScale(gray,1.3,5)

    for (x,y,w,h) in faces:
        faces_conter_x = (int)(x + (w / 2)) 
        faces_conter_y = (int)(y + (h / 2))
        cv2.rectangle(img,(x,y), (x+w,y+h), (0,255,120),2)
        cv2.putText(img,"face",(w+x,y+h),cv2.FONT_HERSHEY_PLAIN,2,(0,255,255),2)

        if(faces_conter_x > conter_x):
            client.publish("POSITION","RIGHT")
            str_x = str(conter_x - faces_conter_x)
            print("RIGHT" + str_x)

        elif(faces_conter_x < conter_x):
            client.publish("POSITION","LEFT")
            str_x = str(faces_conter_y - conter_y)
            print("LEFT:" + str_x)

        if(faces_conter_y > conter_y):
            client.publish("POSITION","DOWN")
            str_y = str(conter_y - faces_conter_y)
            print("DOWN:" + str_y)

        elif(faces_conter_y < conter_y):
            client.publish("POSITION","UP")
            str_y = str(faces_conter_y - conter_y)
            print("UP:" + str_y)
        

    end = time.time()
    seconds = end - start  # 處理一幀所用的時間
    fps = 1 / seconds  # 一秒鍾可以處理多少幀
    fps = "%.2f fps"%fps
    cv2.putText(img, fps, (5,50 ), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 1)

    cv2.imshow("Berhasil",img)
    key=cv2.waitKey(30) & 0xff
    if key==27:
        break

cv2.destroyAllWindows

總結:舵機控制不穩定,可采用好的控制算法解決。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM