这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【ArduinoGIGAR1WiFi】网络摄像头

共3条 1/1 1 跳转至

【ArduinoGIGAR1WiFi】网络摄像头

高工
2026-02-08 10:45:41     打赏

【目标实现】

使用ArduinoGIGAR1WiFi实现网络摄像头

【硬件】

1、Arduino GIGA R1 WiFi开发板

2、OV7670摄像头

【硬件连接】

在开发板上有一个摄像头的接口

image.png

在他的示例中有原生的摄像头示例,可以驱动以下摄像头:

  • OV7670 and OV7675

  • GC2145

  • Himax HM01B0

刚好我手上有OV7670摄像头,组装好后效果如下:

20ed288d40e76f1afb9945822396e4dd.jpg

【代码编写】

在基于官方例程的基础上,我结合了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()
    
    这样简易的测试环境就好了,运行程序后,可以看到在电脑端成功的显示了开发板采集的程序:

b48058ef-d095-4130-ba52-db5fb4a83287.png

但是有点偏色,多次修改代码也还是没有达到原生色彩。原因是ov7670采集的是RGB图像,可能解码方面没有计算好。




关键词: ArduinoGIGAR1WiFi     摄像头    

专家
2026-02-10 08:17:19     打赏
2楼

谢谢楼主分享


院士
2026-02-12 00:23:16     打赏
3楼

这已很厉害了。

又会C语言,又会Python的


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]