ESP32-CAM 使用 webcam 摄像头实时查看视频

打印 上一主题 下一主题

主题 1843|帖子 1843|积分 5531

0 ESP32cam 介绍

ESP32-CAM 是小尺寸的摄像头模组该模块可以作为最小系统独立工作,尺寸仅为 2740.54.5mm,可广泛应用于各种物联网场合,适用于家庭智能设备、工业无线控制、无线监控、QR 无线辨认,无线定位系统信号以及别的物联网应用,是物联网应用的理想办理方案。

产物特性:


  • 采用低功耗双核32位CPU,可作应用处置惩罚器
  • 主频高达240MHz,运算能力高达 600 DMIPS
  • 内置 520 KB SRAM,外置8MB PSRAM
  • 支持UART/SPI/I2C/PWM/ADC/DAC等接口
  • 支持OV2640和OV7670摄像头,内置闪光灯
  • 支持图片WiFI上传
  • 支持TF卡
  • 支持多种休眠模式。
  • 内嵌Lwip和FreeRTOS
  • 支持 STA/AP/STA+AP 工作模式
  • 支持 Smart Config/AirKiss 一键配网
  • 支持二次开发
ESP32cam 的接口引脚图如下所示:

1 arduino IDE

1.1 安装 arduino IDE

下载官方网址:https://www.arduino.cc/en/software
下载符合自己操纵系统版本的IDE并安装。
1.2 arduino IDE 获取 ESP32 开发环境

由于 arduino IDE 中自己是没有 ESP32 的开发版,必要手动进行安装,安装方式如下:


  • 打开 Arduino IDE ,找到 文件>首选项 ,将 ESP32 的配置链接填入附加开发板管理网址中。
    1. # 配置链接
    2.   https://dl.espressif.com/dl/package_esp32_index.json
    复制代码

  • 在 Arduino IDE 中,找到 工具>开发板>开发板开发板管理,搜索 ESP32 大概直接选择 ESP32 Wrover Module


2 内网视频实时查看

2.1 选择 文件>示例>ESP32>Camera>CameraWebServer ,进入示例代码界面


2.2 修改示例代码中的相干参数



  • 修改示例代码中的 wifi 和密码的名称。
  • 修改示例代码中的摄像头类型为 CAMERA_MODEL_AI_THINKER 。

2.3 运行结果

上传乐成后,按一下 ESP32cam 开发板上的 RST 按键 ,重新启动开发板。
选择 工具>串口监督器,查看串口中输出的 ip,并用浏览器打开 ip 即可实时查看视频画面。


2.4 代码

  1. #include "esp_camera.h"
  2. #include <WiFi.h>
  3. //
  4. // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
  5. //            Ensure ESP32 Wrover Module or other board with PSRAM is selected
  6. //            Partial images will be transmitted if image exceeds buffer size
  7. //
  8. // Select camera model
  9. // #define CAMERA_MODEL_WROVER_KIT // Has PSRAM
  10. //#define CAMERA_MODEL_ESP_EYE // Has PSRAM
  11. //#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
  12. //#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
  13. //#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
  14. //#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
  15. #define CAMERA_MODEL_AI_THINKER // Has PSRAM
  16. //#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
  17. #include "camera_pins.h"
  18. const char* ssid = "TP-LINK_1760";
  19. const char* password = "987654321";
  20. void startCameraServer();
  21. void setup() {
  22.   Serial.begin(115200);
  23.   Serial.setDebugOutput(true);
  24.   Serial.println();
  25.   camera_config_t config;
  26.   config.ledc_channel = LEDC_CHANNEL_0;
  27.   config.ledc_timer = LEDC_TIMER_0;
  28.   config.pin_d0 = Y2_GPIO_NUM;
  29.   config.pin_d1 = Y3_GPIO_NUM;
  30.   config.pin_d2 = Y4_GPIO_NUM;
  31.   config.pin_d3 = Y5_GPIO_NUM;
  32.   config.pin_d4 = Y6_GPIO_NUM;
  33.   config.pin_d5 = Y7_GPIO_NUM;
  34.   config.pin_d6 = Y8_GPIO_NUM;
  35.   config.pin_d7 = Y9_GPIO_NUM;
  36.   config.pin_xclk = XCLK_GPIO_NUM;
  37.   config.pin_pclk = PCLK_GPIO_NUM;
  38.   config.pin_vsync = VSYNC_GPIO_NUM;
  39.   config.pin_href = HREF_GPIO_NUM;
  40.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  41.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  42.   config.pin_pwdn = PWDN_GPIO_NUM;
  43.   config.pin_reset = RESET_GPIO_NUM;
  44.   config.xclk_freq_hz = 20000000;
  45.   config.pixel_format = PIXFORMAT_JPEG;
  46.   
  47.   // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  48.   //                      for larger pre-allocated frame buffer.
  49.   if(psramFound()){
  50.     config.frame_size = FRAMESIZE_UXGA;
  51.     config.jpeg_quality = 10;
  52.     config.fb_count = 2;
  53.   } else {
  54.     config.frame_size = FRAMESIZE_SVGA;
  55.     config.jpeg_quality = 12;
  56.     config.fb_count = 1;
  57.   }
  58. #if defined(CAMERA_MODEL_ESP_EYE)
  59.   pinMode(13, INPUT_PULLUP);
  60.   pinMode(14, INPUT_PULLUP);
  61. #endif
  62.   // camera init
  63.   esp_err_t err = esp_camera_init(&config);
  64.   if (err != ESP_OK) {
  65.     Serial.printf("Camera init failed with error 0x%x", err);
  66.     return;
  67.   }
  68.   sensor_t * s = esp_camera_sensor_get();
  69.   // initial sensors are flipped vertically and colors are a bit saturated
  70.   if (s->id.PID == OV3660_PID) {
  71.     s->set_vflip(s, 1); // flip it back
  72.     s->set_brightness(s, 1); // up the brightness just a bit
  73.     s->set_saturation(s, -2); // lower the saturation
  74.   }
  75.   // drop down frame size for higher initial frame rate
  76.   s->set_framesize(s, FRAMESIZE_QVGA);
  77. #if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  78.   s->set_vflip(s, 1);
  79.   s->set_hmirror(s, 1);
  80. #endif
  81.   WiFi.begin(ssid, password);
  82.   while (WiFi.status() != WL_CONNECTED) {
  83.     delay(500);
  84.     Serial.print(".");
  85.   }
  86.   Serial.println("");
  87.   Serial.println("WiFi connected");
  88.   startCameraServer();
  89.   Serial.print("Camera Ready! Use 'http://");
  90.   Serial.print(WiFi.localIP());
  91.   Serial.println("' to connect");
  92. }
  93. void loop() {
  94.   // put your main code here, to run repeatedly:
  95.   delay(10000);
  96. }
复制代码
3 烧录步伐到 ESP32cam 开发板中

3.1 通过配套的下载器进行下载




  • 将下载器与 ESP32cam 安装到一起,使用数据线链接到电脑,安装商家提供的驱动,之后在 工具选项中选择对应的 开发板与串口。

  • 然后点击左上角的编译验证按钮进行编译,编译乐成后点击旁边的上传按钮烧录到 ESP32cam 开发板中。

3.2 通过 USB转TTL(CH340)下载器进行下载


USB转TTL下载器仅仅是连接线上与配套送的下载器差别,其他下载步调是一样的。
USB转TTL下载器与 ESP32cam 的链接线如下:


  • USB转TTL VCC 接 ESP32cam 5V
  • USB转TTL GND 接 ESP32cam GND
  • USB转TTL RXD 接 ESP32cam TXD
  • USB转TTL TXD 接 ESP32cam RXD
  • 下载时,必要将 GPIO1 接到 GND 上,用来启动下载模式。
4 外网视频实时查看

外网视频实时查看分为:


  • esp32cam 开发板中运行的步伐;
  • 服务器中运行的步伐。
通过ESP32cam 将视频数据发送的服务器中,服务器运行接受步伐进行接收并展示,如许的好处是可以发送到外部公网服务器中。
esp32cam 中的步伐如下:
  1. #include <Arduino.h>
  2. #include <WiFi.h>
  3. #include "esp_camera.h"
  4. #include <vector>
  5. const char *ssid = "TP-LINK_1760";
  6. const char *password = "987654321";
  7. const IPAddress serverIP(192,168,1,104); //欲访问的地址,即服务器的ip,可内网也可公网
  8. uint16_t serverPort = 18080;         //服务器端口号
  9. # MTU
  10. #define maxcache 1430
  11. WiFiClient client; //声明一个客户端对象,用于与服务器进行连接
  12. //CAMERA_MODEL_AI_THINKER类型摄像头的引脚定义
  13. #define PWDN_GPIO_NUM     32
  14. #define RESET_GPIO_NUM    -1
  15. #define XCLK_GPIO_NUM      0
  16. #define SIOD_GPIO_NUM     26
  17. #define SIOC_GPIO_NUM     27
  18. #define Y9_GPIO_NUM       35
  19. #define Y8_GPIO_NUM       34
  20. #define Y7_GPIO_NUM       39
  21. #define Y6_GPIO_NUM       36
  22. #define Y5_GPIO_NUM       21
  23. #define Y4_GPIO_NUM       19
  24. #define Y3_GPIO_NUM       18
  25. #define Y2_GPIO_NUM        5
  26. #define VSYNC_GPIO_NUM    25
  27. #define HREF_GPIO_NUM     23
  28. #define PCLK_GPIO_NUM     22
  29. static camera_config_t camera_config = {
  30.     .pin_pwdn = PWDN_GPIO_NUM,
  31.     .pin_reset = RESET_GPIO_NUM,
  32.     .pin_xclk = XCLK_GPIO_NUM,
  33.     .pin_sscb_sda = SIOD_GPIO_NUM,
  34.     .pin_sscb_scl = SIOC_GPIO_NUM,
  35.    
  36.     .pin_d7 = Y9_GPIO_NUM,
  37.     .pin_d6 = Y8_GPIO_NUM,
  38.     .pin_d5 = Y7_GPIO_NUM,
  39.     .pin_d4 = Y6_GPIO_NUM,
  40.     .pin_d3 = Y5_GPIO_NUM,
  41.     .pin_d2 = Y4_GPIO_NUM,
  42.     .pin_d1 = Y3_GPIO_NUM,
  43.     .pin_d0 = Y2_GPIO_NUM,
  44.     .pin_vsync = VSYNC_GPIO_NUM,
  45.     .pin_href = HREF_GPIO_NUM,
  46.     .pin_pclk = PCLK_GPIO_NUM,
  47.    
  48.     .xclk_freq_hz = 20000000,
  49.     .ledc_timer = LEDC_TIMER_0,
  50.     .ledc_channel = LEDC_CHANNEL_0,
  51.    
  52.     .pixel_format = PIXFORMAT_JPEG,
  53.     // .frame_size = FRAMESIZE_VGA,
  54.     // FRAMESIZE_UXGA (1600 x 1200)
  55.     // FRAMESIZE_QVGA (320 x 240)
  56.     // FRAMESIZE_CIF (352 x 288)
  57.     // FRAMESIZE_VGA (640 x 480)
  58.     // FRAMESIZE_SVGA (800 x 600)
  59.     // FRAMESIZE_XGA (1024 x 768)
  60.     // FRAMESIZE_SXGA (1280 x 1024)
  61.     .frame_size = FRAMESIZE_QVGA,
  62.     .jpeg_quality = 24,
  63.     // 图像质量(jpeg_quality) 可以是 0 到 63 之间的数字。数字越小意味着质量越高
  64.     .fb_count = 1,
  65. };
  66. void wifi_init()
  67. {
  68.     WiFi.mode(WIFI_STA);
  69.     WiFi.setSleep(false); //关闭STA模式下wifi休眠,提高响应速度
  70.     WiFi.begin(ssid, password);
  71.     while (WiFi.status() != WL_CONNECTED)
  72.     {
  73.         delay(500);
  74.         Serial.print(".");
  75.     }
  76.     Serial.println("WiFi Connected!");
  77.     Serial.print("IP Address:");
  78.     Serial.println(WiFi.localIP());
  79. }
  80. esp_err_t camera_init() {
  81.     //initialize the camera
  82.     esp_err_t err = esp_camera_init(&camera_config);
  83.     if (err != ESP_OK) {
  84.         Serial.println("Camera Init Failed");
  85.         return err;
  86.     }
  87.     sensor_t * s = esp_camera_sensor_get();
  88.     //initial sensors are flipped vertically and colors are a bit saturated
  89.     if (s->id.PID == OV2640_PID) {
  90.     //        s->set_vflip(s, 1);//flip it back
  91.     //        s->set_brightness(s, 1);//up the blightness just a bit
  92.     //        s->set_contrast(s, 1);
  93.     }
  94.     Serial.println("Camera Init OK!");
  95.     return ESP_OK;
  96. }
  97. void setup()
  98. {
  99.     Serial.begin(115200);
  100.     wifi_init();
  101.     camera_init();
  102. }
  103. void loop()
  104. {
  105.     Serial.println("Try To Connect TCP Server!");
  106.     if (client.connect(serverIP, serverPort)) //尝试访问目标地址
  107.     {
  108.         Serial.println("Connect Tcp Server Success!");
  109.         //client.println("Frame Begin");  //46 72 61 6D 65 20 42 65 67 69 6E // 0D 0A 代表换行  //向服务器发送数据
  110.         while (1){      
  111.           camera_fb_t * fb = esp_camera_fb_get();
  112.           uint8_t * temp = fb->buf; //这个是为了保存一个地址,在摄像头数据发送完毕后需要返回,否则会出现板子发送一段时间后自动重启,不断重复
  113.           if (!fb)
  114.           {
  115.               Serial.println( "Camera Capture Failed");
  116.           }
  117.           else
  118.           {
  119.             //先发送Frame Begin 表示开始发送图片 然后将图片数据分包发送 每次发送1430 余数最后发送
  120.             //完毕后发送结束标志 Frame Over 表示一张图片发送完毕
  121.             client.print("Frame Begin"); //一张图片的起始标志
  122.             // 将图片数据分段发送
  123.             int leng = fb->len;
  124.             int timess = leng/maxcache;
  125.             int extra = leng%maxcache;
  126.             for(int j = 0;j< timess;j++)
  127.             {
  128.               client.write(fb->buf, maxcache);
  129.               for(int i =0;i< maxcache;i++)
  130.               {
  131.                 fb->buf++;
  132.               }
  133.             }
  134.             client.write(fb->buf, extra);
  135.             client.print("Frame Over");      // 一张图片的结束标志
  136.             Serial.print("This Frame Length:");
  137.             Serial.print(fb->len);
  138.             Serial.println(".Succes To Send Image For TCP!");
  139.             //return the frame buffer back to the driver for reuse
  140.             fb->buf = temp; //将当时保存的指针重新返还
  141.             esp_camera_fb_return(fb);  //这一步在发送完毕后要执行,具体作用还未可知。        
  142.           }
  143.           delay(20);//短暂延时 增加数据传输可靠性
  144.         }
  145.         /*
  146.         while (client.connected() || client.available()) //如果已连接或有收到的未读取的数据
  147.         {
  148.             if (client.available()) //如果有数据可读取
  149.             {
  150.                 String line = client.readStringUntil('\n'); //读取数据到换行符
  151.                 Serial.print("ReceiveData:");
  152.                 Serial.println(line);
  153.                 client.print("--From ESP32--:Hello Server!");   
  154.             }
  155.         }
  156.         Serial.println("close connect!");
  157.         client.stop(); //关闭客户端
  158.         */
  159.     }
  160.     else
  161.     {
  162.         Serial.println("Connect To Tcp Server Failed!After 10 Seconds Try Again!");
  163.         client.stop(); //关闭客户端
  164.     }
  165.     delay(10000);
  166. }
复制代码
服务器中运行的步伐(Python):
  1. import socket
  2. import threading
  3. import time
  4. import numpy as np
  5. import cv2
  6. begin_data = b'Frame Begin'
  7. end_data = b'Frame Over'
  8. #接收数据
  9. # ESP32发送一张照片的流程
  10. # 先发送Frame Begin 表示开始发送图片 然后将图片数据分包发送 每次发送1430 余数最后发送
  11. # 完毕后发送结束标志 Frame Over 表示一张图片发送完毕
  12. # 1430 来自ESP32cam发送的一个包大小为1430 接收到数据 data格式为b''
  13. def handle_sock(sock, addr):
  14.     temp_data = b''
  15.     t1 = int(round(time.time() * 1000))
  16.     while True:
  17.         data = sock.recv(1430)
  18.         # 如果这一帧数据包的开头是 b'Frame Begin' 则是一张图片的开始
  19.         if data[0:len(begin_data)] == begin_data:
  20.             # 将这一帧数据包的开始标志信息(b'Frame Begin')清除   因为他不属于图片数据
  21.             data = data[len(begin_data):len(data)]
  22.             # 判断这一帧数据流是不是最后一个帧 最后一针数据的结尾时b'Frame Over'
  23.             while data[-len(end_data):] != end_data:
  24.                 temp_data = temp_data + data  # 不是结束的包 讲数据添加进temp_data
  25.                 data = sock.recv(1430)# 继续接受数据 直到接受的数据包包含b'Frame Over' 表示是这张图片的最后一针
  26.             # 判断为最后一个包 将数据去除 结束标志信息 b'Frame Over'
  27.             temp_data = temp_data + data[0:(len(data) - len(end_data))]  # 将多余的(\r\nFrame Over)去掉 其他放入temp_data
  28.             # 显示图片
  29.             receive_data = np.frombuffer(temp_data, dtype='uint8')  # 将获取到的字符流数据转换成1维数组
  30.             r_img = cv2.imdecode(receive_data, cv2.IMREAD_COLOR)  # 将数组解码成图像
  31.             # r_img = r_img.reshape(480, 640, 3)
  32.             # r_img = r_img.reshape(320, 240, 3)
  33.             t2 = int(round(time.time() * 1000))
  34.             fps = 1000//(t2-t1)
  35.             cv2.putText(r_img, "FPS" + str(fps), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
  36.             cv2.imshow('server_frame', r_img)
  37.             if cv2.waitKey(1) & 0xFF == ord('q'):
  38.                 break
  39.             t1 = t2
  40.             print("接收到的数据包大小:" + str(len(temp_data)))  # 显示该张照片数据大小
  41.             temp_data = b''  # 清空数据 便于下一章照片使用
  42. server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  43. # 这里的 ip 与端口是运行该程序的服务器的 ip 与端口,需要与 arduino 中的一致
  44. server.bind(('192.168.1.104', 18080))
  45. server.listen(5)
  46. CONNECTION_LIST = []
  47. #主线程循环接收客户端连接
  48. while True:
  49.     sock, addr = server.accept()
  50.     CONNECTION_LIST.append(sock)
  51.     print('Connect--{}'.format(addr))
  52.     #连接成功后开一个线程用于处理客户端
  53.     client_thread = threading.Thread(target=handle_sock, args=(sock, addr))
  54.     client_thread.start()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表