3、图像采集基础:图像传感器工作原理、常见接口(MIPI、LVDS、Parallel)、帧格式解析

好,咱们进入正题。图像采集这块,说白了就是搞清楚摄像头怎么把光信号变成数字信号,再通过什么路径送到FPGA手里。我做了这么多年图像处理,发现很多新手一上来就调MIPI,结果波形乱飞,根本原因就是没搞懂传感器到底在干什么。

3.1 图像传感器是怎么工作的?

先聊聊核心——传感器。现在主流就两种:CCD和CMOS。CCD我用的少,它太贵,功耗也高,工业上偶尔见。CMOS才是咱们的日常,便宜、集成度高、功耗低。

CMOS传感器内部其实就是一个像素阵列。每个像素是个光电二极管,光打上去产生电荷,电荷量跟光强成正比。然后通过行选、列选,把每个像素的电压读出来,再经过ADC转成数字值。

关键点:传感器输出的原始数据叫Bayer RAW,不是RGB。每个像素只记录一种颜色(R、G或B),绿色像素占一半,因为人眼对绿光最敏感。我当年第一次拿到RAW图直接显示,全是绿的,还以为板子坏了。

传感器的工作时序由几个关键信号控制:

  • XCLK / MCLK:主时钟,传感器的心脏
  • VSYNC / FS:帧同步,一帧开始就拉高
  • HSYNC / LINE_VALID:行同步,一行有效数据时拉高
  • PCLK:像素时钟,每个时钟沿输出一个像素

嗯,这里要注意:不同厂家的命名可能不一样。比如OV的传感器叫HREF,SONY的叫LINE_VALID。但本质都一样。

3.2 常见接口:MIPI、LVDS、Parallel

接口这块,我按自己的经验排个序:Parallel最简单,LVDS中等,MIPI最麻烦。咱们一个一个说。

3.2.1 Parallel接口

这是最古老的接口,也是入门首选。数据线8位、10位或12位,加上VSYNC、HSYNC、PCLK就完事了。FPGA这边直接用IO口抓,不需要串化解串。

我的经验:Parallel接口调试时,先看PCLK有没有,再看VSYNC和HSYNC的极性对不对。我曾经被一个反相的HSYNC坑了整整一天,图像全是斜条纹。

Parallel接口的典型时序:

// 伪代码描述
always @(posedge pclk) begin
    if (vsync == 1'b1) begin
        // 新的一帧开始
        frame_cnt <= frame_cnt + 1;
    end
    if (hsync == 1'b1) begin
        // 有效像素数据
        pixel_data <= data_in;
    end
end

3.2.2 LVDS接口

LVDS用差分信号传输,抗干扰能力强,适合长距离。常见于工业相机和高速传感器。它把并行数据串行化,用一对或几对差分线传出去。

LVDS的典型配置:

  • 4对数据线 + 1对时钟线(4-lane模式)
  • 每对数据线串行化7位或10位数据
  • 时钟频率通常是像素时钟的1/7或1/10

注意:LVDS在FPGA里需要调用原语(如IBUFDS、IDELAY)来解串。别想着用普通IO口直接读,那肯定不行。我见过有人把LVDS当单端信号接,结果数据全是乱的。

3.2.3 MIPI接口

MIPI是手机和平板上的主流接口,现在也大量用在FPGA项目里。它用差分信号,但比LVDS复杂得多。MIPI D-PHY物理层有LP(低功耗)和HS(高速)两种模式。

MIPI的难点在于:

  1. 初始化序列:需要先发LP状态切换,再进入HS模式
  2. 数据包格式:每帧数据包有包头(4字节)、有效数据、包尾(2字节校验)
  3. 时钟连续:MIPI时钟是连续的,不像Parallel有门控

避坑指南:我曾经在MIPI调试时,传感器死活不出图。查了三天,发现是LP-111状态没保持够时间。MIPI协议要求LP-111至少保持100us,我代码里只给了50us。嗯,这种细节最坑人。

MIPI数据包结构:

// 4-lane MIPI, 每lane 8位
// 包头: 0x2A (帧起始) + 2字节数据长度 + 1字节ECC
// 包尾: 2字节CRC校验

// 帧起始包示例
lane0: 0x2A, 0x00, 0x80, 0x1E, data[0], data[4], ...
lane1: 0x00, 0x00, 0x00, 0x00, data[1], data[5], ...
lane2: 0x00, 0x00, 0x00, 0x00, data[2], data[6], ...
lane3: 0x00, 0x00, 0x00, 0x00, data[3], data[7], ...

3.3 帧格式解析

传感器输出的数据格式,说白了就是像素怎么排列的。常见的有这几种:

格式 描述 典型应用
Bayer RAW 每个像素一种颜色,RGGB排列 大多数CMOS传感器
YUV422 亮度+色差,每个像素16位 USB摄像头、视频采集
RGB565 R:5位 G:6位 B:5位 LCD显示、嵌入式系统
JPEG 压缩格式,非原始数据 网络摄像头、存储

你想想看,Bayer RAW怎么变成彩色图像?需要做去马赛克(Demosaic)处理。FPGA里常用双线性插值,简单但效果一般。我建议用边缘导向插值,效果更好,资源也多不了多少。

小技巧:调试时先用RAW格式抓一帧,看看像素值分布。如果全是0或全是255,说明传感器没初始化好。如果值在中间范围,那大概率是接口时序问题。

帧格式解析的流程:

// 帧解析状态机
typedef enum {
    IDLE,
    WAIT_FS,      // 等待帧起始
    LINE_HEADER,  // 行包头
    LINE_DATA,    // 行数据
    LINE_FOOTER,  // 行包尾
    WAIT_FE       // 等待帧结束
} frame_state_t;

always @(posedge clk) begin
    case(state)
        IDLE: begin
            if (vsync == 1) state <= WAIT_FS;
        end
        WAIT_FS: begin
            if (frame_start_detected) state <= LINE_HEADER;
        end
        LINE_HEADER: begin
            // 解析行包头,获取数据长度
            if (header_done) state <= LINE_DATA;
        end
        LINE_DATA: begin
            // 接收像素数据
            if (pixel_cnt == line_length) state <= LINE_FOOTER;
        end
        LINE_FOOTER: begin
            // 校验CRC
            if (footer_done) state <= LINE_HEADER; // 下一行
            if (frame_end_detected) state <= IDLE;
        end
    endcase
end

最后,我画了一张图,把传感器、接口、帧格式的关系串起来。你看一眼就明白了。

图像采集知识体系 图像传感器 CMOS / CCD Bayer RAW输出 VSYNC/HSYNC/PCLK 传输接口 Parallel (最简单) LVDS (差分/长距) MIPI (高速/复杂) D-PHY / C-PHY 帧格式解析 Bayer RAW YUV422 RGB565 JPEG FPGA处理流程 传感器初始化 → 接口解串 → 帧同步 → 像素重组 → 缓存 → 输出 关键调试点 ① 检查时钟和同步信号 ② 确认数据线极性 ③ 验证帧头帧尾 ④ 用ILA抓取原始数据 ⑤ 对比传感器手册时序图

这张图把传感器、接口、帧格式和FPGA处理流程串起来了。你调试的时候,按这个顺序排查,基本不会漏掉关键点。

最后提醒一句:别一上来就调MIPI。我建议新手先从Parallel接口的传感器入手,比如OV7670或MT9V034。等把帧同步、像素缓存这些基础搞熟了,再碰MIPI。否则你会被LP/HS状态切换、ECC校验这些细节搞到崩溃。

好了,图像采集基础就这些。记住:传感器是源头,接口是通道,帧格式是数据组织方式。三个环节都通了,图像就能稳稳地进到FPGA里。

可可精品资料库