【目标实现】
使用ArduinoGIGAR1WiFi实现网络摄像头
【硬件】
1、Arduino GIGA R1 WiFi开发板
2、OV7670摄像头
【硬件连接】
在开发板上有一个摄像头的接口

在他的示例中有原生的摄像头示例,可以驱动以下摄像头:
OV7670 and OV7675
GC2145
Himax HM01B0
刚好我手上有OV7670摄像头,组装好后效果如下:

【代码编写】
在基于官方例程的基础上,我结合了wifi来实现。
#include <Arduino.h>
#include <WiFi.h>
#include "ov767x.h" // 摄像头驱动
#include "SDRAM.h" // 必须包含SDRAM库
// ========== 1. WiFi 配置 ==========
char ssid[] = "HUAWEI";
char pass[] = "pwd";
WiFiServer server(23); // 端口23
// ========== 2. 全局变量声明 (修复报错的关键) ==========
OV7670 ov767x; // 创建OV7670对象
Camera cam(ov767x); // 创建Camera对象
#define RESOLUTION CAMERA_R320x240 // 分辨率
#define IMAGE_MODE CAMERA_RGB565 // 模式
// 使用SDRAM存储图像数据,防止内存溢出
FrameBuffer fb(SDRAM_START_ADDRESS);
// ========== 3. setup 函数 ==========
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
// 初始化SDRAM
if (!SDRAM.begin()) {
Serial.println("SDRAM 初始化失败");
while(1);
}
Serial.println("SDRAM 初始化成功");
// 初始化WiFi
if (WiFi.begin(ssid, pass) != WL_CONNECTED) {
Serial.println("WiFi 连接失败");
while(1);
}
server.begin();
Serial.print("WiFi 已连接,IP: ");
Serial.println(WiFi.localIP());
// 初始化摄像头 (使用上面定义的 RESOLUTION 和 IMAGE_MODE)
if (!cam.begin(RESOLUTION, IMAGE_MODE, 30)) {
Serial.println("摄像头初始化失败");
while(1);
}
Serial.println("摄像头初始化成功");
}
// ========== 4. 发送帧函数 ==========
void sendFrameOverWiFi(WiFiClient& client) {
// 1. 获取一帧图像
// 注意:grabFrame 的第三个参数是超时时间
if (cam.grabFrame(fb, 3000) == 0) {
uint8_t* buffer = fb.getBuffer();
size_t bufferSize = cam.frameSize(); // 获取当前帧的大小
client.write(buffer, bufferSize);
client.flush(); // 强制发送缓冲区数据
if (client.availableForWrite() == 0) {
if (!client.connected()) {
Serial.println("发送数据时检测到客户端断开");
client.stop();
}
}
}
}
// ========== 5. loop 函数 ==========
void loop() {
// 检查是否有新的客户端尝试连接
WiFiClient newClient = server.available();
static bool clientConnected = false; // 用于跟踪连接状态
static WiFiClient currentClient; // 存储当前连接的客户端
if (newClient) {
// 如果已经有客户端连接,先断开旧的
if (currentClient) {
Serial.println("有新客户端连接,断开旧客户端");
currentClient.stop();
}
currentClient = newClient;
clientConnected = true;
Serial.println("新客户端已连接");
}
if (clientConnected && currentClient.connected()) {
if (currentClient.available()) {
char command = currentClient.read();
if (command == 'C') {
sendFrameOverWiFi(currentClient);
delay(5);
}
} else {
if (!currentClient.connected()) {
Serial.println("检测到客户端意外断开");
clientConnected = false;
currentClient.stop();
}
}
} else {
if (clientConnected) {
Serial.println("当前客户端已断开,等待新连接...");
clientConnected = false;
}
delay(10);
}
}接下来在PC上编写一个python程序用于解析图像:
import socket
import numpy as np
import cv2
# 配置
HOST = '192.168.3.159' # GIGA R1 的IP地址
PORT = 23 # 端口
WIDTH = 320 # 分辨率宽
HEIGHT = 240 # 分辨率高
BYTES_PER_PIXEL = 2 # RGB565 是 2 字节/像素
def recv_all(sock, count):
"""辅助函数:确保接收指定长度的字节"""
buf = b''
while count:
newbuf = sock.recv(count)
if not newbuf:
return None
buf += newbuf
count -= len(newbuf)
return buf
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))
print("Connected to GIGA R1")
# 发送捕获指令给GIGA R1 (对应代码中的 'C')
client_socket.send(b'C')
try:
while True:
# 1. 计算总数据量
total_bytes = WIDTH * HEIGHT * BYTES_PER_PIXEL
# 2. 接收完整的图像数据
image_bytes = recv_all(client_socket, total_bytes)
if not image_bytes:
break
img_uint8 = np.frombuffer(image_bytes, dtype=np.uint8)
img_uint8 = img_uint8.reshape((HEIGHT, WIDTH, 2))
img_16bit = (img_uint8[:, :, 0] << 8) | img_uint8[:, :, 1]
r = (img_16bit & 0xF800) >> 8 # 取出5位 R,并左移3位变成8位 (0xF8 -> 0b11111000)
g = (img_16bit & 0x07E0) >> 3 # 取出6位 G,并左移2位变成8位 (0xFC -> 0b11111100)
b = (img_16bit & 0x001F) << 3 # 取出5位 B,并左移3位变成8位 (0xF8 -> 0b11111000)
# 7. **关键修正**:确保数据类型为 uint8,以满足 cv2.merge 的要求
# 之前 r, g, b 是 uint16 类型,现在转换为 uint8
b = b.astype(np.uint8)
g = g.astype(np.uint8)
r = r.astype(np.uint8)
# 8. 合并为 BGR 格式 (OpenCV 使用 BGR)
img_8bit = cv2.merge([b, g, r])
# 9. 显示图像
cv2.imshow('GIGA R1 Camera Feed', img_8bit)
# 按 'q' 退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 重新请求下一帧
client_socket.send(b'C')
except KeyboardInterrupt:
pass
finally:
client_socket.close()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
这样简易的测试环境就好了,运行程序后,可以看到在电脑端成功的显示了开发板采集的程序:
但是有点偏色,多次修改代码也还是没有达到原生色彩。原因是ov7670采集的是RGB图像,可能解码方面没有计算好。
我要赚赏金
