資料介紹
描述
這是我在 TensorFlow 下與 Google Summer of Code (GSoC) 合作的第二個項目。互聯網上沒有合適的文檔來構建自定義圖像識別 TinyML 模型,因此我的 GSoC 導師 Paul Ruiz 建議我嘗試解決它。您還可以通過以下方式構建圖像識別 TinyML 應用程序。快樂修補!
項目背后的想法:
我想解決一個變量較少的問題,因為有關如何使用相機模塊和處理其數據的文檔不是很好。我選擇構建一個 MNIST TinyML 模型,因為在這種情況下,我不需要擔心訓練數據集,它可以讓我專注于項目的重要部分,以啟動和運行項目。但是,既然我已經了解了構建自定義圖像識別項目的所有部分,我已經記錄了如何使用相機模塊收集訓練數據集。
博客的主題/基調?
我想警告您,這個博客可能有點難以理解。對此有一個正確的解釋:使用基于加速度計的應用程序,只需在串行監視器或繪圖儀上打印出一個軸的加速度計值,就可以很容易地進行健全性檢查。相比之下,對圖像識別應用程序進行健全性檢查至少要煩人 10 倍,因為檢查一段代碼是否正在執行所需的操作無法實時可視化。
一些評論
由于單元測試的復雜性,這篇博客可能有點難以理解。我想通過讀者的反饋來解決解釋中的任何差距。因此,請在下方評論您對嵌入式系統圖像識別相關的任何疑問和問題。
TinyML 有意義嗎?
我建議您通讀 TinyML 書的作者 Pete Warden 的這篇精彩文章,以了解為什么在微控制器上運行機器學習模型是有意義的,并且是機器學習的未來。
即使 TinyML 有意義,圖像識別在 TinyML 上有意義嗎?
我們將在此處使用的 OV7670 相機輸出的完整 VGA(640×480 分辨率)對于當前的 TinyML 應用程序來說太大了。uTensor 通過使用 28×28 圖像的 MNIST 運行手寫檢測。TensorFlow Lite for Microcontrollers 示例中的人員檢測示例使用 96×96,這已經足夠了。即使是最先進的“Big ML”應用程序也通常只使用 320×320 的圖像。總之,在微型微控制器上運行圖像識別應用程序非常有意義
本教程簡而言之:
- 接線
- OV7670攝像頭模組介紹
- RGB888 與 RGB565
- 結論
1、接線
1.a Arduino Nano 33 BLE Sense 引出線
1.b 原理圖
1.c Arduino Nano 33 BLE Sense - OV7670 攝像頭模塊
OV7670 相機模塊上的引腳 - Arduino Nano 33 BLE Sense 上的引腳
3.3 至 3.3V
接地到接地
SIOC 至 A5
SIOD 至 A4
VSYNC 至 8
HREF 到 A1
PCLK 到 A0
XCLK 至 9
D7 至 4
D6至6
D5至5
D4 至 3
D3 至 2
D2 至 0 / RX
D1 到 1 / TX
D0 至 10
1.d Arduino Nano 33 BLE Sense - TFT LCD 模塊
1.44" TFT LCD 顯示屏上的引腳 - Arduino Nano 33 BLE Sense 上的引腳
注意:Arduino 板上只有一個 3.3V。使用面包板與其建立多個連接。
LED 至 3.3V
SCK 至 13
SDA 至 11
A0 至 A6
重置為 7
CS到A7
接地到接地
VCC 至 5V
注意:連接到 Arduino 板的 TFT LCD 模塊使用硬件 SPI 引腳。
SPI代表串行外設接口。微控制器使用它與一個或多個外圍設備快速通信。SPI 通信比 I2C 通信更快。
所有外圍設備共有三個公共引腳:
SCK - 它代表串行時鐘。該引腳產生時鐘脈沖,用于同步數據傳輸。
MISO - 它代表主輸入/從輸出。MISO 引腳中的這條數據線用于向主機發送數據。
MOSI - 它代表主輸出/從輸入。該線用于向從站/外圍設備發送數據。
開發板上的 SPI 引腳:
- D13-SCK
- D12 - 味噌
- D11 - 莫西
我們將只在此處使用 SCK 和 MOSI 引腳,因為我們將向 TFT 發送數據并且不需要 MISO 引腳。
二、OV7670攝像頭模組介紹
2.a OV7670模塊的一般信息
OV7670 攝像頭模塊是一款低成本的 0.3 兆像素 CMOS 彩色攝像頭模塊。它可以 30fps 的速度輸出 640x480 VGA 分辨率的圖像。
特征:
- 低光操作的高靈敏度
- 嵌入式便攜式應用的低工作電壓
- 鏡頭陰影校正
- 閃爍 (50/60 Hz) 自動檢測
- 降噪電平自動調整
- 支持圖像尺寸:VGA、CIF 以及從 CIF 縮小到 40x30 的任何尺寸
- 用于子采樣的 VarioPixel 方法
- 自動圖像控制功能包括:自動曝光控制(AEC)、自動增益控制(AGC)、自動白平衡(AWB)、自動帶狀濾波器(ABF)、自動黑電平校準(ABLC)
- ISP 包括降噪和缺陷校正
- 支持LED和閃光燈頻閃模式
- 支持縮放
- 輸出支持 Raw RGB、RGB(GRB 4:2:2、RGB565/555/444)、YUV (4:2:2) 和 YCbCr (4:2:2) 格式
- 圖像質量控制包括色彩飽和度、色調、伽馬、銳度(邊緣增強)和防暈染
- 飽和度自動調整(UV調整)
- 邊緣增強級別自動調整
規格:
- 感光陣列:640 x 480。
- IO 電壓:2.5V 至 3.0V。
- 工作功率:60mW/15fpsVGAYUV。
- 休眠模式:<20μA。
- 工作溫度:-30 至 70 攝氏度。
- 輸出格式:YUV/YCbCr4:2:2 RGB565/555/444 GRB4:2:2 原始 RGB 數據(8 位)。
- 鏡頭尺寸:1/6 英寸。
- 視角:25度。
- 最大限度。幀速率:30fps VGA。
- 靈敏度:1.3V / (Lux-sec)。
- 信噪比:46 分貝。
- 動態范圍:52 分貝。
- 瀏覽方式:按行。
- 電子曝光:1 至 510 行。
- 像素覆蓋范圍:3.6μm x 3.6μm。
- 鴨電流:60℃時為 12 mV/s。
- PCB 尺寸(長 x 寬):約 1.4 x 1.4 英寸/3.5 x 3.5 厘米。
2.b 軟件設置:安裝“Arduino_OV767x”庫
首先,您需要安裝 Arduino IDE。接下來,在“工具”部分下,單擊“管理庫”,搜索OV7670 ,選擇Arduino_OV767x庫并單擊“安裝”。
OV767X 庫中支持的圖像配置:
- VGA – 640 x 480
- CIF – 352 x 240
- QVGA – 320 x 240
- QCIF – 176 x 144
2.c 軟件設置:安裝Processing
Processing是一個簡單的編程環境,由麻省理工學院媒體實驗室的研究生創建,旨在更輕松地開發以動畫為重點的面向視覺的應用程序,并通過交互為用戶提供即時反饋。
為什么我需要下載這個軟件?我們將使用此應用程序可視化 OV7670 相機模塊通過串行端口發送的相機輸出。
2.d 使用處理:測試模式
本小節的 Github 鏈接。
打開一個 Arduino 草圖,將下面的草圖復制并粘貼到草圖中,將其上傳到您的電路板。
Processing_test_pattern.ino:
/*
Circuit:
- Arduino Nano 33 BLE board
- OV7670 camera module:
- 3.3 connected to 3.3
- GND connected GND
- SIOC connected to A5
- SIOD connected to A4
- VSYNC connected to 8
- HREF connected to A1
- PCLK connected to A0
- XCLK connected to 9
- D7 connected to 4
- D6 connected to 6
- D5 connected to 5
- D4 connected to 3
- D3 connected to 2
- D2 connected to 0 / RX
- D1 connected to 1 / TX
- D0 connected to 10
*/
#include
int bytesPerFrame;
byte data[320 * 240 * 2]; // QVGA: 320x240 X 2 bytes per pixel (RGB565)
void setup() {
Serial.begin(115200);
while (!Serial);
if (!Camera.begin(QVGA, RGB565, 1)) {
Serial.println("Failed to initialize camera!");
while (1);
}
bytesPerFrame = Camera.width() * Camera.height() * Camera.bytesPerPixel();
Camera.testPattern();
}
void loop() {
Camera.readFrame(data);
Serial.write(data, bytesPerFrame);
}
將上述草圖上傳到 Arduino 板后,打開 Processing 應用程序并將以下代碼復制粘貼到一個新文件中。
處理草圖:
import processing.serial.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
Serial myPort;
// must match resolution used in the sketch
final int cameraWidth = 320;
final int cameraHeight = 240;
final int cameraBytesPerPixel = 2;
final int bytesPerFrame = cameraWidth * cameraHeight * cameraBytesPerPixel;
PImage myImage;
void setup()
{
size(320, 240);
// if you have only ONE serial port active
//myPort = new Serial(this, Serial.list()[0], 9600); // if you have only ONE serial port active
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
// wait for full frame of bytes
myPort.buffer(bytesPerFrame);
myImage = createImage(cameraWidth, cameraHeight, RGB);
}
void draw()
{
image(myImage, 0, 0);
}
void serialEvent(Serial myPort) {
byte[] frameBuffer = new byte[bytesPerFrame];
// read the saw bytes in
myPort.readBytes(frameBuffer);
// create image to set byte values
PImage img = createImage(cameraWidth, cameraHeight, RGB);
// access raw bytes via byte buffer
ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
bb.order(ByteOrder.BIG_ENDIAN);
int i = 0;
img.loadPixels();
while (bb.hasRemaining()) {
// read 16-bit pixel
short p = bb.getShort();
// convert RGB565 to RGB 24-bit
int r = ((p >> 11) & 0x1f) << 3;
int g = ((p >> 5) & 0x3f) << 2;
int b = ((p >> 0) & 0x1f) << 3;
// set pixel color
img.pixels[i++] = color(r, g, b);
}
img.updatePixels();
// assign image for next draw
myImage = img;
}
現在,在上面取消注釋特定于您的操作系統的行。然后單擊“運行”按鈕。
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
//myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
您應該得到如下所示的輸出:
2.e 解釋:測試模式
Processing_test_pattern.ino:
byte data[320 * 240 * 2]; // QVGA: 320x240 X 2 bytes per pixel (RGB565)
這行代碼建立了一個 byte 類型的數組。我們將使用 RGB565 顏色格式,因此每個像素需要 2 個字節,我們將在此處使用的圖像格式是 QVGA,大小為 320x240 像素。因此,數組的大小將是每個像素的顏色所需的高度 * 寬度 * 字節數。實際上,它轉換為320 * 240 * 2 。
Serial.begin(115200);
while (!Serial);
這行代碼設置了串口,用于在計算機和單片機之間傳輸數據。
if (!Camera.begin(QVGA, RGB565, 1)) {
Serial.println("Failed to initialize camera!");
while (1);
}
上面的代碼行設置了 OV7670 攝像頭模塊。在本例中,我們已將其初始化為使用QVGA圖像格式和RGB565顏色格式。
Camera.testPattern();
這行代碼設置相機通過串行端口發送測試圖像。
Camera.readFrame(data);
這行代碼從攝像頭中讀取一幀圖像并將其存儲在我們之前聲明的數組中。
Serial.write(data, bytesPerFrame);
最后,這行代碼將數組的值寫入串行監視器。
處理草圖:
// must match resolution used in the sketch
final int cameraWidth = 320;
final int cameraHeight = 240;
這些代碼行設置 cameraWidth 和 cameraHeight 以匹配 Arduino 草圖中的大小。
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
//myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
這些代碼行指定了微控制器和計算機之間傳輸數據的串行端口。
// convert RGB565 to RGB 24-bit
int r = ((p >> 11) & 0x1f) << 3;
int g = ((p >> 5) & 0x3f) << 2;
int b = ((p >> 0) & 0x1f) << 3;
這些代碼行將 RGB565 顏色格式轉換為 RGB888 格式以顯示在您的計算機屏幕上。這將在后面的章節中詳細解釋。
2.f 使用處理:實時圖像
本小節的 Github 鏈接。
打開一個 Arduino 草圖,將下面的草圖復制并粘貼到草圖中,將其上傳到您的電路板。
Processing_ov7670_live_image.ino
/*
Circuit:
- Arduino Nano 33 BLE board
- OV7670 camera module:
- 3.3 connected to 3.3
- GND connected GND
- SIOC connected to A5
- SIOD connected to A4
- VSYNC connected to 8
- HREF connected to A1
- PCLK connected to A0
- XCLK connected to 9
- D7 connected to 4
- D6 connected to 6
- D5 connected to 5
- D4 connected to 3
- D3 connected to 2
- D2 connected to 0 / RX
- D1 connected to 1 / TX
- D0 connected to 10
*/
#include
int bytesPerFrame;
byte data[320 * 240 * 2]; // QVGA: 320x240 X 2 bytes per pixel (RGB565)
void setup() {
Serial.begin(115200);
while (!Serial);
if (!Camera.begin(QVGA, RGB565, 1)) {
Serial.println("Failed to initialize camera!");
while (1);
}
bytesPerFrame = Camera.width() * Camera.height() * Camera.bytesPerPixel();
Camera.testPattern();
}
void loop() {
Camera.readFrame(data);
Serial.write(data, bytesPerFrame);
}
將上述草圖上傳到 Arduino 板后,打開 Processing 應用程序并將以下代碼復制粘貼到一個新文件中。
處理草圖:
import processing.serial.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
Serial myPort;
// must match resolution used in the sketch
final int cameraWidth = 320;
final int cameraHeight = 240;
final int cameraBytesPerPixel = 2;
final int bytesPerFrame = cameraWidth * cameraHeight * cameraBytesPerPixel;
PImage myImage;
void setup()
{
size(320, 240);
// if you have only ONE serial port active
//myPort = new Serial(this, Serial.list()[0], 9600); // if you have only ONE serial port active
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
// wait for full frame of bytes
myPort.buffer(bytesPerFrame);
myImage = createImage(cameraWidth, cameraHeight, RGB);
}
void draw()
{
image(myImage, 0, 0);
}
void serialEvent(Serial myPort) {
byte[] frameBuffer = new byte[bytesPerFrame];
// read the saw bytes in
myPort.readBytes(frameBuffer);
// create image to set byte values
PImage img = createImage(cameraWidth, cameraHeight, RGB);
// access raw bytes via byte buffer
ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
bb.order(ByteOrder.BIG_ENDIAN);
int i = 0;
img.loadPixels();
while (bb.hasRemaining()) {
// read 16-bit pixel
short p = bb.getShort();
// convert RGB565 to RGB 24-bit
int r = ((p >> 11) & 0x1f) << 3;
int g = ((p >> 5) & 0x3f) << 2;
int b = ((p >> 0) & 0x1f) << 3;
// set pixel color
img.pixels[i++] = color(r, g, b);
}
img.updatePixels();
// assign image for next draw
myImage = img;
}
現在,在上面取消注釋特定于您的操作系統的行。然后單擊“運行”按鈕。
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
//myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
您應該得到如下所示的輸出:
2.g 解釋:實時圖像
Processing_ov7670_live_image.ino:
byte data[320 * 240 * 2]; // QVGA: 320x240 X 2 bytes per pixel (RGB565)
這行代碼建立了一個 byte 類型的數組。我們將使用 RGB565 顏色格式,因此每個像素需要 2 個字節,我們將在此處使用的圖像格式是 QVGA,其大小為 320x240 像素。因此,數組的大小將是每個像素顏色所需的高度 * 寬度 * 字節數。實際上,它轉換為320 * 240 * 2 。
Serial.begin(115200);
while (!Serial);
這行代碼設置了串口,用于在計算機和單片機之間傳輸數據。
if (!Camera.begin(QVGA, RGB565, 1)) {
Serial.println("Failed to initialize camera!");
while (1);
}
上面的代碼行設置了 OV7670 攝像頭模塊。在本例中,我們已將其初始化為使用QVGA圖像格式和RGB565顏色格式。
Camera.testPattern();
這行代碼設置相機通過串行端口發送測試圖像。
Camera.readFrame(data);
這行代碼從攝像頭中讀取一幀圖像并將其存儲在我們之前聲明的數組中。
Serial.write(data, bytesPerFrame);
最后,這行代碼將數組寫入串行監視器。
處理草圖:
// must match resolution used in the sketch
final int cameraWidth = 320;
final int cameraHeight = 240;
這些代碼行設置 cameraWidth 和 cameraHeight 以匹配 Arduino 草圖中的大小。
// if you know the serial port name
//myPort = new Serial(this, "COM5", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
//myPort = new Serial(this, "/dev/cu.usbmodem14101", 9600); // Mac
這些代碼行指定了微控制器和計算機之間傳輸數據的串行端口。
// convert RGB565 to RGB 24-bit
int r = ((p >> 11) & 0x1f) << 3;
int g = ((p >> 5) & 0x3f) << 2;
int b = ((p >> 0) & 0x1f) << 3;
這些代碼行將 RGB565 顏色格式轉換為 RGB888 格式,以便在您的計算機屏幕上顯示。這將在后面的章節中詳細解釋。
2.h 這種方法的問題,以及可能的解決方案
處理應用程序顯示鋸齒形測試圖案而不是實際測試圖案,并顯示破損/褪色圖像而不是正確的實時圖像。這已在 Github 討論和 Arduino 論壇中進行了討論。我已將鏈接附加到下面的鏈接。
鏈接到 Github 討論
鏈接到 Arduino 論壇
一些建議的解決方案:
1.使用較短的電線
- 我的看法:我將 20 厘米的電線更改為 10 厘米,但這并沒有什么不同。
2. 試試 Ubuntu Linux
3.改變FPS
- 我的看法:我將其更改為 1/5/30 FPS,但沒有任何改進。
4.更改串口速率
- 我的看法:我將串行速率從 9600 bps 更改為 115200 bps。但問題仍然沒有改善
問題的合理原因:
- 論壇上的大多數人都認為導致問題的是 Windows 處理速度,切換到 Ubuntu 應該可以解決問題。
3. RGB888 與 RGB565
3.a 關于RGB888的一般信息
RGB888 顏色模型使用 8 位來表示每種顏色。透明度 (alpha) 值假定為最大值 (255)。
紅色、藍色和綠色可能的最大值為 255。
一些例子:
- 白色:(R, G, B) = (255, 255, 255)
- 黑色:(R, G, B) = (0, 0, 0)
3.b 關于RGB565的一般信息
RGB565 用于以 16 位表示顏色,而不是 24 位來指定顏色。為了充分利用這 16 位,紅色和藍色編碼為 5 位,綠色編碼為 6 位。這是因為人眼能夠更好地看到更多的綠色陰影。
RGB565 顏色格式中紅色和藍色值的最大可能值為 31,而綠色的最大值為 63。
有趣的事實:RGB565 只有 RGB888 顏色的 0.39%(65k 對 16m)
3.c 將 RGB888 值轉換為 RGB565
/*
Assumption:
r = 8 bits
g = 8 bits
b = 8 bits
*/
rgb565 = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
我們轉移:
- r左移 11 位,并丟棄最后 3 位
- g左移 5 位,并丟棄最后 2 位
- b右移 3 位以丟棄最后 3 位
我們最終按位或將這 3 個連接成一個 16 位表示。
例子:
讓我們將白色從 RGB888 顏色空間轉換為 RGB565 顏色空間。
由于我們已經知道兩個顏色空間可能的最大可能值,我們應該期望
- RGB888顏色空間中的 (255, 255, 255)
- RGB565顏色空間中的 (31, 63, 31)
在這個問題中,
- r = 十進制的 255 或二進制的 0000000011111111
- g = 十進制的 255 或二進制的 0000000011111111
- b = 十進制的 255 或二進制的 0000000011111111
對于紅色:
- r = 0000000011111111
- (r & 0b11111000) = 0000000011111000
- (r & 0b11111000) << 8) = 1111100000000000
對于綠色:
- g = 0000000011111111
- (g & 0b11111100) = 0000000011111100
- ((g & 0b11111100) << 3) = 0000011111100000
對于藍色:
- b = 0000000011111111
- (b >> 3) = 0000000000011111
結合這三個等式:
- rgb565 = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
- rgb565 = ( 1111100000000000 | 0000011111100000 | 0000000000011111)
- rgb565 = 1111111111111111
在RGB565色彩空間中,
- 前5位對應紅色值
- 接下來的 6 位對應綠色值
- 最后 5 位對應藍色值
- 這轉換為 (31, 63, 31),這是預期的輸出!
3.d 將 RGB565 值轉換為 RGB888
int r = ((p >> 11) & 0b00011111) << 3;
int g = ((p >> 5) & 0b00111111) << 2;
int b = ((p >> 0) & 0b00011111) << 3;
- 對于紅色,我們左移 11 位,與 0b00011111 按位與,右移 3 位
- 對于綠色,我們左移 5 位,與 0b00111111 按位與,右移 2 位
- 對于藍色,我們左移 0 位,與 0b00011111 按位與,右移 3 位
例子:
讓我們將白色從 RGB565 顏色空間轉換為 RGB888 顏色空間。
由于我們已經知道兩個顏色空間可能的最大可能值,我們應該期望
- RGB565顏色空間中的 (31, 63, 31)
- RGB888顏色空間中的 (248, 252, 248)
我們不應該期望 RGB888 顏色空間中的 (255, 255, 255) 嗎?
RGB565 只有 RGB888 顏色的 0.39%(65k 對 16m)。因此它無法覆蓋 RGB888 的整個頻譜。
在這個問題中,
在RGB 格式中,白色 = 1111111111111111
對于紅色:
- p(此處:白色)= 1111111111111111
- (p >> 11) = 00011111
- ((p >> 11) & 0b00011111) = 00011111
- (((p >> 11) & 0b00011111) << 3) = 11111000
對于綠色:
- p(此處:白色)= 1111111111111111
- (p >> 5) = 0000011111111111
- ((p >> 5) & 0b00111111) = 00111111
- (((p >> 5) & 0b00111111) << 2) = 11111100
對于藍色:
- p(此處:白色)= 1111111111111111
- (p >> 0) = 1111111111111111
- ((p >> 0) & 0b00011111) = 00011111
- ((p >> 0) & 0b00011111) << 3 = 11111000
結合這三個輸出:
- 最終紅色值 = 0b11111000 = 248
- 最終綠色值 = 0b11111100 = 252
- 最終藍色值 = 0b11111000 = 248
- 這是預期的輸出!
鏈接到 RGB565 顏色選擇器
RGB88轉RGB565轉換器
結論
我感謝我的 GSoC 導師 Paul Ruiz,他在整個項目中指導我!
鏈接
- 教程第4部分:帶有OV7670相機模塊的TinyML
- 基于OV7670的視覺捕捉系統 3次下載
- Arduino Nano 33 BLE OV7670相機擴展板
- 教程第3部分:帶有OV7670攝像頭模塊的TinyML
- 教程第2部分:帶有OV7670攝像頭模塊的TinyML
- 基于stm32控制OV7670攝像頭 133次下載
- STM32單片機移植帶有FIFO攝像頭的OV7670 107次下載
- OV7670的驅動程序和模塊經典資料合集免費下載 53次下載
- 使用STM32單片機驅動OV7670進行圖像的采集的程序和工程文件免費下載 47次下載
- OV7670攝像頭模塊的資料合集免費下載 123次下載
- OV7670模塊的詳細資料合集免費下載 29次下載
- ov7670電路原理圖 0次下載
- OV7670使用說明和程序講解-參考精英板 76次下載
- OV7670模塊(資料總包) 211次下載
- OV7670/OV7171 CMOS VGA (640x48
- Phase Lab相場模塊-定向凝固 745次閱讀
- 如何在 MCU 上快速部署 TinyML 1689次閱讀
- 如何利用TinyML實現語音識別機器人車的設計 2110次閱讀
- 基于制造帶有電容式觸摸屏的數碼運動相機 2255次閱讀
- 微雪電子OV5640 攝像頭模塊B型簡介 3748次閱讀
- 微雪電子OV5640攝像頭模塊A型簡介 5878次閱讀
- 微雪電子OV5640 攝像頭模塊C型簡介 2916次閱讀
- 微雪電子OV7670數碼攝像頭模塊簡介 4344次閱讀
- 基于OmniVision的OV5640設計的USB攝像頭模塊 5661次閱讀
- 天嵌科技OV3640攝像頭模塊介紹 2416次閱讀
- 帶你深入了解車牌號識別系統,STM32F103RBT單片機為主控 1.8w次閱讀
- TI OV10640汽車1.3M照相模塊TIDA-00421參考設計 5844次閱讀
- ov7620怎么接線_ov7620硬件連接 8818次閱讀
- 一文看懂ov7620與ov7670的區別 5.1w次閱讀
- 基于32位ARM STM32F103C8T6和傳感器的實時安防系統設計 1.4w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數據手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅動電路設計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多