HarvardX TinyML小笔记3(番外2:OV7670平替)

1 缘由

教程里面用的是OV7675,不过有点贵,是国产的OV7670价格的10倍不止。所以这里打算换成国产的OV7670。两个都是OmniVision 0.3MP VGA 级CMOS图像传感器。

OV7670 用的是老一代6µm像素工艺,光敏面积大,但芯片体积大。OV7675 用的是更新的3µm工艺,在小尺寸模组里更合适,噪声和功耗控制更好。所以两者最大的差异就是制作工艺,7675体积也更小。不过两者并不是Pin2Pin兼容。

2 硬件连接

OV7670的datasheet:https://web.mit.edu/6.111/www/f2016/tools/OV7670_2006.pdf

数据口是8-bit 并行 DVP(Digital Video Port)。

引脚说明:

  • 控制接口(I2C):SCL(时钟线)、SDA(数据线)、VCC(电源)、GND(接地)。
  • 数据接口(并行):D0-D7(8 位数据)、VSYNC(场同步)、HREF(行参考)、PCLK(像素时钟)、RST(复位,可选)、PWDN(省电,接低电平启用)。
OV7670 引脚说明
VCC电源(不要接 5V!)
GND
SCLI²C 时钟
SDAI²C 数据
XCLK用于产生摄像头主时钟(例如 8MHz)
PCLK采样像素时钟(可中断方式)
VSYNC帧同步检测
HSYNC行同步检测
D0–D7图像数据输入

有专门的一篇文章说怎么修改:https://blog.arduino.cc/2020/06/24/machine-vision-with-low-cost-camera-modules/

Nano BLE的Pins定义如下:

按照上面那篇文章,接线图如下:

但是这个Pin脚定义好像不对,因为直接初始化就挂了。

  if (!Camera.begin(QVGA, RGB565, 1)) {

    Serial.println("Failed to initialize camera!");

    while (1);

  }

看了一下代码,好像说了一下Pin脚的配置,和上面的差很多。

Test that the connection between your Arduino and Camera is able to transfer data correctly at the given speed

    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

     

  This example code is in the public domain.

试了一下。我是真想吐槽的,因为引脚真的太多了。。。一共快20个了。连接这堆杜邦线都要搞好久。。。

上去起码不报错了。

3 软件配置

软件上首先要多安装一个OV765X的库。

其实还要装一个Arduino_CRC32的库,里面有例子会用到。

用CameraCaptureRawBytes这个例子,之后就可以看到出的图了。

但是这个图是乱码,怎么看呢。看了一下之前那个教程,说是有个Processing软件可以看。

Processing 是由麻省理工学院媒体实验室开发的开源图形设计语言与开发环境,2001 年诞生至今始终免费,支持跨平台运行。它以简化的 Java 语法为基础,无需深厚编程基础也能快速上手,核心通过 setup()(初始化)和 draw()(循环渲染)函数实现图形绘制、动画效果与交互功能,还可借助扩展库拓展音频处理、3D 渲染等能力,广泛用于艺术创作(如视觉装置、动态图形)、设计领域(如交互设计原型)及编程教育,是连接代码与视觉表达的实用工具。

下载地址是:https://processing.org/

01年的软件,老掉牙了属于,不过还能用吧。

这个要放置一套Java代码进去。

/*
  This sketch reads a raw Stream of RGB565 pixels
  from the Serial port and displays the frame on
  the window.

  Use with the Examples -> CameraCaptureRawBytes Arduino sketch.

  This example code is in the public domain.
*/

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;
byte[] frameBuffer = new byte[bytesPerFrame];

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, "COM11", 9600);                    // Windows
  //myPort = new Serial(this, "/dev/ttyACM0", 9600);            // Linux
  //myPort = new Serial(this, "/dev/cu.usbmodem14401", 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) {
  // read the saw bytes in
  myPort.readBytes(frameBuffer);

  // access raw bytes via byte buffer
  ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
  bb.order(ByteOrder.BIG_ENDIAN);

  int i = 0;

  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
    myImage .pixels[i++] = color(r, g, b);
  }
 myImage .updatePixels();

}

我是Windows,用的COM11,所以改成myPort = new Serial(this, "COM11", 9600);

打开OV767X - Camera Capture Raw Bytes这个例子,编译上传之后关掉Arduino,运行这个程序,就可以看到图了。

如果屏蔽掉// Camera.testPattern();是下面的。

可以看到,数据是能出来了,但是花屏了,明显还不对。。。

仔细检查了以下排线,有一个是D6没接对,换过来是下面这样。还有一个是接触问题,接头好像不是很稳,稍微碰一下就花屏了。

换成Python,效果要好一些,但是依然有错位。

import serial, numpy as np, cv2
ser = serial.Serial('COM11', 115200)
w, h = 320, 240
img = np.zeros((h, w, 3), dtype=np.uint8)

while True:
    data = ser.read(w*h*2)  # RGB565
    for i in range(h*w):
        pixel = data[2*i]<<8 | data[2*i+1]
        img[i//w, i%w] = [
            (pixel>>11)<<3,   # R
            ((pixel>>5)&0x3F)<<2,  # G
            (pixel&0x1F)<<3   # B
        ]
    cv2.imshow('frame', img)
    if cv2.waitKey(1)==27: break

效果:

但是需要的效果是:

白 → 黄 → 青 → 绿 → 品红 → 红 → 蓝 → 黑
(这是标准 SMPTE 8-Bar 顺序)

目前就是刚开始的几秒钟可以正常这样显示,但是过一会就有问题了。

相机还是糊的,网上看了一下大神的处理,结合AI的回答。应该是没有处理帧的标记。可以参考下面这篇。

https://www.instructables.com/OV7670-Camera-and-Image-Sensor-With-Nano-33-BLE/

加了帧标记之后,果然Pattern可以了。(他的示例代码分辨率小一些,但是颜色顺序是对的)

然后继续处理实际拍摄花屏的问题。。。经过今天带病排查,终于发现了问题。

1 花屏就是杜邦线松了。果然一分钱一分货。

2 卡口这里的螺丝其实是对焦,需要慢慢将焦距对好。。。

终于算是勉强出画面了。(这个用的没有帧标记的代码)

终究还是一分钱一份货,10块钱的糊的很。不知道能否用在后面的TinyML。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值