Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 75aa60f

Browse files
committedJun 25, 2020
Copy example files from the esp32 package:
cp ~/.arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/ESP32/examples/Camera/CameraWebServer/* ./
1 parent 1bc07a7 commit 75aa60f

File tree

4 files changed

+1425
-0
lines changed

4 files changed

+1425
-0
lines changed
 

‎CameraWebServer.ino

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include "esp_camera.h"
2+
#include <WiFi.h>
3+
4+
//
5+
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
6+
// or another board which has PSRAM enabled
7+
//
8+
9+
// Select camera model
10+
#define CAMERA_MODEL_WROVER_KIT
11+
//#define CAMERA_MODEL_ESP_EYE
12+
//#define CAMERA_MODEL_M5STACK_PSRAM
13+
//#define CAMERA_MODEL_M5STACK_WIDE
14+
//#define CAMERA_MODEL_AI_THINKER
15+
16+
#include "camera_pins.h"
17+
18+
const char* ssid = "*********";
19+
const char* password = "*********";
20+
21+
void startCameraServer();
22+
23+
void setup() {
24+
Serial.begin(115200);
25+
Serial.setDebugOutput(true);
26+
Serial.println();
27+
28+
camera_config_t config;
29+
config.ledc_channel = LEDC_CHANNEL_0;
30+
config.ledc_timer = LEDC_TIMER_0;
31+
config.pin_d0 = Y2_GPIO_NUM;
32+
config.pin_d1 = Y3_GPIO_NUM;
33+
config.pin_d2 = Y4_GPIO_NUM;
34+
config.pin_d3 = Y5_GPIO_NUM;
35+
config.pin_d4 = Y6_GPIO_NUM;
36+
config.pin_d5 = Y7_GPIO_NUM;
37+
config.pin_d6 = Y8_GPIO_NUM;
38+
config.pin_d7 = Y9_GPIO_NUM;
39+
config.pin_xclk = XCLK_GPIO_NUM;
40+
config.pin_pclk = PCLK_GPIO_NUM;
41+
config.pin_vsync = VSYNC_GPIO_NUM;
42+
config.pin_href = HREF_GPIO_NUM;
43+
config.pin_sscb_sda = SIOD_GPIO_NUM;
44+
config.pin_sscb_scl = SIOC_GPIO_NUM;
45+
config.pin_pwdn = PWDN_GPIO_NUM;
46+
config.pin_reset = RESET_GPIO_NUM;
47+
config.xclk_freq_hz = 20000000;
48+
config.pixel_format = PIXFORMAT_JPEG;
49+
//init with high specs to pre-allocate larger buffers
50+
if(psramFound()){
51+
config.frame_size = FRAMESIZE_UXGA;
52+
config.jpeg_quality = 10;
53+
config.fb_count = 2;
54+
} else {
55+
config.frame_size = FRAMESIZE_SVGA;
56+
config.jpeg_quality = 12;
57+
config.fb_count = 1;
58+
}
59+
60+
#if defined(CAMERA_MODEL_ESP_EYE)
61+
pinMode(13, INPUT_PULLUP);
62+
pinMode(14, INPUT_PULLUP);
63+
#endif
64+
65+
// camera init
66+
esp_err_t err = esp_camera_init(&config);
67+
if (err != ESP_OK) {
68+
Serial.printf("Camera init failed with error 0x%x", err);
69+
return;
70+
}
71+
72+
sensor_t * s = esp_camera_sensor_get();
73+
//initial sensors are flipped vertically and colors are a bit saturated
74+
if (s->id.PID == OV3660_PID) {
75+
s->set_vflip(s, 1);//flip it back
76+
s->set_brightness(s, 1);//up the blightness just a bit
77+
s->set_saturation(s, -2);//lower the saturation
78+
}
79+
//drop down frame size for higher initial frame rate
80+
s->set_framesize(s, FRAMESIZE_QVGA);
81+
82+
#if defined(CAMERA_MODEL_M5STACK_WIDE)
83+
s->set_vflip(s, 1);
84+
s->set_hmirror(s, 1);
85+
#endif
86+
87+
WiFi.begin(ssid, password);
88+
89+
while (WiFi.status() != WL_CONNECTED) {
90+
delay(500);
91+
Serial.print(".");
92+
}
93+
Serial.println("");
94+
Serial.println("WiFi connected");
95+
96+
startCameraServer();
97+
98+
Serial.print("Camera Ready! Use 'http://");
99+
Serial.print(WiFi.localIP());
100+
Serial.println("' to connect");
101+
}
102+
103+
void loop() {
104+
// put your main code here, to run repeatedly:
105+
delay(10000);
106+
}

‎app_httpd.cpp

Lines changed: 662 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,662 @@
1+
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
#include "esp_http_server.h"
15+
#include "esp_timer.h"
16+
#include "esp_camera.h"
17+
#include "img_converters.h"
18+
#include "camera_index.h"
19+
#include "Arduino.h"
20+
21+
#include "fb_gfx.h"
22+
#include "fd_forward.h"
23+
#include "fr_forward.h"
24+
25+
#define ENROLL_CONFIRM_TIMES 5
26+
#define FACE_ID_SAVE_NUMBER 7
27+
28+
#define FACE_COLOR_WHITE 0x00FFFFFF
29+
#define FACE_COLOR_BLACK 0x00000000
30+
#define FACE_COLOR_RED 0x000000FF
31+
#define FACE_COLOR_GREEN 0x0000FF00
32+
#define FACE_COLOR_BLUE 0x00FF0000
33+
#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN)
34+
#define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN)
35+
#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED)
36+
37+
typedef struct {
38+
size_t size; //number of values used for filtering
39+
size_t index; //current value index
40+
size_t count; //value count
41+
int sum;
42+
int * values; //array to be filled with values
43+
} ra_filter_t;
44+
45+
typedef struct {
46+
httpd_req_t *req;
47+
size_t len;
48+
} jpg_chunking_t;
49+
50+
#define PART_BOUNDARY "123456789000000000000987654321"
51+
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
52+
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
53+
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
54+
55+
static ra_filter_t ra_filter;
56+
httpd_handle_t stream_httpd = NULL;
57+
httpd_handle_t camera_httpd = NULL;
58+
59+
static mtmn_config_t mtmn_config = {0};
60+
static int8_t detection_enabled = 0;
61+
static int8_t recognition_enabled = 0;
62+
static int8_t is_enrolling = 0;
63+
static face_id_list id_list = {0};
64+
65+
static ra_filter_t * ra_filter_init(ra_filter_t * filter, size_t sample_size){
66+
memset(filter, 0, sizeof(ra_filter_t));
67+
68+
filter->values = (int *)malloc(sample_size * sizeof(int));
69+
if(!filter->values){
70+
return NULL;
71+
}
72+
memset(filter->values, 0, sample_size * sizeof(int));
73+
74+
filter->size = sample_size;
75+
return filter;
76+
}
77+
78+
static int ra_filter_run(ra_filter_t * filter, int value){
79+
if(!filter->values){
80+
return value;
81+
}
82+
filter->sum -= filter->values[filter->index];
83+
filter->values[filter->index] = value;
84+
filter->sum += filter->values[filter->index];
85+
filter->index++;
86+
filter->index = filter->index % filter->size;
87+
if (filter->count < filter->size) {
88+
filter->count++;
89+
}
90+
return filter->sum / filter->count;
91+
}
92+
93+
static void rgb_print(dl_matrix3du_t *image_matrix, uint32_t color, const char * str){
94+
fb_data_t fb;
95+
fb.width = image_matrix->w;
96+
fb.height = image_matrix->h;
97+
fb.data = image_matrix->item;
98+
fb.bytes_per_pixel = 3;
99+
fb.format = FB_BGR888;
100+
fb_gfx_print(&fb, (fb.width - (strlen(str) * 14)) / 2, 10, color, str);
101+
}
102+
103+
static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *format, ...){
104+
char loc_buf[64];
105+
char * temp = loc_buf;
106+
int len;
107+
va_list arg;
108+
va_list copy;
109+
va_start(arg, format);
110+
va_copy(copy, arg);
111+
len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg);
112+
va_end(copy);
113+
if(len >= sizeof(loc_buf)){
114+
temp = (char*)malloc(len+1);
115+
if(temp == NULL) {
116+
return 0;
117+
}
118+
}
119+
vsnprintf(temp, len+1, format, arg);
120+
va_end(arg);
121+
rgb_print(image_matrix, color, temp);
122+
if(len > 64){
123+
free(temp);
124+
}
125+
return len;
126+
}
127+
128+
static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, int face_id){
129+
int x, y, w, h, i;
130+
uint32_t color = FACE_COLOR_YELLOW;
131+
if(face_id < 0){
132+
color = FACE_COLOR_RED;
133+
} else if(face_id > 0){
134+
color = FACE_COLOR_GREEN;
135+
}
136+
fb_data_t fb;
137+
fb.width = image_matrix->w;
138+
fb.height = image_matrix->h;
139+
fb.data = image_matrix->item;
140+
fb.bytes_per_pixel = 3;
141+
fb.format = FB_BGR888;
142+
for (i = 0; i < boxes->len; i++){
143+
// rectangle box
144+
x = (int)boxes->box[i].box_p[0];
145+
y = (int)boxes->box[i].box_p[1];
146+
w = (int)boxes->box[i].box_p[2] - x + 1;
147+
h = (int)boxes->box[i].box_p[3] - y + 1;
148+
fb_gfx_drawFastHLine(&fb, x, y, w, color);
149+
fb_gfx_drawFastHLine(&fb, x, y+h-1, w, color);
150+
fb_gfx_drawFastVLine(&fb, x, y, h, color);
151+
fb_gfx_drawFastVLine(&fb, x+w-1, y, h, color);
152+
#if 0
153+
// landmark
154+
int x0, y0, j;
155+
for (j = 0; j < 10; j+=2) {
156+
x0 = (int)boxes->landmark[i].landmark_p[j];
157+
y0 = (int)boxes->landmark[i].landmark_p[j+1];
158+
fb_gfx_fillRect(&fb, x0, y0, 3, 3, color);
159+
}
160+
#endif
161+
}
162+
}
163+
164+
static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_boxes){
165+
dl_matrix3du_t *aligned_face = NULL;
166+
int matched_id = 0;
167+
168+
aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
169+
if(!aligned_face){
170+
Serial.println("Could not allocate face recognition buffer");
171+
return matched_id;
172+
}
173+
if (align_face(net_boxes, image_matrix, aligned_face) == ESP_OK){
174+
if (is_enrolling == 1){
175+
int8_t left_sample_face = enroll_face(&id_list, aligned_face);
176+
177+
if(left_sample_face == (ENROLL_CONFIRM_TIMES - 1)){
178+
Serial.printf("Enrolling Face ID: %d\n", id_list.tail);
179+
}
180+
Serial.printf("Enrolling Face ID: %d sample %d\n", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
181+
rgb_printf(image_matrix, FACE_COLOR_CYAN, "ID[%u] Sample[%u]", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
182+
if (left_sample_face == 0){
183+
is_enrolling = 0;
184+
Serial.printf("Enrolled Face ID: %d\n", id_list.tail);
185+
}
186+
} else {
187+
matched_id = recognize_face(&id_list, aligned_face);
188+
if (matched_id >= 0) {
189+
Serial.printf("Match Face ID: %u\n", matched_id);
190+
rgb_printf(image_matrix, FACE_COLOR_GREEN, "Hello Subject %u", matched_id);
191+
} else {
192+
Serial.println("No Match Found");
193+
rgb_print(image_matrix, FACE_COLOR_RED, "Intruder Alert!");
194+
matched_id = -1;
195+
}
196+
}
197+
} else {
198+
Serial.println("Face Not Aligned");
199+
//rgb_print(image_matrix, FACE_COLOR_YELLOW, "Human Detected");
200+
}
201+
202+
dl_matrix3du_free(aligned_face);
203+
return matched_id;
204+
}
205+
206+
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
207+
jpg_chunking_t *j = (jpg_chunking_t *)arg;
208+
if(!index){
209+
j->len = 0;
210+
}
211+
if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
212+
return 0;
213+
}
214+
j->len += len;
215+
return len;
216+
}
217+
218+
static esp_err_t capture_handler(httpd_req_t *req){
219+
camera_fb_t * fb = NULL;
220+
esp_err_t res = ESP_OK;
221+
int64_t fr_start = esp_timer_get_time();
222+
223+
fb = esp_camera_fb_get();
224+
if (!fb) {
225+
Serial.println("Camera capture failed");
226+
httpd_resp_send_500(req);
227+
return ESP_FAIL;
228+
}
229+
230+
httpd_resp_set_type(req, "image/jpeg");
231+
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
232+
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
233+
234+
size_t out_len, out_width, out_height;
235+
uint8_t * out_buf;
236+
bool s;
237+
bool detected = false;
238+
int face_id = 0;
239+
if(!detection_enabled || fb->width > 400){
240+
size_t fb_len = 0;
241+
if(fb->format == PIXFORMAT_JPEG){
242+
fb_len = fb->len;
243+
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
244+
} else {
245+
jpg_chunking_t jchunk = {req, 0};
246+
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
247+
httpd_resp_send_chunk(req, NULL, 0);
248+
fb_len = jchunk.len;
249+
}
250+
esp_camera_fb_return(fb);
251+
int64_t fr_end = esp_timer_get_time();
252+
Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000));
253+
return res;
254+
}
255+
256+
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
257+
if (!image_matrix) {
258+
esp_camera_fb_return(fb);
259+
Serial.println("dl_matrix3du_alloc failed");
260+
httpd_resp_send_500(req);
261+
return ESP_FAIL;
262+
}
263+
264+
out_buf = image_matrix->item;
265+
out_len = fb->width * fb->height * 3;
266+
out_width = fb->width;
267+
out_height = fb->height;
268+
269+
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
270+
esp_camera_fb_return(fb);
271+
if(!s){
272+
dl_matrix3du_free(image_matrix);
273+
Serial.println("to rgb888 failed");
274+
httpd_resp_send_500(req);
275+
return ESP_FAIL;
276+
}
277+
278+
box_array_t *net_boxes = face_detect(image_matrix, &mtmn_config);
279+
280+
if (net_boxes){
281+
detected = true;
282+
if(recognition_enabled){
283+
face_id = run_face_recognition(image_matrix, net_boxes);
284+
}
285+
draw_face_boxes(image_matrix, net_boxes, face_id);
286+
free(net_boxes->score);
287+
free(net_boxes->box);
288+
free(net_boxes->landmark);
289+
free(net_boxes);
290+
}
291+
292+
jpg_chunking_t jchunk = {req, 0};
293+
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
294+
dl_matrix3du_free(image_matrix);
295+
if(!s){
296+
Serial.println("JPEG compression failed");
297+
return ESP_FAIL;
298+
}
299+
300+
int64_t fr_end = esp_timer_get_time();
301+
Serial.printf("FACE: %uB %ums %s%d\n", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start)/1000), detected?"DETECTED ":"", face_id);
302+
return res;
303+
}
304+
305+
static esp_err_t stream_handler(httpd_req_t *req){
306+
camera_fb_t * fb = NULL;
307+
esp_err_t res = ESP_OK;
308+
size_t _jpg_buf_len = 0;
309+
uint8_t * _jpg_buf = NULL;
310+
char * part_buf[64];
311+
dl_matrix3du_t *image_matrix = NULL;
312+
bool detected = false;
313+
int face_id = 0;
314+
int64_t fr_start = 0;
315+
int64_t fr_ready = 0;
316+
int64_t fr_face = 0;
317+
int64_t fr_recognize = 0;
318+
int64_t fr_encode = 0;
319+
320+
static int64_t last_frame = 0;
321+
if(!last_frame) {
322+
last_frame = esp_timer_get_time();
323+
}
324+
325+
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
326+
if(res != ESP_OK){
327+
return res;
328+
}
329+
330+
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
331+
332+
while(true){
333+
detected = false;
334+
face_id = 0;
335+
fb = esp_camera_fb_get();
336+
if (!fb) {
337+
Serial.println("Camera capture failed");
338+
res = ESP_FAIL;
339+
} else {
340+
fr_start = esp_timer_get_time();
341+
fr_ready = fr_start;
342+
fr_face = fr_start;
343+
fr_encode = fr_start;
344+
fr_recognize = fr_start;
345+
if(!detection_enabled || fb->width > 400){
346+
if(fb->format != PIXFORMAT_JPEG){
347+
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
348+
esp_camera_fb_return(fb);
349+
fb = NULL;
350+
if(!jpeg_converted){
351+
Serial.println("JPEG compression failed");
352+
res = ESP_FAIL;
353+
}
354+
} else {
355+
_jpg_buf_len = fb->len;
356+
_jpg_buf = fb->buf;
357+
}
358+
} else {
359+
360+
image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
361+
362+
if (!image_matrix) {
363+
Serial.println("dl_matrix3du_alloc failed");
364+
res = ESP_FAIL;
365+
} else {
366+
if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){
367+
Serial.println("fmt2rgb888 failed");
368+
res = ESP_FAIL;
369+
} else {
370+
fr_ready = esp_timer_get_time();
371+
box_array_t *net_boxes = NULL;
372+
if(detection_enabled){
373+
net_boxes = face_detect(image_matrix, &mtmn_config);
374+
}
375+
fr_face = esp_timer_get_time();
376+
fr_recognize = fr_face;
377+
if (net_boxes || fb->format != PIXFORMAT_JPEG){
378+
if(net_boxes){
379+
detected = true;
380+
if(recognition_enabled){
381+
face_id = run_face_recognition(image_matrix, net_boxes);
382+
}
383+
fr_recognize = esp_timer_get_time();
384+
draw_face_boxes(image_matrix, net_boxes, face_id);
385+
free(net_boxes->score);
386+
free(net_boxes->box);
387+
free(net_boxes->landmark);
388+
free(net_boxes);
389+
}
390+
if(!fmt2jpg(image_matrix->item, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len)){
391+
Serial.println("fmt2jpg failed");
392+
res = ESP_FAIL;
393+
}
394+
esp_camera_fb_return(fb);
395+
fb = NULL;
396+
} else {
397+
_jpg_buf = fb->buf;
398+
_jpg_buf_len = fb->len;
399+
}
400+
fr_encode = esp_timer_get_time();
401+
}
402+
dl_matrix3du_free(image_matrix);
403+
}
404+
}
405+
}
406+
if(res == ESP_OK){
407+
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
408+
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
409+
}
410+
if(res == ESP_OK){
411+
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
412+
}
413+
if(res == ESP_OK){
414+
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
415+
}
416+
if(fb){
417+
esp_camera_fb_return(fb);
418+
fb = NULL;
419+
_jpg_buf = NULL;
420+
} else if(_jpg_buf){
421+
free(_jpg_buf);
422+
_jpg_buf = NULL;
423+
}
424+
if(res != ESP_OK){
425+
break;
426+
}
427+
int64_t fr_end = esp_timer_get_time();
428+
429+
int64_t ready_time = (fr_ready - fr_start)/1000;
430+
int64_t face_time = (fr_face - fr_ready)/1000;
431+
int64_t recognize_time = (fr_recognize - fr_face)/1000;
432+
int64_t encode_time = (fr_encode - fr_recognize)/1000;
433+
int64_t process_time = (fr_encode - fr_start)/1000;
434+
435+
int64_t frame_time = fr_end - last_frame;
436+
last_frame = fr_end;
437+
frame_time /= 1000;
438+
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
439+
Serial.printf("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps), %u+%u+%u+%u=%u %s%d\n",
440+
(uint32_t)(_jpg_buf_len),
441+
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
442+
avg_frame_time, 1000.0 / avg_frame_time,
443+
(uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time,
444+
(detected)?"DETECTED ":"", face_id
445+
);
446+
}
447+
448+
last_frame = 0;
449+
return res;
450+
}
451+
452+
static esp_err_t cmd_handler(httpd_req_t *req){
453+
char* buf;
454+
size_t buf_len;
455+
char variable[32] = {0,};
456+
char value[32] = {0,};
457+
458+
buf_len = httpd_req_get_url_query_len(req) + 1;
459+
if (buf_len > 1) {
460+
buf = (char*)malloc(buf_len);
461+
if(!buf){
462+
httpd_resp_send_500(req);
463+
return ESP_FAIL;
464+
}
465+
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
466+
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
467+
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
468+
} else {
469+
free(buf);
470+
httpd_resp_send_404(req);
471+
return ESP_FAIL;
472+
}
473+
} else {
474+
free(buf);
475+
httpd_resp_send_404(req);
476+
return ESP_FAIL;
477+
}
478+
free(buf);
479+
} else {
480+
httpd_resp_send_404(req);
481+
return ESP_FAIL;
482+
}
483+
484+
int val = atoi(value);
485+
sensor_t * s = esp_camera_sensor_get();
486+
int res = 0;
487+
488+
if(!strcmp(variable, "framesize")) {
489+
if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
490+
}
491+
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
492+
else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
493+
else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
494+
else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
495+
else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val);
496+
else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val);
497+
else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val);
498+
else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val);
499+
else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val);
500+
else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
501+
else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
502+
else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val);
503+
else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val);
504+
else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val);
505+
else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val);
506+
else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val);
507+
else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val);
508+
else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val);
509+
else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val);
510+
else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val);
511+
else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val);
512+
else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
513+
else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
514+
else if(!strcmp(variable, "face_detect")) {
515+
detection_enabled = val;
516+
if(!detection_enabled) {
517+
recognition_enabled = 0;
518+
}
519+
}
520+
else if(!strcmp(variable, "face_enroll")) is_enrolling = val;
521+
else if(!strcmp(variable, "face_recognize")) {
522+
recognition_enabled = val;
523+
if(recognition_enabled){
524+
detection_enabled = val;
525+
}
526+
}
527+
else {
528+
res = -1;
529+
}
530+
531+
if(res){
532+
return httpd_resp_send_500(req);
533+
}
534+
535+
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
536+
return httpd_resp_send(req, NULL, 0);
537+
}
538+
539+
static esp_err_t status_handler(httpd_req_t *req){
540+
static char json_response[1024];
541+
542+
sensor_t * s = esp_camera_sensor_get();
543+
char * p = json_response;
544+
*p++ = '{';
545+
546+
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
547+
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
548+
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
549+
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
550+
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
551+
p+=sprintf(p, "\"sharpness\":%d,", s->status.sharpness);
552+
p+=sprintf(p, "\"special_effect\":%u,", s->status.special_effect);
553+
p+=sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode);
554+
p+=sprintf(p, "\"awb\":%u,", s->status.awb);
555+
p+=sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain);
556+
p+=sprintf(p, "\"aec\":%u,", s->status.aec);
557+
p+=sprintf(p, "\"aec2\":%u,", s->status.aec2);
558+
p+=sprintf(p, "\"ae_level\":%d,", s->status.ae_level);
559+
p+=sprintf(p, "\"aec_value\":%u,", s->status.aec_value);
560+
p+=sprintf(p, "\"agc\":%u,", s->status.agc);
561+
p+=sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain);
562+
p+=sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling);
563+
p+=sprintf(p, "\"bpc\":%u,", s->status.bpc);
564+
p+=sprintf(p, "\"wpc\":%u,", s->status.wpc);
565+
p+=sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma);
566+
p+=sprintf(p, "\"lenc\":%u,", s->status.lenc);
567+
p+=sprintf(p, "\"vflip\":%u,", s->status.vflip);
568+
p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
569+
p+=sprintf(p, "\"dcw\":%u,", s->status.dcw);
570+
p+=sprintf(p, "\"colorbar\":%u,", s->status.colorbar);
571+
p+=sprintf(p, "\"face_detect\":%u,", detection_enabled);
572+
p+=sprintf(p, "\"face_enroll\":%u,", is_enrolling);
573+
p+=sprintf(p, "\"face_recognize\":%u", recognition_enabled);
574+
*p++ = '}';
575+
*p++ = 0;
576+
httpd_resp_set_type(req, "application/json");
577+
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
578+
return httpd_resp_send(req, json_response, strlen(json_response));
579+
}
580+
581+
static esp_err_t index_handler(httpd_req_t *req){
582+
httpd_resp_set_type(req, "text/html");
583+
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
584+
sensor_t * s = esp_camera_sensor_get();
585+
if (s->id.PID == OV3660_PID) {
586+
return httpd_resp_send(req, (const char *)index_ov3660_html_gz, index_ov3660_html_gz_len);
587+
}
588+
return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len);
589+
}
590+
591+
void startCameraServer(){
592+
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
593+
594+
httpd_uri_t index_uri = {
595+
.uri = "/",
596+
.method = HTTP_GET,
597+
.handler = index_handler,
598+
.user_ctx = NULL
599+
};
600+
601+
httpd_uri_t status_uri = {
602+
.uri = "/status",
603+
.method = HTTP_GET,
604+
.handler = status_handler,
605+
.user_ctx = NULL
606+
};
607+
608+
httpd_uri_t cmd_uri = {
609+
.uri = "/control",
610+
.method = HTTP_GET,
611+
.handler = cmd_handler,
612+
.user_ctx = NULL
613+
};
614+
615+
httpd_uri_t capture_uri = {
616+
.uri = "/capture",
617+
.method = HTTP_GET,
618+
.handler = capture_handler,
619+
.user_ctx = NULL
620+
};
621+
622+
httpd_uri_t stream_uri = {
623+
.uri = "/stream",
624+
.method = HTTP_GET,
625+
.handler = stream_handler,
626+
.user_ctx = NULL
627+
};
628+
629+
630+
ra_filter_init(&ra_filter, 20);
631+
632+
mtmn_config.type = FAST;
633+
mtmn_config.min_face = 80;
634+
mtmn_config.pyramid = 0.707;
635+
mtmn_config.pyramid_times = 4;
636+
mtmn_config.p_threshold.score = 0.6;
637+
mtmn_config.p_threshold.nms = 0.7;
638+
mtmn_config.p_threshold.candidate_number = 20;
639+
mtmn_config.r_threshold.score = 0.7;
640+
mtmn_config.r_threshold.nms = 0.7;
641+
mtmn_config.r_threshold.candidate_number = 10;
642+
mtmn_config.o_threshold.score = 0.7;
643+
mtmn_config.o_threshold.nms = 0.7;
644+
mtmn_config.o_threshold.candidate_number = 1;
645+
646+
face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
647+
648+
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
649+
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
650+
httpd_register_uri_handler(camera_httpd, &index_uri);
651+
httpd_register_uri_handler(camera_httpd, &cmd_uri);
652+
httpd_register_uri_handler(camera_httpd, &status_uri);
653+
httpd_register_uri_handler(camera_httpd, &capture_uri);
654+
}
655+
656+
config.server_port += 1;
657+
config.ctrl_port += 1;
658+
Serial.printf("Starting stream server on port: '%d'\n", config.server_port);
659+
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
660+
httpd_register_uri_handler(stream_httpd, &stream_uri);
661+
}
662+
}

‎camera_index.h

Lines changed: 558 additions & 0 deletions
Large diffs are not rendered by default.

‎camera_pins.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
2+
#if defined(CAMERA_MODEL_WROVER_KIT)
3+
#define PWDN_GPIO_NUM -1
4+
#define RESET_GPIO_NUM -1
5+
#define XCLK_GPIO_NUM 21
6+
#define SIOD_GPIO_NUM 26
7+
#define SIOC_GPIO_NUM 27
8+
9+
#define Y9_GPIO_NUM 35
10+
#define Y8_GPIO_NUM 34
11+
#define Y7_GPIO_NUM 39
12+
#define Y6_GPIO_NUM 36
13+
#define Y5_GPIO_NUM 19
14+
#define Y4_GPIO_NUM 18
15+
#define Y3_GPIO_NUM 5
16+
#define Y2_GPIO_NUM 4
17+
#define VSYNC_GPIO_NUM 25
18+
#define HREF_GPIO_NUM 23
19+
#define PCLK_GPIO_NUM 22
20+
21+
#elif defined(CAMERA_MODEL_ESP_EYE)
22+
#define PWDN_GPIO_NUM -1
23+
#define RESET_GPIO_NUM -1
24+
#define XCLK_GPIO_NUM 4
25+
#define SIOD_GPIO_NUM 18
26+
#define SIOC_GPIO_NUM 23
27+
28+
#define Y9_GPIO_NUM 36
29+
#define Y8_GPIO_NUM 37
30+
#define Y7_GPIO_NUM 38
31+
#define Y6_GPIO_NUM 39
32+
#define Y5_GPIO_NUM 35
33+
#define Y4_GPIO_NUM 14
34+
#define Y3_GPIO_NUM 13
35+
#define Y2_GPIO_NUM 34
36+
#define VSYNC_GPIO_NUM 5
37+
#define HREF_GPIO_NUM 27
38+
#define PCLK_GPIO_NUM 25
39+
40+
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
41+
#define PWDN_GPIO_NUM -1
42+
#define RESET_GPIO_NUM 15
43+
#define XCLK_GPIO_NUM 27
44+
#define SIOD_GPIO_NUM 25
45+
#define SIOC_GPIO_NUM 23
46+
47+
#define Y9_GPIO_NUM 19
48+
#define Y8_GPIO_NUM 36
49+
#define Y7_GPIO_NUM 18
50+
#define Y6_GPIO_NUM 39
51+
#define Y5_GPIO_NUM 5
52+
#define Y4_GPIO_NUM 34
53+
#define Y3_GPIO_NUM 35
54+
#define Y2_GPIO_NUM 32
55+
#define VSYNC_GPIO_NUM 22
56+
#define HREF_GPIO_NUM 26
57+
#define PCLK_GPIO_NUM 21
58+
59+
#elif defined(CAMERA_MODEL_M5STACK_WIDE)
60+
#define PWDN_GPIO_NUM -1
61+
#define RESET_GPIO_NUM 15
62+
#define XCLK_GPIO_NUM 27
63+
#define SIOD_GPIO_NUM 22
64+
#define SIOC_GPIO_NUM 23
65+
66+
#define Y9_GPIO_NUM 19
67+
#define Y8_GPIO_NUM 36
68+
#define Y7_GPIO_NUM 18
69+
#define Y6_GPIO_NUM 39
70+
#define Y5_GPIO_NUM 5
71+
#define Y4_GPIO_NUM 34
72+
#define Y3_GPIO_NUM 35
73+
#define Y2_GPIO_NUM 32
74+
#define VSYNC_GPIO_NUM 25
75+
#define HREF_GPIO_NUM 26
76+
#define PCLK_GPIO_NUM 21
77+
78+
#elif defined(CAMERA_MODEL_AI_THINKER)
79+
#define PWDN_GPIO_NUM 32
80+
#define RESET_GPIO_NUM -1
81+
#define XCLK_GPIO_NUM 0
82+
#define SIOD_GPIO_NUM 26
83+
#define SIOC_GPIO_NUM 27
84+
85+
#define Y9_GPIO_NUM 35
86+
#define Y8_GPIO_NUM 34
87+
#define Y7_GPIO_NUM 39
88+
#define Y6_GPIO_NUM 36
89+
#define Y5_GPIO_NUM 21
90+
#define Y4_GPIO_NUM 19
91+
#define Y3_GPIO_NUM 18
92+
#define Y2_GPIO_NUM 5
93+
#define VSYNC_GPIO_NUM 25
94+
#define HREF_GPIO_NUM 23
95+
#define PCLK_GPIO_NUM 22
96+
97+
#else
98+
#error "Camera model not selected"
99+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.