這個(gè)項(xiàng)目可以讓你在半個(gè)小時(shí)內(nèi)實(shí)現(xiàn)模型訓(xùn)練和圖像識(shí)別,非常簡單。
開始前先放效果視頻點(diǎn)擊這里
一、網(wǎng)頁顯示視頻流
現(xiàn)成資源有很多,只要稍微找下然后把程序燒錄到Esp32-Cam都可以實(shí)現(xiàn)該功能。詳細(xì)內(nèi)容前往學(xué)習(xí)即可,此處不贅述。
1、Linux式例程
可以學(xué)習(xí)安信可官網(wǎng)的例程,權(quán)威。點(diǎn)擊前往
教程很詳細(xì),有Linux基礎(chǔ)的兄弟可以嘗試一下,否則就別在這個(gè)上面折騰了(比如vim編輯器使用、shell腳本使用、linux配置等,都很費(fèi)時(shí)間,而且寡人也沒嘗試成功)
2、MicroPython式例程
這種方式是讓Esp32-Cam具備python環(huán)境,能夠運(yùn)行py文件。點(diǎn)擊前往
步驟1、下載Thonny
下載地址:https://thonny.org/
步驟2、燒錄Esp32-Cam固件
使用Thonny如果燒錄固件后無法顯示boot.py文件的話應(yīng)該是底板有問題,可以去買指定的相應(yīng)底板,但其實(shí)使用USB轉(zhuǎn)ttl,杜邦線對(duì)應(yīng)接5V、GND、TXD和RXD就可以了。
步驟3、運(yùn)行相應(yīng)代碼
import socket
import network
import camera
import time
# 連接wifi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('dongfeiqiu', 'wangmingdong1225')
while not wlan.isconnected():
pass
print('網(wǎng)絡(luò)配置:', wlan.ifconfig())
# 攝像頭初始化
try:
camera.init(0, format=camera.JPEG)
except Exception as e:
camera.deinit()
camera.init(0, format=camera.JPEG)
# 其他設(shè)置:
# 上翻下翻
camera.flip(1)
#左/右
camera.mirror(1)
# 分辨率
camera.framesize(camera.FRAME_HVGA)
# 選項(xiàng)如下:
# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD
# FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA
# FRAME_P_FHD FRAME_QSXGA
# 有關(guān)詳細(xì)信息,請(qǐng)查看此鏈接:https://bit.ly/2YOzizz
# 特效
camera.speffect(camera.EFFECT_NONE)
#選項(xiàng)如下:
# 效果\無(默認(rèn))效果\負(fù)效果\ BW效果\紅色效果\綠色效果\藍(lán)色效果\復(fù)古效果
# EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO
# 白平衡
# camera.whitebalance(camera.WB_HOME)
#選項(xiàng)如下:
# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME
# 飽和
camera.saturation(0)
#-2,2(默認(rèn)為0). -2灰度
# -2,2 (default 0). -2 grayscale
# 亮度
camera.brightness(0)
#-2,2(默認(rèn)為0). 2亮度
# -2,2 (default 0). 2 brightness
# 對(duì)比度
camera.contrast(0)
#-2,2(默認(rèn)為0).2高對(duì)比度
#-2,2 (default 0). 2 highcontrast
# 質(zhì)量
camera.quality(10)
#10-63數(shù)字越小質(zhì)量越高
# socket UDP 的創(chuàng)建
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
try:
while True:
buf = camera.capture() # 獲取圖像數(shù)據(jù)
s.sendto(buf, ("192.168.31.53", 9090)) # 向服務(wù)器發(fā)送圖像數(shù)據(jù)
time.sleep(0.1)
except:
pass
finally:
camera.deinit()
3、Arduino式例程
這個(gè)也是我發(fā)現(xiàn)最簡單的實(shí)現(xiàn)例程,而且資源也多,涉及的語言主要是C++。點(diǎn)擊前往
步驟1、下載Arduino
下載地址:點(diǎn)擊前往
步驟2、安裝Esp32-Cam庫
方法一:在IDE安裝。
(1). 文件 → 首選項(xiàng)→附加開發(fā)板管理器網(wǎng)址,修改網(wǎng)址為
https://arduino.esp8266.com/stable/package_esp8266com_index.json
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
(2). 工具 → 開發(fā)板 → 開發(fā)板管理器,搜索esp32,點(diǎn)擊安裝即可
方法二:github下載zip壓縮包作為庫
下載地址:點(diǎn)擊前往
下載zip壓縮包完成后,項(xiàng)目 →包含庫 →添加.ZIP庫
步驟3、選擇例程
工具 →開發(fā)板 →esp32 →AI Thinker ESP32-CAM
在如下位置里邊填充wifi和密碼
const char* ssid = "Your wifi name";
const char* password = "wifi password";
完整代碼截取如下
#include "esp_camera.h"
#include <WiFi.h>
//
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
// or another board which has PSRAM enabled
//
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER
#include "camera_pins.h"
const char* ssid = "Your wifi name";
const char* password = "wifi password";
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
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;
//init with high specs to pre-allocate larger buffers
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
sensor_t * s = esp_camera_sensor_get();
//initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1);//flip it back
s->set_brightness(s, 1);//up the blightness just a bit
s->set_saturation(s, -2);//lower the saturation
}
//drop down frame size for higher initial frame rate
s->set_framesize(s, FRAMESIZE_QVGA);
#if defined(CAMERA_MODEL_M5STACK_WIDE)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#endif
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}
void loop() {
// put your main code here, to run repeatedly:
delay(10000);
}
步驟4、查看運(yùn)行結(jié)果
工具→串口監(jiān)視器,然后按下esp32-cam的復(fù)位鍵
復(fù)制網(wǎng)址在網(wǎng)頁打開,即可看攝像頭實(shí)時(shí)內(nèi)容了
二、半小時(shí)內(nèi)實(shí)現(xiàn)圖像識(shí)別
1、網(wǎng)頁視頻流
和前面的Arduino例程相似,但包含的庫不是官方庫,而是這個(gè):點(diǎn)擊這里
下載該zip庫后在IDE操作包含該庫,然后復(fù)制下面代碼作為一個(gè)新工程ino文件。注意:要配置自己的板件,然后改成自己的wifi和密碼
#include "eloquent.h"
#include "eloquent/networking/wifi.h"
#include "eloquent/vision/camera/esp32/webserver.h"
// 把 'm5wide' 替換成自己的模塊,
// 支持的模塊有 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/aithinker.h"//我用的是aithinker
void setup() {
Serial.begin(115200);
delay(2000);
camera.jpeg();
camera.qqvga();
// 改成自己的wifi和密碼
while (!wifi.connectTo("Abc", "12345678"))
Serial.println("Cannot connect to WiFi");
while (!camera.begin())
Serial.println("Cannot connect to camera");
webServer.start();
Serial.print("Camera web server started at http://");
Serial.println(WiFi.localIP());
}
void loop() {
// do nothing
}
編譯燒到esp32-cam板子上后打開串口監(jiān)視器,獲取網(wǎng)址(我的是192.168.1.103),然后在網(wǎng)頁打開即可,和常規(guī)Arduino的視頻流例程差不多。
視頻窗口設(shè)這么小是為了讓視頻更加流暢。
2、通過視頻流采集目標(biāo)并訓(xùn)練
訓(xùn)練環(huán)境是Python,我這邊推薦Anaconda
簡單介紹就是:數(shù)據(jù)可視化+JupyterNotebook+Spyder
下載用不了多長時(shí)間的,然后我們只需要用其中的IDE:Spyder
下載好之后安裝everywhereml包,打開Anaconda Powershell Prompt輸入以下指令,already表示包已經(jīng)安裝好了
pip install everywhereml>=0.2.19
步驟1、新建Spyder工程
project->new project
然后把學(xué)習(xí)訓(xùn)練模型的Python工程解壓添加到工程里,點(diǎn)擊獲取Python工程
然后打開Spyder軟件如圖顯示,左邊工程文件欄目里就會(huì)顯示Python工程,此外派上用場的還有交互界面和數(shù)據(jù)可視化顯示界面
步驟2、訓(xùn)練數(shù)據(jù)獲取
復(fù)制以下代碼到交互界面并回車,從視頻流中截取目標(biāo)圖片作為模型數(shù)據(jù)支撐
from logging import basicConfig, INFO
from everywhereml.data import ImageDataset
from everywhereml.data.collect import MjpegCollector
# 給將要存放數(shù)據(jù)的文件夾命名
base_folder = 'Images_Data'
# 視頻流顯示的那個(gè)網(wǎng)頁地址
IP_ADDRESS_OF_ESP = 'http://192.168.1.103'
basicConfig(level=INFO)
try:
image_dataset = ImageDataset.from_nested_folders(
name='Dataset',
base_folder=base_folder
)
except FileNotFoundError:
mjpeg_collector = MjpegCollector(address=IP_ADDRESS_OF_ESP)
image_dataset = mjpeg_collector.collect_many_classes(
dataset_name='Dataset',
base_folder=base_folder,
duration=30
)
print(image_dataset)
然后就會(huì)彈出讓你給創(chuàng)建的類命名,我先什么都不識(shí)別所以命名none然后回車,如下圖所示
之后會(huì)顯示提示拍了1272張圖作為模型訓(xùn)練基礎(chǔ),并詢問該類是否ok
INFO:root:Captured 1272 images
Is this class ok? (y|n)
接著輸入y回車,如果是第一次的話會(huì)提示建立文件夾Images_Data存數(shù)據(jù)
INFO:root:creating D:\Esp_Cam\Spyder_Demo\Esp32_Cam\Images_Data folder
INFO:root:creating D:\Esp_Cam\Spyder_Demo\Esp32_Cam\Images_Data\none folder
Which class are you going to capture? (leave empty to exit)
打開對(duì)應(yīng)文件夾就會(huì)發(fā)現(xiàn)里邊存了拍下來的圖片數(shù)據(jù)
同樣的,我訓(xùn)練了pen、napkin
如果不想添加了,不用輸入直接回車
Which class are you going to capture? (leave empty to exit)
Are you sure you want to exit? (y|n)
然后輸入y回車退出,這時(shí)候就會(huì)顯示所訓(xùn)練的類
ImageDataset[Dataset](num_images=3704, num_labels=3, labels=['napkin', 'none', 'pen'])
步驟3、數(shù)據(jù)處理并建立模型
步驟2獲取了紙巾、筆、空白的情況下各一千多張圖片作為數(shù)據(jù)支撐
首先對(duì)圖片進(jìn)行灰化
在交互界面執(zhí)行
image_dataset = image_dataset.gray().uint8()
可以在交互界面執(zhí)行以下代碼預(yù)覽數(shù)據(jù)處理情況
image_dataset.preview(samples_per_class=10, rows_per_class=2, figsize=(20, 10), cmap='gray')
然后使用定向梯度直方圖算法進(jìn)行處理
定向梯度直方圖( Histogram of Oriented Gradients,簡稱HOG),該算法是輕量級(jí)的很適合Esp32-cam使用。
在交互界面執(zhí)行以下代碼
from everywhereml.preprocessing.image.object_detection import HogPipeline
from everywhereml.preprocessing.image.transform import Resize
pipeline = HogPipeline(
transforms=[
Resize(width=40, height=30)#此處的分辨率會(huì)影響處理時(shí)間和模型建立的準(zhǔn)確度,可自行調(diào)整
]
)
feature_dataset = pipeline.fit_transform(image_dataset)
feature_dataset.describe()
接著輸出由特征向量組成的數(shù)據(jù)集
print(pipeline)
如果想看所提取的特征量信息情況,可以繪制配對(duì)圖(pairplot)直觀感受數(shù)據(jù)
feature_dataset.plot.features_pairplot(n=200, k=8)
可以直觀的看到,這3個(gè)類(none、napkin、pen)的聚集性質(zhì)良好,但在某種程度上彼此是有混合的情況。
使用降維算法進(jìn)一步優(yōu)化
使用的降維算法是統(tǒng)一流形逼近與投影(Uniform Manifold Approximation and Projection,簡稱UMAP)
feature_dataset.plot.umap()
分析點(diǎn)聚集性質(zhì)可知,1(none)的模型最理想,0(napkin)和2(pen)的模型相對(duì)比較差。
總的來說,也算是能夠用來表征我們的數(shù)據(jù)了。
最后訓(xùn)練分類器完成模型建立
使用的建模方法叫隨機(jī)森林(Random Forest,簡稱RF)
from everywhereml.sklearn.ensemble import RandomForestClassifier
for i in range(10):
clf = RandomForestClassifier(n_estimators=5, max_depth=10)
train, test = feature_dataset.split(test_size=0.4, random_state=i)
clf.fit(train)
print('Score on test set: %.2f' % clf.score(test))
clf.fit(feature_dataset)
現(xiàn)在,我們已經(jīng)訓(xùn)練并且建好模型了
3、生成代碼移植到Esp32-Cam
(1)將HOG和RF算法轉(zhuǎn)換為可以在 Esp32-cam 上運(yùn)行的C++代碼
HOG算法獲取特征向量數(shù)據(jù)集
print(pipeline.to_arduino_file(
filename='path-to-sketch/HogPipeline.h',
instance_name='hog'
))
RF算法訓(xùn)練分類器
print(clf.to_arduino_file(
filename='path-to-sketch/HogClassifier.h',
instance_name='classifier',
class_map=feature_dataset.class_map
))
這時(shí)候就會(huì)生成兩個(gè).h文件在path-to-sketch/ 目錄下
(2)創(chuàng)建Arduino項(xiàng)目工程
ino文件里替換成以下代碼文章來源:http://www.zghlxwxcb.cn/news/detail-427132.html
#include "eloquent.h"
#include "eloquent/print.h"
#include "eloquent/tinyml/voting/quorum.h"
// 支撐的有 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/aithinker.h"//我用的是aithinker
#include "HogPipeline.h"//Spyder里生成的
#include "HogClassifier.h"//Spyder里生成的
Eloquent::TinyML::Voting::Quorum<7> quorum;
void setup() {
Serial.begin(115200);
delay(3000);
Serial.println("Begin");
camera.qqvga();
camera.grayscale();
while (!camera.begin())
Serial.println("Cannot init camera");
}
void loop() {
if (!camera.capture()) {
Serial.println(camera.getErrorMessage());
delay(1000);
return;
}
hog.transform(camera.buffer);
uint8_t prediction = classifier.predict(hog.features);
int8_t stablePrediction = quorum.vote(prediction);
if (quorum.isStable()) {
eloquent::print::printf(
Serial,
"Stable prediction: %s \t(DSP: %d ms, Classifier: %d us)\n",
classifier.getLabelOf(stablePrediction),
hog.latencyInMillis(),
classifier.latencyInMicros()
);
}
camera.free();
}
找到前面生產(chǎn)的兩個(gè).h文件,然后包含進(jìn)工程里(把兩個(gè).h文件復(fù)制到工程里邊)文章來源地址http://www.zghlxwxcb.cn/news/detail-427132.html
(3)燒錄到Esp32-Cam
到了這里,關(guān)于半小時(shí)內(nèi)實(shí)現(xiàn)Esp32-Cam模型訓(xùn)練和圖像識(shí)別的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!