【ESP32-CAM】使用opencv获取ESP32-CAM视频流,并将图像保存至TF卡(一)

2023-11-12

VSCode+python+opencv+ESP32-CAM

本项目仅作为学习记录,不定时更新。

Arduino

对于ESP32-CAM,我们使用Arduino来开发,首先需要准备一些硬件:

  1. ESP32-CAM ,在淘宝大约30rmb一个;
  2. 烧录底座或USB转TTL模块
  3. 杜邦线若干

由于我采用的是烧录底座,所以只需要一根micro-usb线即可。
在这里插入图片描述
在这里插入图片描述
在使用Arduino之前,我们需要下载ESP32的库,其中也包含了ESP32-CAM,若还未配置完成,可以参照这篇博客进行配置。

成功配置后,就可以在工具->开发板中找到“AI Thinker ESP32-CAM”。由于安信可官方所提供的例程并不能在成功烧录后显示ip地址,所以我们使用大神yoursunny所提供的库,下载链接

下载了.zip包之后,不需要解压,在项目->加载库->添加.ZIP库中添加即可。

基于下载的库,使用ESP32-CAM获取视频流的代码如下:

#include <esp32cam.h>
#include <WebServer.h>
#include <WiFi.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 handleBmp()
{
  if (!esp32cam::Camera.changeResolution(loRes)) {
    Serial.println("SET-LO-RES FAIL");
  }

  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()));

  if (!frame->toBmp()) {
    Serial.println("CONVERT FAIL");
    server.send(503, "", "");
    return;
  }
  Serial.printf("CONVERT OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),
                static_cast<int>(frame->size()));

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

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 handleJpgLo()
{
  if (!esp32cam::Camera.changeResolution(loRes)) {
    Serial.println("SET-LO-RES FAIL");
  }
  serveJpg();
}

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

void handleJpg()
{
  server.sendHeader("Location", "/cam-hi.jpg");
  server.send(302, "", "");
}

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

  Serial.println("STREAM BEGIN");
  WiFiClient client = server.client();
  auto startTime = millis();
  int res = esp32cam::Camera.streamMjpeg(client);
  if (res <= 0) {
    Serial.printf("STREAM ERROR %d\n", res);
    return;
  }
  auto duration = millis() - startTime;
  Serial.printf("STREAM END %dfrm %0.2ffps\n", res, 1000.0 * res / duration);
}

void setup()
{
  Serial.begin(115200);
  Serial.println();

  {
    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.bmp");
  Serial.println("  /cam-lo.jpg");
  Serial.println("  /cam-hi.jpg");
  Serial.println("  /cam.mjpeg");

  server.on("/cam.bmp", handleBmp);
  server.on("/cam-lo.jpg", handleJpgLo);
  server.on("/cam-hi.jpg", handleJpgHi);
  server.on("/cam.jpg", handleJpg);
  server.on("/cam.mjpeg", handleMjpeg);

  server.begin();
}

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

VSCode + opencv配置

在VSCode中,我使用windows+python进行开发,python版本为3.9。在这里,VSCode以及python的下载和配置就略过了,大家可以自行根据其他博客进行安装。对于opencv在VSCode里的下载和安装,我们进行详细的介绍。

首先需要使用pip下载opencv,依次在终端里使用如下命令进行安装:

pip install opencv-python
pip install opencv-contrib-python

下载后到下载路径找cv2这个文件夹
在这里插入图片描述
将该文件夹下的cv2.cp39-win_amd64.pyd文件
在这里插入图片描述
复制到你想做opencv项目的新文件夹里。至此,opencv的配置完成。

opencv获取视频流

为了获取ESP32-CAM的视频流,我们需要将电脑ESP32-CAM连接同一个wifi热点,在Arduino中烧录好代码后,打开串口监视器,波特率选择115200,则可以看到ESP32-CAM的ip地址。比如我的ip地址如下:

在这里插入图片描述
然后我们使用复制过cv2.cp39-win_amd64.pyd文件的文件夹新建一个python文件。并且输入代码:

import urllib
import cv2
import numpy as np

url='http://192.168.43.103/cam-hi.jpg'// 改成自己的ip地址+/cam-hi.jpg

while True:
    imgResp=urllib.request.urlopen(url)
    imgNp=np.array(bytearray(imgResp.read()),dtype=np.uint8)
    img=cv2.imdecode(imgNp,-1)

    # all the opencv processing is done here
    cv2.imshow('test',img)
    if ord('q')==cv2.waitKey(10):
        exit(0)

然后运行,即可在test窗口看到我们的图片,此时打开Arduino的串口监视器,可以看到读取速度约为10-15帧,具体情况和当时网速有关。

在这里插入图片描述

新版ESP32库不兼容的问题

有一些朋友可能会遇到这种情况
在这里插入图片描述
这是因为新版的ESP32的库版本兼容问题,现在2.0.2版的esp32开发板即可解决。在arduino软件-文件-首选项里面,附加开放项管理地址改成https://github.com/espressif/arduino-esp32/releases/download/2.0.2/package_esp32_dev_index.json,然后点开工具,开发板,开发板管理器,搜esp32,下载2.0.2解决。
本问题的解决方式由@qq_39641794提供

2022.4.17 更新

拍照保存TF卡

首先我们需要初始化TF卡。初始化TF卡的完整代码如下:

// Init SD Card
void sd_init()
{
  //The argument ("/sdcard",true) means closing LED light on the board
  if (!SD_MMC.begin("/sdcard",true)) { 
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD_MMC.cardType();
  if (cardType == CARD_NONE) {
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if (cardType == CARD_MMC) {
    Serial.println("MMC");
  }
  else if (cardType == CARD_SD) {
    Serial.println("SDSC");
  }
  else if (cardType == CARD_SDHC) {
    Serial.println("SDHC");
  }
  else {
    Serial.println("UNKNOWN");
  }

//Get the size of SD card, unit: MB
  uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);   
  Serial.printf("SD 卡容量大小: %lluMB\n", cardSize);
}

这一段代码要放在setup函数前面。**注意,ESP32-CAM模块的TF卡槽仅支持4G容量,超过4G均无法成功识别。**这段方法写好后,工程文件开头的#include要包含如下几个头文件,并声明几个变量,用以作为文件名序号:

#include <SPI.h>
#include <sd_defines.h>
#include <SD_MMC.h>
#include <SD.h>
#include <sd_defines.h>
#include <sd_diskio.h>
#include <esp32cam.h>
#include <WebServer.h>
#include <WiFi.h>
#include "cJSON.h"
#include "FS.h"
#include "esp_camera.h"
...
char path[] = "/1.jpg";
int order = 1;

而在setup()函数中,在上面获取视频流的代码保持不变的情况下,需要添加一行代码:

void setup(){
	...
	sd_init();//初始化TF卡
	delay(5000);
	...
  }
}

在loop()函数中,添加保存的代码。完整的loop()函数代码如下:

void loop()
{
  server.handleClient();
  camera_fb_t * fb = esp_camera_fb_get();
  sprintf(path,"/%d.jpg",order);
  if (fb == NULL)
  {
    Serial.println( "Get picture failed");
  }
  else
  {
    fs::FS &fs = SD_MMC;
    Serial.printf("Writing file: %s\n", path);
    File file = fs.open(path, FILE_WRITE);
    if (!file)
    {
      Serial.println("Failed to Create a File!");
    }
    else
    {
      file.write(fb->buf , fb->len);
    }
    esp_camera_fb_return(fb);
    order += 1;
  }
}

将代码上传到板子中并运行,然后取下TF卡,插入读卡器,并将读卡器插在电脑上,我们就可以看到保存在TF卡中的照片了。效果如下图所示:
在这里插入图片描述
至此,我们就完成了WiFi图像传输和本地保存两个功能。
注:此次更新的代码均是在上文中获取视频流代码的基础上修改,读者可以对比位置,在不修改获取视频流代码的情况下,将保存TF卡的代码添加到正确的位置即可,整个代码即可同时实现两个功能。
本次更新由本人同学,用户@Zhuwany进行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【ESP32-CAM】使用opencv获取ESP32-CAM视频流,并将图像保存至TF卡(一) 的相关文章

  • iOS 上的 OpenCV - VideoCapture 属性始终返回 1

    我一直在尝试构建一个简单的 OpenCV iOS 应用程序 该应用程序从捆绑包中加载视频并查询其帧数 持续时间等 然后它将尝试从中获取各个帧 不幸的是 当我使用VideoCapture类中 所有属性返回值 1 然后我尝试导航到frame 1
  • 如何使用 colorchecker 在 opencv 中进行颜色校准?

    我有数码相机获取的色彩检查器图像 我如何使用它来使用 opencv 校准图像 按照以下颜色检查器图像操作 您是想问如何进行颜色校准或如何使用 OpenCV 进行校准 为了进行颜色校准 您可以使用校准板的最后一行 灰色调 以下是您应该逐步进行
  • 二值图像中骨架上两点之间的最短路径

    我有一个二进制图像 其中包含图像的一个像素宽度骨架 您可能基本上知道 在这个二值图像中 我在骨架上有 1 在其他地方有 0 如何找到骨架上两个非零元素之间的最短距离 路径也应该在骨架本身上 我想使用 A star 算法的 C 实现 我找到了
  • cv2.VideoWriter:请求一个元组作为 Size 参数,然后拒绝它

    我正在使用 OpenCV 4 0 和 Python 3 7 创建延时视频 构造 VideoWriter 对象时 文档表示 Size 参数应该是一个元组 当我给它一个元组时 它拒绝它 当我尝试用其他东西替换它时 它不会接受它 因为它说参数不是
  • 如何在 cv2.VideoWriter 中使用 FPS 参数?

    好的 所以我正在制作视频 我想确切地知道如何使用 FPS 参数 它是一个浮点数 所以我假设这是我想要的每帧之间的间隔 你能给个例子吗 我只想知道视频会如何随着 FPS 参数值的变化而变化 因为我制作的视频现在太快了 谢谢 确实只是这样 fr
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件
  • 为什么Android的ImageReader类这么慢?

    我尝试了适用于 Android 3 4 1 的全新 OpenCVJavaCamera2View但它太慢了 仅显示相机视图约 15 fps 当我尝试较旧的JavaCameraView相反 它给了我很好的结果 30fps 这是我相机的极限 我想
  • 查找具有不同强度/亮度的相似图像

    假设我有如下图像 我可以选择什么来比较两个图像之间的相似度 显然它们是相同的图像 只是亮度不同 我找不到任何可行的方法 目前我最好的选择是训练 cnn 或自动编码器并比较输出的特征向量 但这似乎有点矫枉过正 任何提示将不胜感激 相当强大的工
  • 如何检测斑点并将其裁剪成 png 文件?

    我一直在开发一个网络应用程序 我陷入了一个有问题的问题 我会尝试解释我想要做什么 在这里您看到第一个大图像 其中有绿色形状 我想要做的是将这些形状裁剪成不同的 png 文件 并使它们的背景透明 就像大图像下面的示例裁剪图像一样 第一张图像将
  • HoughLinesP后如何合并线?

    My task is to find coordinates of lines startX startY endX endY and rectangles 4 lines Here is input file 我使用下一个代码 img c
  • Opencv 2.4.2 代码讲解-人脸识别

    我参考OpenCV提供的文档制作了一个人脸识别程序 可以识别多个人脸 并且工作正常 在文档中 他们制作了省略号来突出显示脸部 我不明白的是他们如何计算椭圆的中心 他们的计算如下 for int i 0 i lt faces size i P
  • 将图像加载到现有 Mat 中

    有没有办法将图像加载到现有的 Mat 中 如果没有 有没有办法控制 OpenCV 在调用 cv imread 时分配内存的位置 我只是为您的类创建一个构造函数 该构造函数接受 imread 的输入参数并将图像直接加载 并分配 到您的类中 所
  • 如何在python 3.8中安装opencv-python

    我在 pycharm 中安装 opencv python 时遇到问题 打开 pycharm 后 我单击 设置 然后单击 项目解释器 单击 并搜索正确的模块 我开始安装 但失败了 Could not find a version that s
  • 静态 OpenCV 库中未定义的引用

    我有一个使用 OpenCV 3 1 的 C 项目 并且使用共享库可以正常工作 但现在我想使用静态库 位于项目目录中的文件夹中 来编译它 因为我希望能够在未安装 OpenCV 的情况下导出它 如果需要还可以编辑和重新编译 这次我重新编译了 O
  • 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点)

    在用于图像分类的tensorflow lite android演示代码中 图像首先转换为ByteBuffer格式以获得更好的性能 这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一个昂贵的操作 循环 按位运算符 float mem
  • OpenCV Sobel 滤波器 - 为什么它看起来这么糟糕,尤其是与 Gimp 相比?

    我正在尝试使用 OpenCV 重建一些我之前在 Gimp 中完成的预处理 第一级是用于边缘检测的 Sobel 滤波器 它在 Gimp 中运行得很好 现在这是我对 OpenCV 的尝试 opencv imgproc Sobel src sca
  • 在 virtualenvwrapper 中激活环境

    我安装了virtualenv and virtualenvwrapper用这个命令我创建了一个环境 mkvirtualenv cv 它有效 创建后我就处于新环境中 现在我重新启动了我的电脑 我想activate又是那个环境 但是怎么样 我使
  • 在openCV内部调用Gstreamer

    我需要在 openCV 代码中调用 Gstremaer 本质上是打开摄像机 当我查看源代码时 modules highgui src cap gstreamer cpp似乎是我正在寻找的文件 我用 Gstreamer 标志编译了 OpenC
  • Python 2.7/OpenCV 3.3: cv2.initUn DistorifyMap 中出现错误。不显示不扭曲的校正图像

    我想扭曲并校正我的立体图像 为此 我在 Python 2 7 中使用了 Opencv 3 3 我使用的代码是 import cv2 import numpy as np cameraMatrixL np load mtx left npy
  • 从基本矩阵中查找单应矩阵

    我正在尝试计算单应性矩阵H给定一组对应关系和基本矩阵F 根据对极几何原理 我知道这可以通过对极线和对极线的叉积来完成F from 极点几何 http www cs unc edu marc tutorial node44 html e ij

随机推荐

  • 基于Umi搭建的个人Dva脚手架(一) - 框架说明

    1 基本概念阐述 阅读本文前 你需要对react dva umi以及ant design的有一定的认识 具体的相关知识都可以参考官方文档 Umi 中文可发音为乌米 是一个可插拔的企业级 react 应用框架 是蚂蚁金服的底层前端框架 具体的
  • 语义化版本(SemVer)的范围

    转自 http www u396 com semver range html 在使用 Node js 和 Bower 的时候 其中的 package json 和 bower json 都会有 dependencies devDepende
  • 如何将jar加入自己的maven本地仓库

    本文介绍如何将本地的jar加入到自己的maven本地仓库中 直接在pom文件引用依赖即可 无需手动添加jar文件 一 检查mvn命令 有同学没有配置过maven环境变量 使用mvn命令时 会提示 mvn 不是内部或外部命令 也不是可运行的程
  • 前端框架react----条件渲染、循环处理、受控组件

    一 条件渲染 很多时候 用户可能会有多种操作需求 这个时候就需要我们对不同的操作选择不同的执行逻辑 在react中 你可以创建不同的组件来封装各种你需要的行为 react中的条件渲染和JavaScript中的一样 使用JavaScript运
  • 怎么修改服务器里面的权限设置,怎样修改上传服务器文件的权限设置

    怎样修改上传服务器文件的权限设置 内容精选 换一换 执行chmod R 777 导致CentOS云服务器根目录权限设置成777 系统中的大部分服务以及命令无法使用 此时可通过系统自带的getfacl命令来拷贝和还原系统权限 本节操作介绍误操
  • 电脑键盘练习_用键盘打字怎样才能练得快,有什么窍门没?

    键盘打字速度提升是没有绝对的窍门 唯一的方法是熟悉好键盘布局后勤加练习 熟练指法和输入 练习的方法还可以使用专门的打字练习软件 比如说是使用 金山打字通 以下是详细介绍 1 金山打字通是专门为初学电脑输入者而开发的一款软件 金山打字通可根据
  • Malformed version string ‘~‘: invalid character(s)

    conda upgrade n base c defaults override channels conda
  • 数学建模(生物数学篇)之 MATLAB在求解高阶微分方程时的应用实例(3/3)

    一 实验目的 理解并掌握利用MATLAB在求解高阶微分方程时的应用 二 实验内容 求解高阶微分方程时 可想办法将其变为几个一阶微分方程组成的微分方程组 例1 选择变量 可得出一阶微分方程组为 例2 设系统模型以二元方程组形式给出 试将其转化
  • IDEA实现 springmvc的简单注册登录

    IDEA实现 springmvc的简单登录 1 基本环境搭建 spring简介 SpringMVC框架是以请求为驱动 围绕Servlet设计 将请求发给控制器 然后通过模型对象 分派器来展示请求结果视图 其中核心类是DispatcherSe
  • 我同情那些不写单元测试的傻瓜

    J Timothy King写了一篇很棒的文章 先写单元测试的12个好处 Twelve Benefits of Writing Unit Tests First 遗憾的是 他在文章最后说的话完全是画蛇添足 然而 如果你不愿意改掉先写代码的老
  • java实现【国密SM4】加密解密-CBC模式

    网上有很多个版本 但是算法都是一样的 有可能使用相同的参数来加密解密文本得到的加密字符是不一样的 在此统一说下 SM4实现的功能 商业加密 SM4功能是加密文本 例如客户A把字符串 hello world 通过SM4的cbc模式加密后得到密
  • Kali Hyper-V安装正常启动后 黑屏 只能进命令模式

    问题 Hyper V安装虚拟机Kali系统一切安装正常 没有出现错误 安装成功后重启 只能进入命令模式 tt1 tt6 进不去GUI桌面 尝试 一代二代虚拟硬盘都试过 同样问题 只能开进后进入命令模式 在命令模式下一切运行正常 也修复过系统
  • 深入理解 Python 中的元类

    1 类是如何产生的 类是如何产生 这个问题肯定很傻 实则不然 很多初学者只知道使用继承的表面形式来创建一个类 却不知道其内部真正的创建是由type来创建的 type 这不是判断对象类型的函数吗 是的 type通常用法就是用来判断对象的类型
  • 快速查看自己的全部文章,帮助下找不到私人发布的小伙伴

    刚刚加入csdn 不知道自己发布过的文章在哪 可以点击链接直接查看 CSDN
  • 深度学习神经网络优化器总结

    深度学习神经网络优化器有以下几种 1 梯度下降法 Gradient Descent 2 随机梯度下降法 Stochastic Gradient Descent 3 批量梯度下降法 Batch Gradient Descent 4 动量法 M
  • win10录完指纹要求验证pin,输完pin闪退

    win10用了几个月指纹会失效 重新设置指纹会因为无法设置pin码而失败 目前解决方案将Credential Manager服务改为自动并启用 每个人指纹失效的原因不一样 我把网上能搜到的都试了一遍不行 这是自己摸索的 不一定能解决每个人的
  • Linux 使用 cp 命令强制覆盖功能

    我们平时在 Linux 中使用 cp 命令时 当把文件从一个目录复制到另一个目录 且目录中具有同名文件时 系统会提示输入 y 来确认是否覆盖同名文件 如果文件少的话 也无关紧要 但文件多的话 要一个一个确认简直太累了 更要命的是 即使我们加
  • 蓝牙模块怎么使用_有线音箱完美升级蓝牙功能,只需2杯咖啡钱!

    文章作者 噩梦飘雷结束一天繁忙的工作 相信很多人都跟小值一样 喜欢打开手机 播放起自己喜欢的歌单 音乐响起 就能双脚离地 暂时漂浮于眼前的苟且之上 让自己喘口气 当然比起戴上耳机安静地狂欢 外放音乐 让音符充满房间 是种更身临其境的享受 在
  • 【PAT甲级】1074 Reversing Linked List (25 point(s))

    Given a constant K K K and a singly linked list L L L you are supposed to reverse the links of every
  • 【ESP32-CAM】使用opencv获取ESP32-CAM视频流,并将图像保存至TF卡(一)

    VSCode python opencv ESP32 CAM 本项目仅作为学习记录 不定时更新 Arduino 对于ESP32 CAM 我们使用Arduino来开发 首先需要准备一些硬件 ESP32 CAM 在淘宝大约30rmb一个 烧录底