Phân loại hình ảnh ESP32-CAM sử dụng Machine Learning

Phân loại hình ảnh ESP32-CAM sử dụng Machine Learning

Kết nối ESP32-CAM với cáp FTDI

Chúng tôi sẽ yêu cầu các thành phần sau cho dự án này:

  1. Bảng phát triển ESP32-CAM

  2. Cáp FTDI / Chuyển đổi USB nối tiếp sang TTL

  3. Dây kết nối

  4. Nguồn điện 5V bên ngoài (tùy chọn)

Không giống như bảng phát triển ESP32, ESP32-CAM không đi kèm với cổng USB được gắn vào nó. Vì vậy, để tải bản phác thảo chương trình lên ESP32-CAM, chúng ta sẽ cần sử dụng bộ lập trình FTDI (bộ chuyển đổi USB sang TTL Serial).

Sơ đồ sơ đồ sơ đồ chân FTDI USB sang bộ chuyển đổi nối tiếp

Bảng này cho thấy các kết nối giữa ESP32-CAM và FTDI:

ESP32-CAM

Cáp FTDI

5V

VCC

UOR (GPIO3)

TX

UOT (GPIO1)

RX

GND ·

GND ·

Kết nối chân 5V của ESP32-CAM với chân VCC của cáp FTDI để cấp nguồn. Cả hai căn cứ của hai thiết bị sẽ được kết nối chung. Chân TX của cáp FTDI sẽ được kết nối với UOR (GPIO3) của ESP32-CAM. Tương tự như vậy, chân RX sẽ được kết nối với UOT (GPIO1) của mô-đun ESP32-CAM.

Ngoài ra, bạn sẽ cần kết nối GPIO0 với GND để cho phép mô-đun ESP32-CAM chuyển sang chế độ nhấp nháy. Xóa kết nối này sau khi tải bản phác thảo chương trình lên mô-đun.

Trên một số bo mạch ESP32-CAM, bạn sẽ gặp lỗi máy dò màu nâu, do không đủ điện áp do cáp FTDI cung cấp. Trong trường hợp đó, bạn nên kết nối nguồn điện 5V bên ngoài với ESP32 như hình dưới đây:

Sơ đồ kết nối lập trình viên ESP32-CAM và FTDI để tải lên bản phác thảo

Kết nối với Clarifai

"Clarifai Inc. là một công ty trí tuệ nhân tạo chuyên về thị giác máy tính và sử dụng máy học và mạng nơ-ron sâu để xác định và phân tích hình ảnh và video."

Chúng tôi sẽ sử dụng Clarifai, một nền tảng máy học đám mây sử dụng miễn phí để có thể xác định những hình ảnh chúng tôi chụp từ ESP32-CAM của mình. Chúng tôi chỉ cần tạo một tài khoản miễn phí bằng cách nhấp vào liên kết này. Chọn 'Bắt đầu ngay bây giờ miễn phí và thiết lập tài khoản của bạn.

Clarifai thiết lập tài khoản

Sau khi thiết lập thành công tài khoản miễn phí của bạn, hãy lấy khóa API mà chúng tôi sẽ sử dụng trong khi lập trình ESP32-CAM của chúng tôi để kết nối thành công với nền tảng Clarifai.

Đi tới phần Khóa API và nhấp vào 'Tạo khóa API mới' để tạo khóa mới và ghi chú lại.

Clarifai lấy khóa API

Thiết lập Arduino IDE

Trước khi chúng tôi tiếp tục, bạn nên đảm bảo rằng bạn đã cài đặt phiên bản Arduino IDE mới nhất trên hệ thống của mình. Hơn nữa, bạn cũng nên cài đặt tiện ích bổ sung ESP32 trong Arduino IDE. Nếu IDE của bạn chưa cài đặt plugin, bạn có thể truy cập liên kết bên dưới:

Cài đặt Thư viện ArduinoJSON

Bạn sẽ phải cài đặt thư viện ArduinoJSON của Benoit Blanchon vì chúng ta sẽ xử lý tập lệnh JSON. Mở Trình quản lý thư viện Arduino của bạn bằng cách nhấp vào Phác thảo > Bao gồm thư viện > Quản lý thư viện. Nhập 'ArduinoJSON' vào tab tìm kiếm và nhấn enter. Cài đặt phiên bản thư viện 6.17.2 được đánh dấu bên dưới.

Cài đặt thư viện ArduinoJSON phiên bản 6.17.2

ESP32-CAM Phân loại hình ảnh Arduino Sketch

Mở Arduino IDE của bạn và đi tới Tệp > Mới để mở tệp mới. Sao chép mã được cung cấp bên dưới trong tệp đó. Để mã này hoạt động với bảng ESP32-CAM của bạn, bạn sẽ phải thay thế thông tin đăng nhập mạng Wi-Fi và khóa API từ Clarifai.

#include "Arduino.h"

#include "esp_camera.h"

#include <HTTPClient.h>

#include <ArduinoJson.h>

#include <base64.h>

#include <WiFi.h>

 

const char* ssid = "PTCL-BB";

const char* password = "44332211";

 

#define CAMERA_MODEL_AI_THINKER // Has PSRAM

 

#define PWDN_GPIO_NUM     32

#define RESET_GPIO_NUM    -1

#define XCLK_GPIO_NUM      0

#define SIOD_GPIO_NUM     26

#define SIOC_GPIO_NUM     27

 

#define Y9_GPIO_NUM       35

#define Y8_GPIO_NUM       34

#define Y7_GPIO_NUM       39

#define Y6_GPIO_NUM       36

#define Y5_GPIO_NUM       21

#define Y4_GPIO_NUM       19

#define Y3_GPIO_NUM       18

#define Y2_GPIO_NUM        5

#define VSYNC_GPIO_NUM    25

#define HREF_GPIO_NUM     23

#define PCLK_GPIO_NUM     22

 

 

void setup() {

  Serial.begin(115200);

  Serial.setDebugOutput(true);

  Serial.println();

 

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

  Serial.println("");

  Serial.println("WiFi Connected!");

 

  camera_config_t config;

  config.ledc_channel = LEDC_CHANNEL_0;

  config.ledc_timer = LEDC_TIMER_0;

  config.pin_d0 = Y2_GPIO_NUM;

  config.pin_d1 = Y3_GPIO_NUM;

  config.pin_d2 = Y4_GPIO_NUM;

  config.pin_d3 = Y5_GPIO_NUM;

  config.pin_d4 = Y6_GPIO_NUM;

  config.pin_d5 = Y7_GPIO_NUM;

  config.pin_d6 = Y8_GPIO_NUM;

  config.pin_d7 = Y9_GPIO_NUM;

  config.pin_xclk = XCLK_GPIO_NUM;

  config.pin_pclk = PCLK_GPIO_NUM;

  config.pin_vsync = VSYNC_GPIO_NUM;

  config.pin_href = HREF_GPIO_NUM;

  config.pin_sscb_sda = SIOD_GPIO_NUM;

  config.pin_sscb_scl = SIOC_GPIO_NUM;

  config.pin_pwdn = PWDN_GPIO_NUM;

  config.pin_reset = RESET_GPIO_NUM;

  config.xclk_freq_hz = 20000000;

  config.pixel_format = PIXFORMAT_JPEG;

  

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality

  //                      for larger pre-allocated frame buffer.

  if(psramFound()){

    config.frame_size = FRAMESIZE_QVGA;

    config.jpeg_quality = 10;

    config.fb_count = 2;

  } else {

    config.frame_size = FRAMESIZE_QVGA;

    config.jpeg_quality = 12;

    config.fb_count = 1;

  }

 

  esp_err_t err = esp_camera_init(&config);

  if (err != ESP_OK) {

    Serial.printf("Camera init failed with error 0x%x", err);

    return;

  }  

  classify();

  Serial.println("\n Going to Sleep…");

  esp_deep_sleep_start();

 

}

 

void loop(){

}

 

void classify() {

 

   camera_fb_t * fb = NULL;

   fb = esp_camera_fb_get();

   

   if(!fb) {

    Serial.println("Camera capture failed");

    return;

   }

 

  size_t size = fb->len;

  String buffer = base64::encode((uint8_t *) fb->buf, fb->len);

  String payload = "{\"inputs\": [{ \"data\": {\"image\": {\"base64\": \"" + buffer + "\"}}}]}";

 

  buffer = "";

  // Uncomment this if you want to show the payload

  Serial.println(payload);

 

  esp_camera_fb_return(fb);

  

    String model_id = "aaa03c23b3724a16a56b629203edc62c";  //General Model

  //String model_id = "bd367be194cf45149e75f01d59f77ba7";  //Food Model

 

  HTTPClient http;

  http.begin("https://api.clarifai.com/v2/models/" + model_id + "/outputs");

  http.addHeader("Content-Type", "application/json");     

  http.addHeader("Authorization", "Key 16f848599c3c4c5e8c8b5c15f4c4a457"); 

  

  int response_code = http.POST(payload);

  String response;

  

  if(response_code >0){

  Serial.print(response_code );

  Serial.print("Returned String: ");

  response = http.getString();

  Serial.println(response);

 } 

else {

 Serial.print("POST Error: ");

 Serial.print(response_code);

return;

}

 

const int jsonSize = 2*JSON_ARRAY_SIZE(0) + JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(20) + 4*JSON_OBJECT_SIZE(0) + 7*JSON_OBJECT_SIZE(1) + 5*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 21*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(18)+ 3251;

DynamicJsonDocument doc(jsonSize);

deserializeJson(doc, response );

 

for (int i=0; i < 10; i++) {

  const String name = doc["outputs"][0]["data"]["concepts"][i]["name"];

  const float prob = doc["outputs"][0]["data"]["concepts"][i]["value"];

    

  Serial.println("________________________");

  Serial.print("Name:");

  Serial.println(name);

  Serial.print("Probability:");

  Serial.println(prob);

  Serial.println();

}

 

}

Mã hoạt động như thế nào?

Bây giờ, chúng ta hãy hiểu cách thức hoạt động của từng phần của code.

Bao gồm thư viện

Đầu tiên, chúng tôi sẽ bao gồm các thư viện có liên quan cần thiết cho dự án này.
Thư viện WiFi.h được sử dụng để kết nối mô-đun ESP32 của chúng tôi với mạng WIFI cục bộ. ArduinoJSON.h sẽ được sử dụng cho tập lệnh JSON. Arduino.h và esp_camera sẽ được yêu cầu khởi tạo ESP32-CAM. Hơn nữa, chúng tôi sẽ yêu cầu base64.h mã hóa hình ảnh sang định dạng Base64 và HTTPClient.h để kết nối thành công với paltform học máy

#include "Arduino.h"

#include "esp_camera.h"

#include <HTTPClient.h>

#include <ArduinoJson.h>

#include <base64.h>

#include <WiFi.h>

Tiếp theo, chúng ta sẽ tạo hai biến toàn cục, một biến cho SSID và một biến khác cho mật khẩu. Chúng sẽ giữ thông tin đăng nhập mạng của chúng tôi sẽ được sử dụng để kết nối với bộ định tuyến không dây của chúng tôi. Thay thế cả hai bằng thông tin đăng nhập mạng của bạn để đảm bảo kết nối thành công.

const char* ssid = "YOUR_SSID";

const char* password = "YOUR_PASSWORD";

Các định nghĩa sau đây là dành cho chân mô-đun máy ảnh OV2640. Chúng tôi đang sử dụng CAMERA_MODEL_AI_THINKER.

#define CAMERA_MODEL_AI_THINKER // Has PSRAM

 

#define PWDN_GPIO_NUM     32

#define RESET_GPIO_NUM    -1

#define XCLK_GPIO_NUM      0

#define SIOD_GPIO_NUM     26

#define SIOC_GPIO_NUM     27

 

#define Y9_GPIO_NUM       35

#define Y8_GPIO_NUM       34

#define Y7_GPIO_NUM       39

#define Y6_GPIO_NUM       36

#define Y5_GPIO_NUM       21

#define Y4_GPIO_NUM       19

#define Y3_GPIO_NUM       18

#define Y2_GPIO_NUM        5

#define VSYNC_GPIO_NUM    25

#define HREF_GPIO_NUM     23

#define PCLK_GPIO_NUM     22

thiết lập()

Bên trong hàm setup(), chúng ta sẽ mở một kết nối nối tiếp với tốc độ truyền là 115200.

Serial.begin(115200)

Phần mã sau đây sẽ kết nối bo mạch ESP32-CAM của chúng tôi với mạng cục bộ có thông tin đăng nhập mạng mà chúng tôi đã chỉ định ở trên. Chúng ta sẽ sử dụng chức năng WiFi.begin(). Các đối số sẽ là SSID và mật khẩu mà chúng ta đã xác định trước đó trong code. Sau khi kết nối thành công được thiết lập, "Đã kết nối WiFi!" sẽ hiển thị trên màn hình nối tiếp.

WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

  Serial.println("");

  Serial.println("WiFi Connected!");

Đoạn mã sau đặt mô-đun máy ảnh OV2640 và các cài đặt cần thiết để chụp ảnh.

camera_config_t config;

  config.ledc_channel = LEDC_CHANNEL_0;

  config.ledc_timer = LEDC_TIMER_0;

  config.pin_d0 = Y2_GPIO_NUM;

  config.pin_d1 = Y3_GPIO_NUM;

  config.pin_d2 = Y4_GPIO_NUM;

  config.pin_d3 = Y5_GPIO_NUM;

  config.pin_d4 = Y6_GPIO_NUM;

  config.pin_d5 = Y7_GPIO_NUM;

  config.pin_d6 = Y8_GPIO_NUM;

  config.pin_d7 = Y9_GPIO_NUM;

  config.pin_xclk = XCLK_GPIO_NUM;

  config.pin_pclk = PCLK_GPIO_NUM;

  config.pin_vsync = VSYNC_GPIO_NUM;

  config.pin_href = HREF_GPIO_NUM;

  config.pin_sscb_sda = SIOD_GPIO_NUM;

  config.pin_sscb_scl = SIOC_GPIO_NUM;

  config.pin_pwdn = PWDN_GPIO_NUM;

  config.pin_reset = RESET_GPIO_NUM;

  config.xclk_freq_hz = 20000000;

  config.pixel_format = PIXFORMAT_JPEG;

  

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality

  //                      for larger pre-allocated frame buffer.

  if(psramFound()){

    config.frame_size = FRAMESIZE_QVGA;

    config.jpeg_quality = 10;

    config.fb_count = 2;

  } else {

    config.frame_size = FRAMESIZE_QVGA;

    config.jpeg_quality = 12;

    config.fb_count = 1;

  }

 

Khởi tạo ESP32-CAM:

  esp_err_t err = esp_camera_init(&config);

  if (err != ESP_OK) {

    Serial.printf("Camera init failed with error 0x%x", err);

    return;

Tiếp theo, chúng ta sẽ gọi hàm classify() sẽ chịu trách nhiệm phân loại hình ảnh

 classify();

Ngoài ra, chúng tôi sẽ giữ ESP32-CAM ở chế độ ngủ sâu sau đó và nó sẽ thức dậy sau khi ĐẶT LẠI.

  Serial.println("\n Going to Sleep…");

  esp_deep_sleep_start();

Phân loại hình ảnh

Hàm classify() trước tiên sẽ chụp hình ảnh, mã hóa nó trong base64 và sau đó áp dụng nhận dạng hình ảnh cho nó.

void classify() {

 

   camera_fb_t * fb = NULL;

   fb = esp_camera_fb_get();

   

   if(!fb) {

    Serial.println("Camera capture failed");

    return;

   }

 

  size_t size = fb->len;

  String buffer = base64::encode((uint8_t *) fb->buf, fb->len);

  String payload = "{\"inputs\": [{ \"data\": {\"image\": {\"base64\": \"" + buffer + "\"}}}]}";

  buffer = "";

  Serial.println(payload);

 

  esp_camera_fb_return(fb);

  

 

  String model_id = "aaa03c23b3724a16a56b629203edc62c";  //General Model

 

 

  //String model_id = "bd367be194cf45149e75f01d59f77ba7";  //Food Model

 

  HTTPClient http;

  http.begin("https://api.clarifai.com/v2/models/" + model_id + "/outputs");

  http.addHeader("Content-Type", "application/json");     

  http.addHeader("Authorization", "Key 16f848599c3c4c5e8c8b5c15f4c4a457"); 

  

  int response_code = http.POST(payload);

  String response;

  

  if(response_code >0){

  Serial.print(response_code );

  Serial.print("Returned String: ");

  response = http.getString();

  Serial.println(response);

 } 

else {

 Serial.print("POST Error: ");

 Serial.print(response_code);

return;

}

 

const int jsonSize = 2*JSON_ARRAY_SIZE(0) + JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(20) + 4*JSON_OBJECT_SIZE(0) + 7*JSON_OBJECT_SIZE(1) + 5*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 21*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(18)+ 3251;

DynamicJsonDocument doc(jsonSize);

deserializeJson(doc, response );

 

for (int i=0; i < 10; i++) {

  const String name = doc["outputs"][0]["data"]["concepts"][i]["name"];

  const float prob = doc["outputs"][0]["data"]["concepts"][i]["value"];

    

  Serial.println("________________________");

  Serial.print("Name:");

  Serial.println(name);

  Serial.print("Probability:");

  Serial.println(prob);

  Serial.println();

}

 

}

Trước tiên, chúng ta sẽ chụp ảnh bằng ESP32-CAM bằng cách sử dụng phương pháp esp_camera_fb_get(). Các dòng sau đây cho phép chúng tôi làm điều đó.

   camera_fb_t * fb = NULL;

   fb = esp_camera_fb_get();

   

   if(!fb) {

    Serial.println("Camera capture failed");

    return;

   }

Sau đó, chúng tôi mã hóa hình ảnh ở định dạng base64:

  size_t size = fb->len;

  String buffer = base64::encode((uint8_t *) fb->buf, fb->len);

 

  String payload = "{\"inputs\": [{ \"data\": {\"image\": {\"base64\": \"" + buffer + "\"}}}]}";

  buffer = "";

  Serial.println(payload);

Sau đó, chúng tôi sẽ kết nối với nền tảng Clarifai để sử dụng mô hình được đào tạo trước của nó để nhận dạng hình ảnh.

String model_id = "aaa03c23b3724a16a56b629203edc62c";  //General Model

Hơn nữa, bạn có thể sử dụng các mô hình được đào tạo trước khác do Clarifai cung cấp cũng như bao gồm mô hình thực phẩm, mô hình phát hiện khuôn mặt, v.v.  Chỉ cần xác định ID mô hình.

Ví dụ: nếu phân loại thực phẩm, bạn có thể sử dụng ID mẫu được liên kết với Mô hình thực phẩm:

//String model_id = "bd367be194cf45149e75f01d59f77ba7";  //Food Model

Bây giờ hãy bắt đầu kết nối giữa nền tảng Clarifai bằng cách cung cấp khóa API của bạn và ID mẫu.

HTTPClient http;

  http.begin("https://api.clarifai.com/v2/models/" + model_id + "/outputs");

  http.addHeader("Content-Type", "application/json");     

  http.addHeader("Authorization", "Key 16f84859*******e8c8b5c15f4c4a457"); 

Hơn nữa, chuyển hình ảnh được mã hóa base64 hiện được lưu trữ trong tải trọng sang nền tảng máy học đám mây.

int response_code = http.POST(payload);

  String response;

  

  if(response_code >0){

  Serial.print(response_code );

  Serial.print("Returned String: ");

  response = http.getString();

  Serial.println(response);

 } 

else {

 Serial.print("POST Error: ");

 Serial.print(response_code);

return;

}

Tiếp theo chúng ta sẽ sử dụng thư viện JSON để quản lý các khái niệm được trích xuất từ image. Chúng sẽ bao gồm các nhãn khác nhau đã được xác định cho hình ảnh với một giá trị xác suất nhất định. Chúng tôi sẽ hiển thị chúng trong màn hình nối tiếp để phân loại hình ảnh.

const int jsonSize = 2*JSON_ARRAY_SIZE(0) + JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(20) + 4*JSON_OBJECT_SIZE(0) + 7*JSON_OBJECT_SIZE(1) + 5*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 21*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(18)+ 3251;

DynamicJsonDocument doc(jsonSize);

deserializeJson(doc, response );

 

for (int i=0; i < 10; i++) {

  const String name = doc["outputs"][0]["data"]["concepts"][i]["name"];

  const float prob = doc["outputs"][0]["data"]["concepts"][i]["value"];

    

  Serial.println("________________________");

  Serial.print("Name:");

  Serial.println(name);

  Serial.print("Probability:");

  Serial.println(prob);

  Serial.println();

}

Bản demo phân loại hình ảnh ESP32 CAM

Bây giờ, chúng tôi đã sẵn sàng để biên dịch và tải mã lên ESP32-CAM của chúng tôi. Đảm bảo rằng lập trình viên FTDI được kết nối đúng cách với mô-đun và GPIO0 cũng được nối đất.

Chọn đúng bảng và cổng COM trước khi tải mã của bạn lên bảng ESP32-CAM. Đi tới Bảng > Công cụ và chọn ESP32 AI Thinker.

chọn bảng tư duy AI ESP32 CAM trong Arduino IDE

Tiếp theo, đi tới Công cụ > Cổng và chọn cổng thích hợp mà qua đó bảng của bạn được kết nối.

Nhấp vào nút tải lên để tải mã lên bảng ESP32-CAM.

Nếu bạn xem Connecting....._____....._____..... trong cửa sổ lỗi, nhấn nút RESET có trên ESP32-CAM như hình dưới đây:

Nút đặt lại CAM ESP32

Sau khi bạn đã tải thành công mã của mình lên bảng, hãy tháo dây kết nối khỏi GPIO0 và GND.

Bây giờ mở màn hình nối tiếp. Trong giây lát, Wi-Fi sẽ được kết nối và hình ảnh sẽ được chụp, mã hóa và sau đó được gửi đến nền tảng Clarifai.

Ở đây chúng tôi đã chụp được hình ảnh của một con cá trong nước, do đó mô hình được đào tạo trước đã xác định các khái niệm sau đây với xác suất cao nhất đối với cá và không có người.

Bản demo Phân loại hình ảnh ESP32-CAM1

Ở đây chúng tôi chụp ảnh những bông hoa trong khung ảnh:

Phân loại hình ảnh CAM ESP32 với Machine Learning 1

Ở đây chúng tôi đã chụp một bức ảnh của chuối:

Ở đây chúng tôi đã chụp một bức ảnh của một quả bóng:

Phân loại hình ảnh CAM ESP32 với Machine Learning 2

 

>>> 100+ Mã Sản Phẩm Dây Rút: https://mecsu.vn/san-pham/day-rut-nhua.5op

>>> 1000+ Mã Sản Phẩm Đầu Cosse: https://mecsu.vn/san-pham/dau-cosse.Q1j

Bài viết cùng chuyên mục

NHANH

NHANH

Vì Đổi mới liên tục nên Nhanh hơn

ĐÚNG

ĐÚNG

Coi trọng và ưu tiên việc làm Đúng

ĐỦ

ĐỦ

Tìm và mua Đủ Đơn hàng hơn

KỊP THỜI

KỊP THỜI

Hiệu suất tối ưu bởi Kịp Thời hơn