در این پروژه ماژول دوربین ESP32-CAM رو طوری کد نویسی می کنیم تا بتونیم با استفاده از این ماژول به تشخیص و شناسایی اشیا بپردازیم. همونطور که میدونید OpenCV یک کتابخانه پردازش تصویر متنباز است که چه در حوزه هوش مصنوعی و چه در بخش تحقیق و توسعه به طور گسترده مورد استفاده قرار میگیره.
در این پروژه برای تشخیص اشیا از کتابخانه cvlib استفاده میکنیم. این کتابخانه برای شناسایی اشیای موجود در دیتاست COCO از یک مدل هوش مصنوعی استفاده میکنه که از قبل آموزش دیده. اسم این مدل از پیش آموزش دیده شده YOLOv3 است.
در این پروژه دوربین تشخیص اشیا، ویژگیها، پینها و متد لازم برای برنامهنویسی دوربین ESP32-CAM با استفاده از ماژول FTDI رو معرفی میکنیم و Arduino IDE رو هم برای ماژول دوربین ESP32 راهاندازی میکنیم. علاوه بر این، سفتافزار (firmware) رو هم بارگذاری میکنیم و بعد هم میریم سراغ بخش اصلی پروژه یعنی شناسایی اشیا. اسکریپت تشخیص اشیا به زبان پایتون هست و برای همین باید پایتون و کتابخانههای مورد نیاز اون رو نصب کنیم.
در پروژهی قبلی در مورد ESP32-CAM بود راجع به سیستم تشخیص حرکات دست به کمک پایتون و OpenCV پرداختیم. با استفاده از لینک زیر میتونید به این پروژه دسترسی داشته باشید.
قطعات مورد نیاز
برای اجرایی سازی پروژه تشخیص و شناسایی اشیا به کمک ماژول دوربین ESP32-CAM به قطعات زیر نیاز داریم. ESP32-CAM با اتکا به سختافزارها و سفتافزارهای دیگه میتونه اشیا رو ردیابی کنه و تشخیص بده.
قطعات مورد نیاز
-
بورد ESP32-CAM (ماژول دوربین AI-Thinker ESP32)
-
ماژول FTDI (ماژول تبدیل USB به TTL)
-
کابل USB (کابل داده 5V Mini-USB)
-
سیم های جامپر (کانکتور مادگی به مادگی)
ماژول ESP32-CAM
ماژول دوربین ESP32 محصول AI-Thinker است. این کنترلر مبتنی بر یک CPU 32 بیتی هست و یک تراشه Wi-Fi + بلوتوث/BLE داره. این کنترلر یک SRAM 520 کیلوبایتی و یک 4M PSRAM خارجی داره. پینهای GPIO این کنترلر از UART، SPI، I2C، PWM، ADC و DAC پشتیبانی میکنند.
این ماژول با ماژول دوربین OV2640 ادغام میشه که بیشترین میزان وضوح دوربین (1600 × 1200) رو داره. دوربین رو میشه با استفاده از کانکتور طلایی رنگ که 24 تا پین داره به بورد ESP32-CAM وصل کرد. این بورد از کارت SD با حافظه 4 گیگابایت پشتیبانی میکنه. تصاویر ثبتشده در کارت حافظه ذخیره میشن. برای آشنایی بیشتر با ماژول دوربین ESP32 از لینک زیر استفاده کنید.
اتصال ESP32-CAM FTDI
نکته: معمولاً، زمانیکه پینها مشخص نشده باشن، بورد در زمان برقراری ارتباط SPI با تنظیمات پیشفرض از پینهای VSPI استفاده میکنه.
مثل تصویر زیر ماژول FTDI و ماژول دوربین ESP32 رو به هم وصل کنین.
پین 5V و GND بورد ESP32 رو به پین 5V و GND ماژول FTDI وصل کنین. به همین ترتیب، RX رو به UOT و TX رو به UOR وصل کنین. و مهمتر از همه اینکه باید پین IO0 رو به پین GND وصل کنین (short).
این دو تا پین رو برای این به هم وصل میکنیم که دستگاه در حالت برنامهنویسی قرار بگیره. بعد از برنامهنویسی دستگاه میتونین پینها رو از هم جدا کنین.
دانلود فایلهای گربر PCB
اگه نمیخواید مدار رو روی بردبورد وصل کنین و برای انجام پروژه به PCB نیاز دارین، میتونین از این PCB استفاده کنین. بورد PCB برای ماژول ESP32 CAM که طراحی شده مانند تصویر زیر هست:
حالا میتونین قعطات رو روی بورد وصل کنین.
نصب کتابخانه ESP32CAM
در این پروژه به جای ESP webserver example از یک فرایند پخش دیگه استفاده میکنیم. برای همین لازمه یک کتابخانه ESPCAM دیگه اضافه کنیم. کتابخانه ESP32CAM یک API شیگرا (object oriented) داره که به کمک اون میشه از دوربین OV2640 در میکروکنترلر ESP32 استفاده کرد. تصویر زیر کتابخانه ESP32Cam رو نشون میده.
پس از دانلود، این فایل زیپ رو پوشه کتابخانه Arduino اضافه کنین. برای انجام این کار طبق این مراحل پیش برین:
Arduino -> Sketch -> Include Library -> Add .ZIP Library رو باز کنین و فایل زیپ رو پیدا کنین و روی گزینه add کلیک کنین.
سورس کد اصلی ماژول دوربین ESP32 CAM
در این قسمت میتونین کد اصلی پروژهی تشخیص و شناسایی اشیاء به کمک ESP32-CAM و OpenCV رو مشاهده کنین. این کد رو در Arduino IDE کپی کنین.
#include <WebServer.h> #include <WiFi.h> #include <esp32cam.h> const char* WIFI_SSID = "ssid"; const char* WIFI_PASS = "password"; WebServer server(80); static auto loRes = esp32cam::Resolution::find(320, 240); static auto midRes = esp32cam::Resolution::find(350, 530); static auto hiRes = esp32cam::Resolution::find(800, 600);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 handleJpgMid() { if (!esp32cam::Camera.changeResolution(midRes)) { Serial.println("SET-MID-RES FAIL"); } serveJpg(); } 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-lo.jpg"); Serial.println(" /cam-hi.jpg"); Serial.println(" /cam-mid.jpg"); server.on("/cam-lo.jpg", handleJpgLo); server.on("/cam-hi.jpg", handleJpgHi); server.on("/cam-mid.jpg", handleJpgMid); server.begin(); } void loop() { server.handleClient(); }
پیش از بارگذاری کد باید چند تا تغییر جزئی در اون اعمال کنین. متغیرهای SSID و password رو مطابق با شبکه Wi-Fi خودتون تغییر بدین.
حالا کد رو بعد از کامپایل کردن در بورد ESP32-CAM بارگذاری کنین. در طول فرایند بارگذاری کد باید این کارها رو انجام بدین:
- مطمئن بشین وقتی کلید upload رو میزنین حتماً پین IO0 به ground متصل میشه.
- اگر در زمان بارگذاری با نقطه (dot) و dash مواجه شدین، فوراً کلید reset رو بزنین.
- پس از بارگذاری کد، پین IO0 رو که به Ground وصل بوده قطع کنین و یکبار دیگه کلید reset رو بزنین.
- اگه خروجی در سریال مانیتور (Serial monitor) نمایش داده نشد مجدداً کلید reset رو بزنین.
یک خروجی مثل تصویر زیر بهتون نمایش داده میشه:
آدرس IP رو اینجا کپی کنین. در ادامه با استفاده از این آدرس URL رو در کد پایتون تغییر میدیم.
نصب کتابخانه پایتون
برای اینکه بتونیم از طریق کامپیوترمون ویدئو رو به صورت زنده تماشا کنیم باید یک اسکریپت پایتون بنویسیم؛ این اسکریپت امکان بازیابی فریمهای ویدئو رو برای ما فراهم میکنه. در قدم اول باید پایتون رو نصب کنیم. به python.org برید و پایتون رو دانلود کنین.
پس از دانلود، پایتون رو نصب کنین.
حالا به command prompt برید و کتابخانههای Numpy، OpenCV و cvlib رو نصب کنین.
- pip install numpy رو تایپ کنین و کلید Enter رو بنزین.
- pip install opencv-python رو تایپ کنین و کلید enter رو بزنین.
- pip install cvlib رو تایپ کنین و کلید enter رو بزنین. حالا command promp رو ببندین.
در کد پایتون برای بازیابی فریمها از URL از urllib.request استفاده کردیم. کتابخانه پردازش تصویری هم که ازش برای انجام این پروژه استفاده کردیم OpenCV هست. در این پروژه برای تشخیص اشیا از کتابخانه Cvlib استفاده کردیم که با تکیه بر یک مدل هوش مصنوعی اشیا رو تشخیص میده. با توجه به اینکه برای انجام این پروژه به توان پردازشی نسبتاً زیادی نیاز داریم از multiprocessing استفاده کردیم که از چندین هستهی CPU استفاده میکنه.
کد پایتون برای تشخیص و شناسایی اشیا به کمک ESP32-CAM
حالا ldle code editor و یا یه ویرایشگر کد پایتون دیگه رو باز کنین.
کد زیر رو در اون کپی کنین و مطابق همین کد تغییرات لازم رو در اون اعمال کنین.
import cv2 import matplotlib.pyplot as plt import cvlib as cv import urllib.request import numpy as np from cvlib.object_detection import draw_bbox import concurrent.futures url='http://192.168.10.162/cam-hi.jpg' im=None def run1(): cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE) while True: img_resp=urllib.request.urlopen(url) imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8) im = cv2.imdecode(imgnp,-1) cv2.imshow('live transmission',im) key=cv2.waitKey(5) if key==ord('q'): break cv2.destroyAllWindows() def run2(): cv2.namedWindow("detection", cv2.WINDOW_AUTOSIZE) while True: img_resp=urllib.request.urlopen(url) imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8) im = cv2.imdecode(imgnp,-1) bbox, label, conf = cv.detect_common_objects(im) im = draw_bbox(im, bbox, label, conf) cv2.imshow('detection',im) key=cv2.waitKey(5) if key==ord('q'): break cv2.destroyAllWindows() if __name__ == '__main__': print("started") with concurrent.futures.ProcessPoolExecutor() as executer: f1= executer.submit(run1) f2= executer.submit(run2)
در این قسمت باید آدرس IP رو با IP که روی سریال مانیتور Arduino نشون داده میشه عوض کنیم. دفعهی اول که این کار رو انجام میدین، چند تا فایل (اگه نداشته باشینشون) براتون نصب میشه.
بعد از این مرحله دو تا پنجره به نام live transmission و detected بهمون نشون داده میشه.
حالا در پنجره detected میتونین اشیایی که مدل تشخیص داده و با کادر رنگی مشخص شدهاند رو مشاهده کنین.
جمع بندی
به اینصورت در این پروژه با استفاده از ماژول دوربین ESP32-CAM و همچنین بکارگیری کتابخانه های پایتون و OpenCV تونستیم اشیا رو شناسایی و تشخیص دهیم. تشخیص اشیا تقریباً در تمامی صنایع کاربرد داره. از این فناوری برای ردیابی اشیا، شمارش افراد و نظارت خودکار به کمک دوربین مدار بسته، تشخیص وسایل نقلیه و غیره استفاده میشه.