Распознавание лица
Файлы проекта
sketch.ino
#include <Arduino.h>
#include <WebSocketsServer.h>
#include <WiFi.h>
#include "camera.h"
#include "img_converters.h"
#include "FaceFinder.h"
// логин-пароль WiFi
#define AP_SSID ""
#define AP_PASS ""
WebSocketsServer ws(82, "", "hub");
FaceFinder face;
void setup() {
Serial.begin(115200);
delay(200);
cam_init(FRAMESIZE_VGA, PIXFORMAT_JPEG, 10);
WiFi.mode(WIFI_STA);
WiFi.begin(AP_SSID, AP_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println(WiFi.localIP());
ws.begin();
}
void loop() {
ws.loop();
//if (!ws.connectedClients()) return;
camera_fb_t *fbj = nullptr;
fbj = esp_camera_fb_get();
esp_camera_fb_return(fbj);
fbj = nullptr;
fbj = esp_camera_fb_get();
if (fbj) {
uint32_t len = fbj->width * fbj->height * 2;
uint8_t *buf = (uint8_t *)ps_malloc(len);
if (buf) {
bool ok = jpg2rgb565(fbj->buf, fbj->len, buf, JPG_SCALE_NONE);
if (ok) {
// swap low->high byte
for (uint32_t i = 0; i < len; i += 2) {
uint8_t b = buf[i];
buf[i] = buf[i + 1];
buf[i + 1] = b;
}
face.find(buf, fbj->width, fbj->height, true, 0);
if (face.found) Serial.printf("%d,%d,%d,%d\n", face.x, face.y, face.w, face.h);
if (ws.connectedClients()) {
size_t jpg_buf_len = 0;
uint8_t *jpg_buf = nullptr;
ok = fmt2jpg(buf, len, fbj->width, fbj->height, PIXFORMAT_RGB565, 80, &jpg_buf, &jpg_buf_len);
if (ok) ws.broadcastBIN(jpg_buf, jpg_buf_len);
if (jpg_buf) free(jpg_buf);
}
}
free(buf);
}
}
esp_camera_fb_return(fbj);
delay(30);
}
camera.h
#pragma once
#define CAMERA_MODEL_AI_THINKER
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WITHOUT_PSRAM
#include "esp_camera.h"
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_M5STACK_WITHOUT_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#else
#error "Camera model not selected"
#endif
bool cam_init(framesize_t frame_size = FRAMESIZE_VGA, pixformat_t pixel_format = PIXFORMAT_JPEG, int jpeg_quality = 12) {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = pixel_format;
config.frame_size = frame_size;
config.jpeg_quality = jpeg_quality;
config.fb_count = 1;
esp_err_t result = esp_camera_init(&config);
return (result == ESP_OK);
}
FaceFinder.h
#pragma once
#include <Arduino.h>
#include <vector>
#include "fb_gfx.h"
// HUMAN
#include "human_face_detect_mnp01.hpp"
#include "human_face_detect_msr01.hpp"
// CAT
// #include "cat_face_detect_mn03.hpp"
class FaceFinder {
public:
bool find(uint8_t *buf565, uint16_t width, uint16_t height, bool draw = true, bool fill = false) {
found = 0;
frame_w = width;
frame_h = height;
{
// HUMAN
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 2, 0.3F);
HumanFaceDetectMNP01 s2(0.4F, 0.3F, 1);
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)buf565, {height, width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)buf565, {height, width, 3}, candidates);
// CAT
// CatFaceDetectMN03 cat(0.4F, 0.3F, 10, 0.3F);
// std::list<dl::detect::result_t> &results = cat.infer((uint16_t *)buf565, {height, width, 3});
if (!results.size()) return 0;
std::list<dl::detect::result_t>::iterator prediction = results.begin();
x = (int)prediction->box[0];
y = (int)prediction->box[1];
w = (int)prediction->box[2] - x + 1;
h = (int)prediction->box[3] - y + 1;
if ((x + w) > width) w = width - x;
if ((y + h) > height) h = height - y;
results.end();
}
if (draw) {
fb_data_t fbd;
fbd.width = width;
fbd.height = height;
fbd.data = buf565;
fbd.bytes_per_pixel = 2;
fbd.format = FB_RGB565;
uint32_t color = 0b1111100000000000;
if (fill) {
fb_gfx_fillRect(&fbd, x, y, w, h, color);
} else {
fb_gfx_drawFastHLine(&fbd, x, y, w, color);
fb_gfx_drawFastHLine(&fbd, x, y + h - 1, w, color);
fb_gfx_drawFastVLine(&fbd, x, y, h, color);
fb_gfx_drawFastVLine(&fbd, x + w - 1, y, h, color);
}
}
found = 1;
return 1;
}
int16_t x, y, w, h;
uint16_t frame_w, frame_h;
bool found = 0;
};
Для просмотра результата нужно создать html файл со следующим содержимым, открыть его в браузере и ввести IP адрес платы
stream.html
<!DOCTYPE html>
<body>
<input id="ip" type="text" value="192.168.1.6"><br>
<button onclick="connect()">START</button>
<button onclick="wsclose()">STOP</button>
<div id="log_inner"></div>
<br>
<img id="img">
<script>
let ws = null;
let flag = false;
function connect() {
flag = true;
ws = new WebSocket(`ws://${ip.value}:82/`, ['hub']);
console.log('open...');
ws.onopen = function () {
console.log('opened');
};
ws.onclose = function () {
console.log('close');
ws = null;
if (flag) {
setTimeout(connect, 1000);
console.log('reconnect');
}
};
ws.onmessage = function (e) {
document.getElementById('img').src = URL.createObjectURL(e.data);
};
}
function send(text) {
if (ws && ws.readyState == 1) ws.send(text);
}
function wsclose() {
flag = false;
if (ws) ws.close();
}
</script>
</body>
</html>