ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ESP-IoT-Solution 摄像头应用实战指南:从 esp32-camera 驱动到拍摄、推流与录制

ESP-IoT-Solution 摄像头应用实战指南:从 esp32-camera 驱动到拍摄、推流与录制 ESP-IoT-Solution 摄像头应用实战指南从 esp32-camera 驱动到拍摄、推流与录制【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution导读本文基于 ESP-IoT-Solution 仓库 examples/camera 目录下的系列示例系统讲解如何在乐鑫Espressif芯片上从零搭建摄像头应用先梳理 esp32-camera 驱动的初始化与取帧工作流再依次深入五个可运行示例——基础拍照basic、网页拍照服务器pic_server、帧率评测test_framerate、视频流 HTTP 服务器video_stream_server与 AVI 视频录制video_recorder最后给出完整的 API 参考。读完本文你将掌握esp_camera_fb_get()/esp_camera_fb_return()的缓冲区生命周期管理、影响帧率的关键配置因子以及如何用 JPEG 转换接口搭建图片/视频 Web 服务。摄像头示例总览与驱动选型examples/camera目录是一个以 esp32-camera。它包含了从驱动初始化到网络传输再到存储录制的完整链路覆盖典型产品需求。目录布局如下示例核心能力适用目标basic初始化传感器并获取一帧图像入门、验证硬件pic_server通过 Web 页面按需拍照并即时查看拍照类产品test_framerate评测传感器出帧速度及影响因素性能调优video_stream_server实现 HTTP 视频流服务器实时预览video_recorder将视频以 AVI 格式录制到 SD 卡录像存储一个重要的选型结论来自目录 README 的明确提示注意ESP32 和 ESP32-S2 芯片只能配合 esp32-camera 组件使用ESP32-S3 和 ESP32-P4 芯片推荐使用 esp-video 组件。这意味着在选择驱动前首先要确认目标芯片。本文讨论的五个示例中前四个均基于 esp32-camera支持 ESP32 / ESP32-S2 / ESP32-S3而 video_lcd_display 是唯一基于 esp_video 组件、且仅支持 ESP32-P4 的示例用于将摄像头图像实时显示到 LCD 屏上。从源码看芯片支持边界各示例的sdkconfig.defaults文件印证了这一芯片边界。例如 examples/camera/video_stream_server 目录下同时提供了sdkconfig.defaults.esp32、sdkconfig.defaults.esp32s2、sdkconfig.defaults.esp32s3三个芯片级配置而 video_lcd_display 的 README 明确标注 Supported Targets: ESP32-P4其 MIPI-CSI 相机 MIPI-DSI 屏幕的硬件组合在 ESP32-P4-Function-EV-Board 上验证。相机驱动工作流DVP 接口、帧缓冲与数据流目录 README 用一张工作流程图docs/_static/camera-workflow.png概括了 esp32-camera 的核心数据流。其工作机理可以概括为三步传感器经 DVP 接口传输数据相机传感器通过 DVP并行数字视频端口接口把图像数据送入 ESP32 芯片。初始化时分配帧缓冲调用esp_camera_init()初始化相机时驱动会分配若干frame_buffer用于暂存传感器传来的数据。应用层取帧与归还相机初始化完成后立即开始工作应用通过esp_camera_fb_get()获取图像数据数据处理完毕后调用esp_camera_fb_return()归还帧缓冲使其可被复用。用代码表示这个取帧-使用-归还循环在 examples/camera/basic/main/take_picture.c 中体现得最直接while (1) { ESP_LOGI(TAG, Taking picture...); camera_fb_t *pic esp_camera_fb_get(); if (pic) { // use pic-buf to access the image ESP_LOGI(TAG, Picture taken! Its size was: %zu bytes, pic-len); // To enable the frame buffer can be reused again. // Note: If you dont call fb_return(), the next time you call fb_get() you may get // an error Failed to get the frame on time!because there is no frame buffer space available. esp_camera_fb_return(pic); } vTaskDelay(pdMS_TO_TICKS(2000)); }⚠️ 帧缓冲生命周期是本节最重要的工程要点esp_camera_fb_get()返回的camera_fb_t指针指向的是驱动内部管理的缓冲。若只取不还下一次取帧会因无可用缓冲而报错 Failed to get the frame on time!。因此任何路径下都必须成对调用esp_camera_fb_get()/esp_camera_fb_return()——包括异常分支。从 basic 示例学习相机初始化配置examples/camera/basic 是最小可用的拍照示例。它的init_camera()函数examples/camera/basic/main/take_picture.c展示了camera_config_t配置结构的完整填法camera_config_t camera_config { .pin_pwdn CAMERA_PIN_PWDN, .pin_reset CAMERA_PIN_RESET, .pin_xclk CAMERA_PIN_XCLK, .pin_sscb_sda CAMERA_PIN_SIOD, // SCCB/SCCB 控制总线I2C 类数据线 .pin_sscb_scl CAMERA_PIN_SIOC, // 控制总线时钟线 .pin_d7 CAMERA_PIN_D7, // DVP 数据线 D0-D7 .pin_d0 CAMERA_PIN_D0, .pin_vsync CAMERA_PIN_VSYNC, // 场同步 .pin_href CAMERA_PIN_HREF, // 行参考 .pin_pclk CAMERA_PIN_PCLK, // 像素时钟 // EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode. .xclk_freq_hz xclk_freq_hz, .ledc_timer LEDC_TIMER_0, // 仅对 ESP32/ESP32-S2 有效ESP32-S3 使用 LCD_CAM 接口 .ledc_channel LEDC_CHANNEL_0, .pixel_format pixel_format, // YUV422, GRAYSCALE, RGB565, JPEG .frame_size frame_size, // QQVGA-UXGA非 JPEG 格式时不建议超过 QVGA .jpeg_quality 30, // 0-63仅 JPEG 格式使用数值越小质量越高 .fb_count fb_count, // ESP32/ESP32-S2 上大于 1 时i2s 运行在连续模式 .grab_mode CAMERA_GRAB_WHEN_EMPTY, .fb_location CAMERA_FB_IN_PSRAM // 帧缓冲放在 PSRAM };camera_pin.h头文件为每个支持的目标芯片预定义了引脚宏如CAMERA_PIN_D0开发者在idf.py menuconfig - Camera Pin Configuration中完成引脚映射。初始化之后basic 示例还演示了两个实用操作传感器参数调节通过esp_camera_sensor_get()拿到sensor_t *结构再调用s-set_vflip(s, 1)、s-set_brightness(s, 1)等方法修正画面方向与色彩。源码注释特别提醒不要通过sensor_t调用设置分辨率、图像格式和 PLL 时钟的函数如需重置这些参数应重新初始化传感器。传感器能力查询esp_camera_sensor_get_info(s-id)返回camera_sensor_info_t *其中的support_jpeg字段用于判断当前传感器是否支持 JPEG 压缩/编码这直接影响后续的取帧格式选择代码见 examples/camera/basic/main/take_picture.c。编译烧录与典型输出在 examples/camera/basic 目录下idf.py -p PORT flash monitorPORT替换为实际串口号Ctrl-]退出串口监视器。硬件上需要一块带摄像头模组的开发板如 ESP-EYE、ESP32-S2-Kaluga-1、ESP32-S3-EYE和一根 USB 线。成功运行的串口输出大致如下来自 basic 的 READMEI (325) camera: Detected OV2640 camera I (325) camera: Camera PID0x26 VER0x42 MIDL0x7f MIDH0xa2 I (504) s2 ll_cam: node_size: 3840, nodes_per_line: 1, lines_per_node: 6 I (504) s2 ll_cam: dma_half_buffer_min: 3840, dma_half_buffer: 15360, lines_per_half_buffer: 24, dma_buffer_size: 30720 I (512) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 3840, node_cnt: 8, total_cnt: 10 I (522) cam_hal: Allocating 153600 Byte frame buffer in PSRAM I (529) cam_hal: Allocating 153600 Byte frame buffer in PSRAM I (535) cam_hal: cam config ok I (539) ov2640: Set PLL: clk_2x: 1, clk_div: 3, pclk_auto: 1, pclk_div: 8 I (714) example:take_picture: Taking picture... I (855) example:take_picture: Picture taken! Its size was: 153600 bytes日志中的cam_hal: Allocating ... frame buffer in PSRAM证实了CAMERA_FB_IN_PSRAM配置生效对应源码中的fb_location字段。网页拍照服务器pic_server 逐帧剖析examples/camera/pic_server 演示了按需拍照 浏览器即时查看的完整方案在本地网络启动 Web 服务器浏览器访问即可看到最新照片。使用步骤来自 README选择目标芯片idf.py menuconfig - Camera Pin Configuration配置 Wi-Fiidf.py menuconfig - Example Configuration配置相机idf.py menuconfig - Component config - Camera Configuration烧录并启动监视器idf.py flash monitor浏览器交互测试假设 IP 为 192.168.43.130访问http://192.168.43.130/pic查看 HTML 页面点击页面上的刷新按钮获取下一张照片HTTP 处理器的实现细节核心逻辑在 examples/camera/pic_server/main/pic_server.c 的pic_get_handler()中它展示了完整的取帧-编码-发送-归还循环esp_camera_fb_return(esp_camera_fb_get()); // 先丢弃队列中的旧帧 frame esp_camera_fb_get(); // 再取最新一帧 if (frame) { #if CONFIG_IMAGE_JPEG_FORMAT if (frame-format PIXFORMAT_JPEG) { image_data_buf frame-buf; image_data_buf_len frame-len; } else if (!frame2jpg(frame, 60, image_data_buf, image_data_buf_len)) { ESP_LOGE(TAG, JPEG compression failed); res ESP_FAIL; } #elif CONFIG_IMAGE_BMP_FORMAT if (frame2bmp(frame, image_data_buf, image_data_buf_len) ! true) { res ESP_FAIL; } #endif }这段代码中有两个值得注意的设计先丢一帧再取帧esp_camera_fb_return(esp_camera_fb_get())立即归还刚取得的帧从而让下一次esp_camera_fb_get()能拿到更新的图像保证点击刷新看到的是新照片。格式分派由 Kconfig 控制CONFIG_IMAGE_JPEG_FORMAT/CONFIG_IMAGE_BMP_FORMAT决定输出 JPEG 还是 BMP并通过httpd_resp_set_type()设置对应的 MIME 类型与Content-Disposition如inline; filenamecapture.jpg。非 JPEG 帧走软件转换当传感器不支持 JPEG 时调用frame2jpg()来自 img_converters 库在软件层压缩此时_jpg_buf由转换函数动态分配发送完成后必须free()这正是前面缓冲生命周期原则的体现。HTTP 响应收尾最后调用httpd_resp_send_chunk(req, NULL, 0)发送空 chunk 表示响应结束。服务器通过httpd_start()httpd_register_uri_handler()注册/picURI代码见 examples/camera/pic_server/main/pic_server.c任务栈设为 5120 字节以容纳 JPEG 转换开销。帧率评测test_framerate 与影响 fps 的五大因子examples/camera/test_framerate 用于量化评测传感器出帧速度。README 给出核心公式fps (frames/sec) picture_count / time_consumed即固定取 N 张图、统计耗时从而估算每秒帧率。源码实现examples/camera/test_framerate/main/take_picture.c用esp_timer_get_time()计时连续取times帧并累加pic-len最终同时输出 fps 与平均单帧字节数static bool camera_test_fps(uint16_t times, float *fps, size_t *size) { *fps 0.0f; *size 0; uint32_t s 0; uint32_t num 0; uint64_t total_time esp_timer_get_time(); for (size_t i 0; i times; i) { camera_fb_t *pic esp_camera_fb_get(); if (NULL pic) { ESP_LOGW(TAG, fb get failed); return 0; } else { s pic-len; num; } esp_camera_fb_return(pic); } total_time esp_timer_get_time() - total_time; if (num) { *fps num * 1000000.0f / total_time; *size s / num; } return 1; }影响帧率的关键参数表README 明确列出影响摄像头帧率的主要因素这些参数全部通过esp_camera_init()的camera_config_t指定参数说明xclk驱动相机传感器的时钟频率。通常提高该时钟频率会提升帧率但受传感器最高时钟限制image format常见输出格式为 RGB565 / YUV422 / JPEG。JPEG 是压缩数据传输量小因此选择 JPEG 通常能提升帧率image size图像分辨率。分辨率越高单位时间需传输的数据越多帧率可能越低fb_count用于接收传感器数据的帧缓冲数量。增大该值可能提升帧率jpeg_qualityJPEG 质量越低需传输的数据越少可能有助于提升帧率0-63越小质量越低结合源码可以看到xclk、pixel_format、frame_size、fb_count、jpeg_quality正是 init_camera 中camera_config_t的五个关键字段README 建议开发者逐一修改并对比 fps 结果来验证影响。测试流程中的两次初始化examples/camera/test_framerate/main/take_picture.c 展示了camera_performance_test_with_format()的一个细节先以init_camera(10000000, pixel_format, frame_size, 2)探测传感器信息esp_camera_sensor_get_info()随后esp_camera_deinit()反初始化、延迟 500ms再用目标 xclk 频率重新初始化正式测速。整个流程体现了驱动支持初始化 → 取信息 → 反初始化 → 再初始化的生命周期管理。默认配置为PIXFORMAT_RGB565 FRAMESIZE_QVGA、PIC_COUNT_TEST取 360 帧。视频流服务器video_stream_server 的 MJPEG 推流原理examples/camera/video_stream_server 在本地网络启动 Web 服务器浏览器可动态查看画面。使用方法与 pic_server 类似配置引脚、Wi-Fi、相机后idf.py flash monitor浏览器访问http://192.168.43.130/stream即可观看。关键技术multipart/x-mixed-replace 实现 MJPEG 流流服务基于 HTTP 的multipart/x-mixed-replace机制源码见 examples/camera/video_stream_server/main/stram_server.c#define PART_BOUNDARY 123456789000000000000987654321 static const char *_STREAM_CONTENT_TYPE multipart/x-mixed-replace;boundary PART_BOUNDARY; static const char *_STREAM_BOUNDARY \r\n-- PART_BOUNDARY \r\n; static const char *_STREAM_PART Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n;工作流程为请求到达/stream后httpd_resp_set_type()把响应类型设为multipart/x-mixed-replace; boundary...并附带X-Framerate头服务器进入死循环从 FreeRTOS 队列xQueueFrameI阻塞接收帧xQueueReceive(xQueueFrameI, frame, portMAX_DELAY)对每一帧若是PIXFORMAT_JPEG直接使用frame-buf否则调用frame2jpg(frame, 60, _jpg_buf, _jpg_buf_len)软件压缩用httpd_resp_send_chunk()依次发送_STREAM_BOUNDARY、带时间戳的 part 头X-Timestamp: %d.%06d取自frame-timestamp以及 JPEG 数据帧使用完毕后归还缓冲继续等待下一帧——浏览器端混合替换机制会持续刷新画面从而形成视频流。队列解耦了相机取帧任务与 HTTP 发送任务frame-timestamp由驱动在捕获时打点可用于统计实际推流帧率。该示例默认把传感器输出配置为 JPEGTEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2)); // 若传感器不支持 JPEG 压缩请改为 PIXFORMAT_RGB565/PIXFORMAT_YUV422注意xclk20MHz、fb_count2且输出 QVGA JPEG。README 也提示当前传感器配置并非最优若刷新较慢可参考传感器数据手册调整寄存器参数。视频录制video_recorder 将 JPEG 帧写入 AVI 并支持 Web 下载examples/camera/video_recorder 演示把视频以 AVI 格式录制到 SD 卡并可选开启 HTTP 文件服务器方便在浏览器中下载视频文件。硬件与存储要求来自 README一块带摄像头模组和 SD 卡槽的开发板如 ESP32-CAM、ESP32-S3-EYE及一张 SD 卡Note 1默认使用 SDMMC Host 驱动初始化 SD 卡。所有 ESP 芯片都可通过 SPI 接口使用 SD 卡ESP32 与 ESP32-S3 还支持 SDMMC 接口——通过CONFIG_EXAMPLE_USE_SDMMC_HOST开关选择仅支持 FAT32 文件系统挂载失败时可开启CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED让示例自动格式化Note 2推荐使用 4 线 SD 模式提升存储速率格式化时选择合适的分配单元大小簇大小更大的分配单元可提高读写性能Note 3当前仅支持 JPEG 图像编码格式因此使用支持 JPEG 编码的摄像头有助于实现流畅的视频录制。AVI 录制组件接口录制逻辑封装在自研组件 examples/camera/video_recorder/components/avi_video_process 中对外暴露两个接口见 avi_recorder.hesp_err_t avi_recorder_start(const char *fname, int (*get_frame)(void **buf, size_t *len), int (*return_frame)(void *buf), uint16_t image_width, uint16_t image_high, uint32_t rec_time, bool block); void avi_recorder_stop(void);avi_recorder_start()通过回调函数get_frame/return_frame与相机取帧逻辑解耦调用者提供取一帧与还一帧两个函数指针录制器据此消费帧数据并负责 AVI 容器头的写入与收尾。返回值语义为ESP_OK成功、ESP_ERR_INVALID_ARG参数错误、ESP_FAIL驱动安装错误。配置与运行流程idf.py menuconfig - Camera Pin Configuration选择目标芯片引脚idf.py menuconfig - Component config - Camera Configuration配置相机idf.py menuconfig - Example Configuration开启 HTTP 文件服务器EXAMPLE_FILE_SERVER_ENABLED以便从网页下载视频idf.py -p PORT flash monitor编译烧录运行。典型运行输出16GB SDHC 卡 文件服务器开启I (935) video_recorder: satrt to test fps I (1693) video_recorder: fps25.010317, image_average_size22142 I (1693) file manager: Initializing SD card I (1693) file manager: Using SDMMC peripheral Name: SC16G Type: SDHC/SDXC Speed: 20 MHz Size: 15193MB I (1755) avi recorder: Starting an avi [/sdcard/recorde.avi] I (21775) avi recorder: video info: width640 | height480 | fps25 I (21785) avi recorder: frame number502, size9482KB I (21849) avi recorder: avi recording completed日志显示录制前会先测试 fps本例约 25fps、平均每帧 22KB随后初始化 SD 卡并把 502 帧约 9.5MB写入/sdcard/recorde.avi。录制完成后浏览器访问http://192.168.1.100/默认端口 80即可看到服务器上的文件列表并下载视频。基于 esp_video 的 LCD 实时显示video_lcd_displayESP32-P4作为对比与前瞻examples/camera/video_lcd_display 展示了新驱动栈 esp_video 的用法把摄像头画面实时显示到 LCD。支持平台仅 ESP32-P4需 ESP-IDF release/v5.4 及以上分支硬件ESP32-P4-Function-EV-Board、7 英寸 1024×600 EK79007 LCD32-pin FPC 转接板经 MIPI-DSI 接口连接、SC2336 MIPI-CSI 相机32-pin FPC 转接板接线屏幕转接板 5V/GND 接开发板对应电源脚PWM 接 GPIO26背光、LCD_RST 接 GPIO27相机配置Component config - Espressif Camera Sensors Configurations - SC2336默认格式为 RAW8 1280x720 30fps、MIPI 2lane 24M 输入。该示例展示的 MIPI-CSI/MIPI-DSI 方案正是目录 README 推荐 ESP32-S3/ESP32-P4 使用 esp_video 组件的原因——新平台的高带宽摄像头场景需要新的驱动架构支撑。esp32-camera 核心 API 参考目录 README 给出了以下 API 参考均来自 esp32-camera 组件源码位于该仓库driver/include/esp_camera.h、driver/include/sensor.h、conversions/include/img_converters.h等头文件。驱动生命周期与取帧esp_camera.h函数说明esp_err_t esp_camera_init(const camera_config_t *config)初始化相机驱动esp_err_t esp_camera_deinit()反初始化相机驱动camera_fb_t *esp_camera_fb_get()获取帧缓冲指针void esp_camera_fb_return(camera_fb_t *fb)归还帧缓冲以供复用sensor_t *esp_camera_sensor_get()获取图像传感器控制结构指针esp_err_t esp_camera_save_to_nvs(const char *key)将相机设置保存到非易失存储NVSesp_err_t esp_camera_load_from_nvs(const char *key)从非易失存储NVS加载相机设置传感器信息sensor.h函数说明camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id)获取相机传感器信息如support_jpeg能力图像转换img_converters.h函数说明bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void *arg)将图像缓冲转换为 JPEG回调输出bool frame2jpg_cb(camera_fb_t *fb, uint8_t quality, jpg_out_cb cb, void *arg)将相机帧缓冲转换为 JPEG回调输出bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t **out, size_t *out_len)将图像缓冲转换为 JPEG 缓冲bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t **out, size_t *out_len)将图像缓冲转换为 BMP 缓冲bool frame2bmp(camera_fb_t *fb, uint8_t **out, size_t *out_len)将相机帧缓冲转换为 BMP 缓冲bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t *rgb_buf)将图像缓冲转换为 RGB888 缓冲bool jpg2rgb565(const uint8_t *src, size_t src_len, uint8_t *out, jpg_scale_t scale)将 JPEG 缓冲转换为 RGB565 缓冲JPEG 解码缩放esp_jpg_decode.h函数说明esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void *arg)JPEG 缩放/解码函数这些转换接口正是前面 pic_server 中frame2jpg()、frame2bmp()的底层实现也是传感器不支持 JPEG 时把 RGB565/YUV422 帧软件压缩成 JPEG 再发送的技术支撑。常见问题排查各示例 README 均提供了一致的排查指引整理如下GPIO 报错若日志出现gpio: gpio_intr_disable(176): GPIO number error多半是相机引脚配置问题请在idf.py menuconfig的Component config - Camera Pin Config中核对引脚映射。相机初始化失败请检查初始化参数与传感器引脚配置是否正确。推流/拍照缓慢参照 帧率评测 一节调整 xclk、图像格式、分辨率、fb_count 与 jpeg_quality对不支持 JPEG 的传感器需把PIXFORMAT_JPEG改为PIXFORMAT_RGB565或PIXFORMAT_YUV422。SD 卡挂载失败确认卡为 FAT32 格式或在Example Configuration中开启CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED自动格式化。帧缓冲泄漏确保所有esp_camera_fb_get()返回的缓冲都被esp_camera_fb_return()归还否则将出现 Failed to get the frame on time! 错误。延伸资源图像处理开发平台 ESP-WHO基于乐鑫芯片包含可直接用于实际项目的开发示例人脸检测/识别等USB 摄像头示例见 examples/usb/host包含使用 USB 摄像头的示例摄像头常见问题与更多工程细节可参考 examples/camera/README.md 及各子示例 README若需深入学习底层驱动esp32-camera 组件的头文件即是最好的文档esp_camera.h、sensor.h、img_converters.h、esp_jpg_decode.h。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表