ESP32-CAM使用+源码分析

2021-02-23 10:21:25 浏览数 (1)

我觉得一开始就得放一下这个图

这个是一些相关的特性,就是沾ESP32芯片的光了。

忘了说这个东西10g可以上飞机,就是这个处理速度实在拉胯

这里放一些更加细致的资料

这个帧率吧太小了,没有实际的应用价值我觉得

相关相机的管脚定义

这个最小的系统图,没有什么作用。就看看管脚算了

这个是带彩的定义图

因为我直接加钱把下面的串口芯片也买了,文章里面就不出现用

TTL转串口下载程序的步骤了

这个是我们的主角

合体的样子

如果你要是用TTL下载,记得短接IO0 GND

代码语言:javascript复制
http://arduino.esp8266.com/stable/package_esp8266com_index.json
http://digistump.com/package_digistump_index.json
https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
http://digistump.com/package_digistump_index.json
https://dl.espressif.com/dl/package_esp32_index.json

点击安装,先配置一下arduino的环境

选择这个 安可信的模组

选好的样子

这里打开今天的demo

注意把别的模组注释掉,打开安可信

然后波特率,选择115200

稍微等一下,出现IP

在浏览器内打开

串口会输出传输的信息

既然是网页端,那开发工具不能少

代码语言:javascript复制
https://github.com/espressif/arduino-esp32

我们去GitHub下载库

解压把剩下的输出,就留库

我们用code打开

因为图像的传输起来占带宽很大,所以需要缓冲区这种设计

PSRAM:pseudo SRAM,伪SRAM。它具有类SRAM的接口协议:给出地址、读、写命令,就可以实现存取,不像DRAM需要memory controller来控制内存单元定期数据刷新,因此结口简单;但它的内核是DRAM架构:1T1C一个晶体管一个电容构成存储cell,而传统SRAM需要6T即六个晶体管构成一个存储cell。由此结合,他可以实现类SRAM的接口有可实现较大的存储容量。(我们都知道大容量SRAM非常贵)

早期的PSRAM制造商包括Samsung、Micron等巨头,广泛用于最早期的智能手机。那时候的手机内存有192MB、384MB等现在看起来非常小的容量。但很快,就进入到LPDDR1、LPDDR2、LPDDR3到如今的LPDDR4.

然而,PSRAM如今仍然在大规模的使用,只是一般人不知道、看不见而已:在M、S、R三大2G base band芯片供应商里,都集成有32MB的PSRAM,只不过他们都是以SiP的形式出现,封在芯片里面你看不见。

物联网时代,赋予了PSRAM新的活力,尤其在语音交互领域,PSRAM以其小封装、大容量、低成本,开始显露器独特优势。

在一些智能语音交互的场合,有些语音数据来自云端,pSRAM能很好的提供数据缓冲作用,解决网络数据的不稳定问题,以提供稳定、平滑的语音服务。例如:儿童对着一个玩具娃说,“我要听葫芦娃的故事”,玩具娃识别请求后,会在云端找到相关故事,以流媒体传送的方式,播放该故事。由于有PSRAM做data buffer,即使在不是很稳定的环境里,故事也会非常流畅的播放。

同样,在一些网络收音机中,使用PSRAM,能够是声音播放非常平滑,提供优越的用户体验。

为追求小型化,现在已经有串行化的PSRAM:

1. SPI PSRAM: 8-pin SOP封装,最高速率可以达到104MHz, 具有片选CS、CLK、SI、SO 4个信号脚。

2. QPI PSRAM: 8-pin SOP封装,最高速率104MHz, 有额外的3个双向数据管脚,由此带宽峰值可以达到416Mbps。

3. OPI PSRAM: 24 脚封装,有8个串行数据线,最高时钟频率达到133MHz,最高带宽可以达到133x8 x2=2.128Gbps。这里x2是因为它可以实现DDR,以提高数据带宽。

PSRAM在一些数据缓冲应用中可以取代SRAM或者SDRAM: 高速、大容量PSRAM非常贵;而SDRAM需要很多管脚、需要设计DRAM控制器、实现数据刷新等,再尺寸、设计复杂度等上不经济。

在传统的MCU中,都有SPI接口,因此,使用PSRAM没有问题。对应QPI/OPI,设计上需要一些配合。

我们相机模块用的就是这个

在渲染图的这个地方

在下面的位置引入了一个头文件

以及两个串,你相机要连接的ap名字和密码

这个相机服务开启的代码在这里,是个大函数

通过传递类型httpd_uri_t结构的对象来注册URI处理程序,该对象具有包括uri名称,method类型

下面的这一部分是人脸识别的部分


MTMN是一种轻量级的人脸检测模型,它围绕一个新的移动架构(称为移动网络2和多任务级联卷积网络)构建,专为嵌入式设备而设计。

概述

MTMN 由三个主要部分组成:

  1. 建议网(P-Net):建议候选边界框,并将其发送到R-Net;
  2. 优化网络(R-Net):从P-Net筛选边界框;
  3. 输出网络 (O-Net):输出最终结果,即精确边界框、置信系数和 5 点地标。

API 简介

代码语言:javascript复制
box_array_t *face_detect(dl_matrix3du_t *image_matrix, mtmn_config_t *config);

这将处理整个人脸检测任务。face_detect()

输入包括:

  • image_matrix:类型中的图像dl_matrix3du_t
  • 配置:MTMN 的配置。有关更多详细信息,请参阅"提前配置"部分。

输出为:

  • 类型值包含人脸框,以及每个框的分数和地标。box_array_t

此结构定义如下:

代码语言:javascript复制
typedef struct tag_box_list
{
    fptp_t *score;
    box_t *box;
    landmark_t *landmark;
    int len;
} box_array_t;

该结构包含数组头,每个数组具有相同的长度,即图像中的面数。

提前配置

face_detect()为用户自定义定义提供参数。config

代码语言:javascript复制
box_array_t *face_detect(dl_matrix3du_t *image_matrix, mtmn_config_t *config);

的定义:mtmn_config_t

代码语言:javascript复制
typedef struct
{
    float min_face;                 /// The minimum size of a detectable face
    float pyramid;                  /// The scale of the gradient scaling for the input images
    int pyramid_times;              /// The pyramid resizing times
    threshold_config_t p_threshold; /// The thresholds for P-Net. For details, see the definition of threshold_config_t
    threshold_config_t r_threshold; /// The thresholds for R-Net. For details, see the definition of threshold_config_t
    threshold_config_t o_threshold; /// The thresholds for O-Net. For details, see the definition of threshold_config_t
    mtmn_resize_type type;          /// The image resize type. 'pyramid' will lose efficacy, when 'type'==FAST.
} mtmn_config_t;
代码语言:javascript复制
typedef struct
{
    float score;          /// The threshold of confidence coefficient. The candidate bounding boxes with a confidence coefficient lower than the threshold will be filtered out.
    float nms;            /// The threshold of NMS. During the Non-Maximum Suppression, the candidate bounding boxes with a overlapping ratio higher than the threshold will be filtered out.
    int candidate_number; /// The maximum number of allowed candidate bounding boxes. Only the first 'candidate_number' of all the candidate bounding boxes will be kept.
} threshold_config_t;
  • min_face:
    • 不同大小的生成图像的数量越大;
    • 可检测面的最小尺寸越小;
    • 处理时间越长
    • 范围: 12,原始输入图像最短边缘的长度)。
    • 对于固定大小的原始输入图像,尺寸越小,min_face
    • 反之亦然。
  • 金字塔
    • 不同大小的生成图像的数量越大;
    • 检测比越高;
    • 处理时间越长
    • 指定控制生成的金字塔的刻度。
    • 范围:(0,1)
    • 对于固定大小的原始输入图像,大小越大,pyramid
    • 反之亦然。
  • pyramid_times
    • 指定控制生成的金字塔的数字。
    • 范围:{1,inf)
    • 与金字塔和min_face一起,可以在范围 [min_face、min_face/金字塔=pyramid_times] 和 min_face/金字塔=pyramid_times < 原始输入图像最短边缘的长度确定主要可检测到的面大小。
  • 类型
    • FAST:金字塔等于默认值。在同一金字塔值中,类型比类型快。0.707106781FASTNORMAL
    • NORMAL:如果要自定义金字塔值,请将类型设置为请。NORMAL
    • 选项:或FASTNORMAL
  • 分数阈值
    • 筛选出候选边界框的数量越大
    • 检测比率越低
    • 范围:(0,1)
    • 对于固定大小的原始输入图像,大小越大,score
    • 反之亦然。
  • nms 阈值
    • 检测到重叠面的可能性越高;
    • 检测到同一面的候选边界框的数量越大
    • 范围:(0,1)
    • 对于固定大小的原始输入图像,大小越大,nms
    • 反之亦然。
  • 候选人编号
    • 越大,处理时间越长;candidate_number
    • O-Net 越大,检测到的面数越大candidate_number
    • P-Net:[1, 200]
    • R-Net:[1, 100]
    • O-Net:[1, 10]
    • 指定每个网络的输出候选框数。
    • 范围
    • 对于固定大小的原始输入图像,
    • 反之亦然。

用户可以根据实际要求配置这些参数。另请参阅以下通用方案(一个人脸检测)的建议配置:

代码语言:javascript复制
mtmn_config.type = FAST;
mtmn_config.min_face = 80;
mtmn_config.pyramid = 0.707;
mtmn_config.pyramid_times = 4;
mtmn_config.p_threshold.score = 0.6;
mtmn_config.p_threshold.nms = 0.7;
mtmn_config.p_threshold.candidate_number = 20;
mtmn_config.r_threshold.score = 0.7;
mtmn_config.r_threshold.nms = 0.7;
mtmn_config.r_threshold.candidate_number = 10;
mtmn_config.o_threshold.score = 0.7;
mtmn_config.o_threshold.nms = 0.7;
mtmn_config.o_threshold.candidate_number = 1;

型号选择

MTMN 现在有两个版本可用:

  • MTMN lite 在量化(默认值)
  • 浮动中的 Mtmn 精简版
  • MTMN 在量化方面很重
性能

我们使用相同的配置和我们自己的测试集来评估所有型号。结果如下所示。

代码语言:javascript复制
mtmn_config.type = FAST;
mtmn_config.pyramid = 0.707;
mtmn_config.min_face = 80;
mtmn_config.pyramid_times = 4;
mtmn_config.p_threshold.score = 0.6;
mtmn_config.p_threshold.nms = 0.7;
mtmn_config.p_threshold.candidate_number = 100;
mtmn_config.r_threshold.score = 0.7;
mtmn_config.r_threshold.nms = 0.7;
mtmn_config.r_threshold.candidate_number = 100;
mtmn_config.o_threshold.score = 0.7;
mtmn_config.o_threshold.nms = 0.7;
mtmn_config.o_threshold.candidate_number = 1;

这个是性能部分

代码语言:javascript复制
https://github.com/espressif/esp-face/blob/master/face_detection/README.md

参考资料

这个是服务稳定后的后的一些打印的东西

接着又是一个服务器相关的打印语句

因为在主文件里面已经选择了对应的平台,所以在camera_pin的里面全点亮

先看一下概览的样子,只引入了相机,wifi,引脚的头文件

这些引入的头文件里面还有什么的头文件再说

一开始开启了串口的一些相关的配置,初始化了波特率,打开了debug。

下面是引脚的配置部分,在使用这些库去移植的时候需要改动的地方

这个代码就说的很明白了,就是这个地方没有写很底层的代码就是去申请内存什么的。只是开启了更高的分辨率,相当于开启功能


相机初始化

摄像头初始化

Step:

  1. 寻找摄像头
    1. 提供摄像头时钟、初始化 SCCB 总线、硬件复位摄像头
    2. 轮询地址寻找摄像头,通过 SCCB 总线读取摄像头 ID 等信息
    3. 更改摄像头的 ID 判断型号,并绑定对应的相关函数(摄像头传感器配置相关函数)
  2. 初始化摄像头
    1. 根据选择的图像格式、和是否是高速模式,选择对应的 DMA BUF 处理函数和 DMA FIFO 模式
    2. 初始化 I2S 总线,使能 I2S_IN_DONE_INT 中断:当前 DMA 接收链表描述符被处理时即触发此中断 3. 初始化 DMA 相关变量(链表描述符、DMA 使用的数据缓冲区链表等),DMA 单次最多 4KB 、每行 DMA 采集几次
    3. 初始化存储图像的数据缓冲区(添加到一个链表中)并清空
    4. 初始化相关信号量:DMA 数据采集完成、一帧图像采集完成信号量、图像数据缓冲区进出信号量
    5. 创建 dma_filter_task 将 DMA 数据转换成像素数据并存储到图像缓冲区,这里也会检查是否有脏数据产生,判断是否接收完一帧完整的图像
    6. 初始化 vsync io 中断:每一帧图像开始结尾都会发生电平翻转
    7. 摄像头传感器相关配置(图像大小、格式等)

剩下有一点代码,我因为自己这个图像识别方面学的少就不作更多的分析了

代码放这里

最后一部分是WiFi配置部分,一开始的配置通过指针传到这里

配置部分到这里就好了。

因为是demo嘛,一些逻辑代码就没有写

然后整体来说,框架搭好啦。

然后这两个地方是超级大的数组

这个是最后一部分的代码库的头文件了

你看引入了,http的服务器,定时器相关,相机,图像转换库,相机index?

arduino的头,以及三个关于人脸识别的库

一开始是宏定义,名字一目了然

下面是两个结构体

这两个是结构体传递的地方,我也看不懂了。我写完文章就学CPP去了。。。

第一个函数应该是一个操作内存的一个函数,申请一定量的空间用

具体的大小是看结构体去申请的

剩下的函数就是这些了,我能力以及相关领域的知识储备不够就不能继续和各位看官一起分享了,我去恶补知识了~

0 人点赞