带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪

本教程介绍了使用 ESP32 摄像头网络服务器环境的 OpenCV.js 和 OpenCV 工具。例如,我们将构建一个简单的 ESP32 摄像头网络服务器,其中包括对移动物体的颜色检测和跟踪。

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第1张图片

本教程绝不是对 OpenCV 可以提供给 ESP32 摄像头网络服务器的所有内容的详尽处理。此介绍将激发更多使用 ESP32 相机的 OpenCV 工作。

这个项目/教程是基于国外作者(Andrew R. Sass)的项目创建的。

介绍

ESP32 可以作为浏览器客户端的服务器,某些型号包括一个摄像头(例如,ESP32-CAM),允许客户端在浏览器中查看静态或视频图片。HTML、JavaScript 和其它浏览器语言可以利用 ESP32 及其相机的广泛功能。

对于那些对 ESP32 相机开发板经验很少或没有经验的人,可以从以下教程开始。

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第2张图片

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第3张图片

OpenCV.js

如docs.opencv.org 中所述,OpenCV(开源计算机视觉库:http : //opencv.org)是一个包含数百种计算机视觉算法的开源库。OpenCV.js 使用 Emscripten,一个 JavaScript 的编译器,为一个不断增长的 API 库编译 OpenCV 的函数。

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第4张图片

OpenCV.js 在浏览器中运行,它允许仅具有适度 HTML 和 JavaScript 背景的人快速试用 OpenCV 功能。那些有 Esp32 相机应用背景的人已经有了这个背景。

项目概况

我们将在本教程中构建的项目创建一个允许对移动对象进行颜色跟踪的 Web 服务器。在 Web 服务器界面上,您可以使用多种配置来正确选择要跟踪的颜色。然后,浏览器将移动物体实时 x 和 y 坐标发送到 ESP32 板。

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第5张图片

这是 Web 服务器的预览。

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第6张图片

先决条件

在继续此项目之前,请确保正确安装了ESP32的环境组件。

Arduino IDE

我们将使用 Arduino IDE 对 ESP32 板进行编程。因此,您需要安装 Arduino IDE 以及 ESP32 组件:

一、ESP32开发环境搭建(arduino)

获得 ESP32 相机

该项目与任何具有 OV2640 摄像头的 ESP32 摄像头板兼容。有几种 ESP32 相机型号。

确保您知道您正在使用的相机板的引脚分配。对于最流行的开发板的引脚分配,请查看这篇文章:

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第7张图片

带有 OpenCV.js 的 ESP32-CAM Web 服务器:颜色识别和跟踪_第8张图片

ESP32-CAM AI-Thinker引脚指南:GPIO使用说明

代码 – 带有 OpenCV.js 的 ESP32-CAM

该计划由两部分组成:

  • 在 ESP32 相机上运行服务器程序
  • 在 Chrome 浏览器上运行客户端程序

该程序分为两个文件: OCV_ColorTrack_P.ino 包含服务器程序和 index_OCV_ColorTrack.h 包含客户端程序的头文件(HTML、CSS 和 JavaScript with OpenCV.js)。

创建一个名为的新 Arduino 程序 OCV_ColorTrack_P 并复制以下代码。

 
  
  1. /*********
  2. The include file, index_OCV_ColorTrack.h, the Client, is an intoduction of OpenCV.js to the ESP32 Camera environment. The Client was
  3. developed and written by Andrew R. Sass. Permission to reproduce the index_OCV_ColorTrack.h file is granted free of charge if this
  4. entire copyright notice is included in all copies of the index_OCV_ColorTrack.h file.
  5. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  6. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  7. *********/
  8. #include
  9. #include
  10. #include "esp_camera.h"
  11. #include "soc/soc.h"
  12. #include "soc/rtc_cntl_reg.h"
  13. #include "index_OCV_ColorTrack.h"
  14. // Replace with your network credentials
  15. const char* ssid = "REPLACE_WITH_YOUR_SSID";
  16. const char* password = "REPLACE_WITH_YOUR_PASSWORD";
  17. String Feedback="";
  18. String Command="",cmd="",P1="",P2="",P3="",P4="",P5="",P6="",P7="",P8="",P9="";
  19. byte ReceiveState=0,cmdState=1,strState=1,questionstate=0,equalstate=0,semicolonstate=0;
  20. //ANN:0
  21. // AI-Thinker
  22. #define PWDN_GPIO_NUM 32
  23. #define RESET_GPIO_NUM -1
  24. #define XCLK_GPIO_NUM 0
  25. #define SIOD_GPIO_NUM 26
  26. #define SIOC_GPIO_NUM 27
  27. #define Y9_GPIO_NUM 35
  28. #define Y8_GPIO_NUM 34
  29. #define Y7_GPIO_NUM 39
  30. #define Y6_GPIO_NUM 36
  31. #define Y5_GPIO_NUM 21
  32. #define Y4_GPIO_NUM 19
  33. #define Y3_GPIO_NUM 18
  34. #define Y2_GPIO_NUM 5
  35. #define VSYNC_GPIO_NUM 25
  36. #define HREF_GPIO_NUM 23
  37. #define PCLK_GPIO_NUM 22
  38. WiFiServer server(80);
  39. //ANN:2
  40. void ExecuteCommand() {
  41. if (cmd!="colorDetect") { //Omit printout
  42. //Serial.println("cmd= "+cmd+" ,P1= "+P1+" ,P2= "+P2+" ,P3= "+P3+" ,P4= "+P4+" ,P5= "+P5+" ,P6= "+P6+" ,P7= "+P7+" ,P8= "+P8+" ,P9= "+P9);
  43. //Serial.println("");
  44. }
  45. if (cmd=="resetwifi") {
  46. WiFi.begin(P1.c_str(), P2.c_str());
  47. Serial.print("Connecting to ");
  48. Serial.println(P1);
  49. long int StartTime=millis();
  50. while (WiFi.status() != WL_CONNECTED)
  51. {
  52. delay(500);
  53. if ((StartTime+5000) < millis()) break;
  54. }
  55. Serial.println("");
  56. Serial.println("STAIP: "+WiFi.localIP().toString());
  57. Feedback="STAIP: "+WiFi.localIP().toString();
  58. }
  59. else if (cmd=="restart") {
  60. ESP.restart();
  61. }
  62. else if (cmd=="cm"){
  63. int XcmVal = P1.toInt();
  64. int YcmVal = P2.toInt();
  65. Serial.println("cmd= "+cmd+" ,VALXCM= "+XcmVal);
  66. Serial.println("cmd= "+cmd+" ,VALYCM= "+YcmVal);
  67. }
  68. else if (cmd=="quality") {
  69. sensor_t * s = esp_camera_sensor_get();
  70. int val = P1.toInt();
  71. s->set_quality(s, val);
  72. }
  73. else if (cmd=="contrast") {
  74. sensor_t * s = esp_camera_sensor_get();
  75. int val = P1.toInt();
  76. s->set_contrast(s, val);
  77. }
  78. else if (cmd=="brightness") {
  79. sensor_t * s = esp_camera_sensor_get();
  80. int val = P1.toInt();
  81. s->set_brightness(s, val);
  82. }
  83. else {
  84. Feedback="Command is not defined.";
  85. }
  86. if (Feedback=="") {
  87. Feedback=Command;
  88. }
  89. }
  90. void setup() {
  91. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  92. Serial.begin(115200);
  93. Serial.setDebugOutput(true);
  94. Serial.println();
  95. camera_config_t config;
  96. config.ledc_channel = LEDC_CHANNEL_0;
  97. config.ledc_timer = LEDC_TIMER_0;
  98. config.pin_d0 = Y2_GPIO_NUM;
  99. config.pin_d1 = Y3_GPIO_NUM;
  100. config.pin_d2 = Y4_GPIO_NUM;
  101. config.pin_d3 = Y5_GPIO_NUM;
  102. config.pin_d4 = Y6_GPIO_NUM;
  103. config.pin_d5 = Y7_GPIO_NUM;
  104. config.pin_d6 = Y8_GPIO_NUM;
  105. config.pin_d7 = Y9_GPIO_NUM;
  106. config.pin_xclk = XCLK_GPIO_NUM;
  107. config.pin_pclk = PCLK_GPIO_NUM;
  108. config.pin_vsync = VSYNC_GPIO_NUM;
  109. config.pin_href = HREF_GPIO_NUM;
  110. config.pin_sscb_sda = SIOD_GPIO_NUM;
  111. config.pin_sscb_scl = SIOC_GPIO_NUM;
  112. config.pin_pwdn = PWDN_GPIO_NUM;
  113. config.pin_reset = RESET_GPIO_NUM;
  114. config.xclk_freq_hz = 20000000;
  115. config.pixel_format = PIXFORMAT_JPEG;
  116. //init with high specs to pre-allocate larger buffers
  117. if(psramFound()){
  118. config.frame_size = FRAMESIZE_UXGA;
  119. config.jpeg_quality = 10; //0-63 lower number means higher quality
  120. config.fb_count = 2;
  121. } else {
  122. config.frame_size = FRAMESIZE_SVGA;
  123. config.jpeg_quality = 12; //0-63 lower number means higher quality
  124. config.fb_count = 1;
  125. }
  126. // camera init
  127. esp_err_t err = esp_camera_init(&config);
  128. if (err != ESP_OK) {
  129. Serial.printf("Camera init failed with error 0x%x", err);
  130. delay(1000);
  131. ESP.restart();
  132. }
  133. //drop down frame size for higher initial frame rate
  134. sensor_t * s = esp_camera_sensor_get();
  135. s->set_framesize(s, FRAMESIZE_CIF); //UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA 設定初始化影像解析度
  136. WiFi.mode(WIFI_AP_STA);
  137. WiFi.begin(ssid, password);
  138. delay(1000);
  139. long int StartTime=millis();
  140. while (WiFi.status() != WL_CONNECTED) {
  141. delay(500);
  142. if ((StartTime+10000) < millis())
  143. break;
  144. }
  145. if (WiFi.status() == WL_CONNECTED) {
  146. Serial.print("ESP IP Address: http://");
  147. Serial.println(WiFi.localIP());
  148. }
  149. server.begin();
  150. }
  151. void loop() {
  152. Feedback="";Command="";cmd="";P1="";P2="";P3="";P4="";P5="";P6="";P7="";P8="";P9="";
  153. ReceiveState=0,cmdState=1,strState=1,questionstate=0,equalstate=0,semicolonstate=0;
  154. WiFiClient client = server.available();
  155. if (client) {
  156. String currentLine = "";
  157. while (client.connected()) {
  158. if (client.available()) {
  159. char c = client.read();
  160. getCommand(c);
  161. if (c == 'n') {
  162. if (currentLine.length() == 0) {
  163. if (cmd=="colorDetect") {
  164. camera_fb_t * fb = NULL;
  165. fb = esp_camera_fb_get();
  166. if(!fb) {
  167. Serial.println("Camera capture failed");
  168. delay(1000);
  169. ESP.restart();
  170. }
  171. //ANN:1
  172. client.println("HTTP/1.1 200 OK");
  173. client.println("Access-Control-Allow-Origin: *");
  174. client.println("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
  175. client.println("Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS");
  176. client.println("Content-Type: image/jpeg");
  177. client.println("Content-Disposition: form-data; name="imageFile"; filename="picture.jpg"");
  178. client.println("Content-Length: " + String(fb->len));
  179. client.println("Connection: close");
  180. client.println();
  181. uint8_t *fbBuf = fb->buf;
  182. size_t fbLen = fb->len;
  183. for (size_t n=0;n
  184. if (n+1024
  185. client.write(fbBuf, 1024);
  186. fbBuf += 1024;
  187. }
  188. else if (fbLen%1024>0) {
  189. size_t remainder = fbLen%1024;
  190. client.write(fbBuf, remainder);
  191. }
  192. }
  193. esp_camera_fb_return(fb);
  194. }
  195. else {
  196. //ANN:1
  197. client.println("HTTP/1.1 200 OK");
  198. client.println("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
  199. client.println("Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS");
  200. client.println("Content-Type: text/html; charset=utf-8");
  201. client.println("Access-Control-Allow-Origin: *");
  202. client.println("Connection: close");
  203. client.println();
  204. String Data="";
  205. if (cmd!="")
  206. Data = Feedback;
  207. else {
  208. Data = String((const char *)INDEX_HTML);
  209. }
  210. int Index;
  211. for (Index = 0; Index < Data.length(); Index = Index+1000) {
  212. client.print(Data.substring(Index, Index+1000));
  213. }
  214. client.println();
  215. }
  216. Feedback="";
  217. break;
  218. } else {
  219. currentLine = "";
  220. }
  221. }
  222. else if (c != 'r') {
  223. currentLine += c;
  224. }
  225. if ((currentLine.indexOf("/?")!=-1)&&(currentLine.indexOf(" HTTP")!=-1)) {
  226. if (Command.indexOf("stop")!=-1) {
  227. client.println();
  228. client.println();
  229. client.stop();
  230. }
  231. currentLine="";

你可能感兴趣的:(opencv)