4、图像采集基础:使用K210摄像头采集图像,掌握图像格式、分辨率设置、帧率控制及显示到LCD屏幕的方法

K210作为一款集成机器视觉与听觉能力的边缘计算芯片,其离线视觉应用的核心起点便是图像采集。在无网络环境下,K210需要独立完成从摄像头感光、数据搬运、格式转换到最终显示或送入AI模型推理的完整链路。本章将围绕K210的DVP(Digital Video Port)摄像头接口与LCD显示通路,深入讲解图像格式、分辨率、帧率控制以及如何将采集到的图像实时显示在LCD屏幕上。理解这一基础环节,是后续进行人脸检测、物体分类等视觉任务的前提。

K210 图像采集与显示硬件链路 OV2640/GC0328 DVP 摄像头 SCCB/I2C 控制 8-bit 并行数据 DVP_D[7:0] PCLK/VSYNC/HSYNC K210 SoC DVP 控制器 ISP / 缩放 / 裁剪 FIFO (8KB) DMA → 内存帧缓冲 AI 加速器 / CPU LCD 显示屏 SPI / 8-bit 8080 ST7789 / ILI9341 320x240 RGB565 帧缓冲管理 双缓冲切换 / 内存拷贝 RGB565 → 显示格式转换 SCCB 寄存器配置 帧率控制策略 PCLK分频 / 分辨率 / 曝光时间 TP1 TP2

上图展示了K210图像采集与显示的核心硬件链路。摄像头通过DVP接口将并行图像数据送入K210的DVP控制器,经过ISP处理、缩放裁剪后存入FIFO,再由DMA搬运到内存中的帧缓冲。CPU或AI加速器可以访问帧缓冲进行算法处理,最终通过SPI或8080接口将图像输出到LCD屏幕。整个链路中,帧缓冲的管理与格式转换是决定显示流畅度的关键。

4.1 图像格式与像素编码

4.1.1 核心原理:从Bayer到RGB565

K210配套的摄像头(如OV2640、GC0328)其感光元件通常采用Bayer阵列排列,每个像素仅能感知红、绿、蓝中的一种颜色。为了得到彩色图像,必须经过ISP(图像信号处理器)进行去马赛克插值。K210内部集成了ISP模块,可以输出多种格式的数据。在嵌入式视觉应用中,最常用的格式是RGB565和YUV422。

  • RGB565:每个像素用16位表示,其中红色5位、绿色6位、蓝色5位。这种格式无需解码,直接映射到LCD的显存格式,显示效率最高。
  • YUV422:亮度Y与色度UV分离,便于进行人脸检测等算法处理,但显示时需要转换为RGB。
  • GRAYSCALE:8位灰度图,适合做边缘检测或简单轮廓识别,数据量最小。

4.1.2 判断方法:如何选择格式

选择图像格式需根据后续处理需求决定。若仅用于LCD显示,优先选择RGB565;若用于AI模型输入,需查看模型训练时的输入格式;若用于色彩分析,YUV422更合适。K210的sensor.set_pixformat()函数用于设置格式,常见配置如下:

import sensor
sensor.reset()
# 设置为RGB565格式,适合LCD显示
sensor.set_pixformat(sensor.RGB565)
# 或者设置为灰度图,适合简单识别
# sensor.set_pixformat(sensor.GRAYSCALE)

4.1.3 案例拆解:格式转换的代价

假设我们使用OV2640输出RGB565格式,分辨率为320x240。一帧图像的数据量为320×240×2 = 153,600字节。若直接送入LCD显示,无需额外转换。但如果使用YUV422格式,则显示前需要逐像素转换为RGB565,这会占用CPU周期。实测在K210 400MHz主频下,软件转换一帧320x240的YUV422图像约耗时8-12ms,会明显降低帧率。因此,在显示场景中应避免使用非RGB格式。

经验提醒:K210的LCD控制器支持RGB565直接写入显存。若使用RGB888格式,虽然色彩更丰富,但数据量增加50%,且K210的LCD接口通常只支持RGB565,会造成数据截断,得不偿失。

4.2 分辨率设置与窗口裁剪

4.2.1 核心原理:分辨率与视野的权衡

分辨率决定了图像的细节程度,但也直接影响帧率、内存占用和算法处理时间。K210的DVP控制器支持对摄像头输出的图像进行裁剪(Crop)和缩放(Scale)。常见的分辨率有QQVGA(160x120)、QVGA(320x240)、VGA(640x480)。

分辨率 尺寸(像素) RGB565帧大小 典型帧率(fps) 适用场景
QQVGA 160x120 38.4 KB 60 高速物体追踪
QVGA 320x240 153.6 KB 30 人脸检测、LCD显示
VGA 640x480 614.4 KB 10-15 静态高清拍照

4.2.2 操作流程:设置分辨率与窗口

在MaixPy开发环境中,设置分辨率非常简单。但需要注意,sensor.set_framesize()设置的是摄像头输出尺寸,而sensor.set_windowing()可以进一步裁剪感兴趣区域(ROI)。

import sensor
sensor.reset()
# 设置摄像头输出为QVGA
sensor.set_framesize(sensor.QVGA)
# 设置窗口为中央200x200区域
sensor.set_windowing((60, 20, 200, 200))
# 此时实际采集的图像为200x200

4.2.3 实战场景:动态调整分辨率

在一个人脸门禁项目中,待机时使用QQVGA(160x120)进行运动检测,帧率可达60fps,功耗较低。当检测到人体移动时,动态切换至QVGA(320x240)进行人脸识别,以保证识别精度。切换分辨率时,需要重新初始化摄像头,耗时约100ms,因此不能频繁切换。

风险提示:分辨率设置过高会导致内存不足。K210的RAM为8MB,其中约6MB可用于帧缓冲。若使用VGA分辨率RGB565,一帧需614KB,双缓冲则需要1.2MB,虽然可以容纳,但留给AI模型和系统运行的内存会变得紧张,可能导致内存分配失败。

4.3 帧率控制与同步

4.3.1 核心原理:帧率瓶颈分析

帧率(FPS)受多个环节制约:摄像头输出能力、DVP总线时钟、ISP处理速度、DMA传输效率以及CPU/算法处理时间。K210的DVP接口最高支持约50M像素/秒的吞吐量。对于320x240的RGB565图像,理论最高帧率约为50M / (320×240) ≈ 650fps,但实际受限于传感器输出和ISP处理,通常QVGA下能达到30-60fps。

4.3.2 判断方法:定位帧率瓶颈

当实际帧率低于预期时,可通过以下步骤排查:

  1. 使用sensor.snapshot()获取一帧图像,测量耗时。
  2. 关闭LCD显示,仅采集图像,对比帧率变化。若帧率显著提升,则瓶颈在LCD刷新。
  3. 关闭算法处理,仅显示图像,对比帧率。若帧率提升,则瓶颈在算法。
  4. 检查摄像头输出时钟PCLK分频设置,降低分频可提高帧率,但可能增加噪点。

4.3.3 案例拆解:实现30fps稳定显示

某项目需要将摄像头图像实时显示在LCD上,并叠加简单的十字准星。初始实现时帧率仅15fps,画面卡顿。分析发现,代码中每次循环都调用img.draw_cross()绘制准星,该操作需要遍历图像像素,耗时约20ms。优化方案:

  • 将准星绘制改为在LCD的显示缓冲层进行,而非修改摄像头帧缓冲。
  • 使用lcd.display(img)直接显示,避免额外的图像拷贝。
  • 将摄像头输出分辨率从VGA降低至QVGA。

优化后,单帧处理时间从66ms降至33ms,帧率稳定在30fps。关键参数对比如下:

项目 优化前 优化后
分辨率 VGA (640x480) QVGA (320x240)
绘制方式 修改帧缓冲 LCD叠加层
单帧耗时 66ms 33ms
实际帧率 15fps 30fps
复盘经验:帧率控制的核心是“减少不必要的数据搬运”。在K210上,CPU直接操作大尺寸图像非常耗时。应尽量利用硬件DMA和ISP的裁剪功能,避免在软件层面对整帧图像进行遍历。

4.4 图像显示到LCD屏幕

4.4.1 核心原理:LCD显示通路

K210的LCD接口支持SPI和8位并行两种模式。MaixPy开发板通常使用SPI接口驱动ST7789或ILI9341控制器。显示流程为:CPU将帧缓冲中的图像数据通过SPI DMA发送至LCD的GRAM(显存),LCD控制器负责刷新屏幕。为了提高显示效率,K210的DVP和LCD可以同时工作,实现“采集-显示”流水线。

4.4.2 操作流程:初始化与显示

import sensor
import lcd
# 初始化LCD
lcd.init(freq=15000000, color=lcd.RED)
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)  # 启动图像采集

while True:
    img = sensor.snapshot()  # 获取一帧图像
    lcd.display(img)         # 显示到LCD

4.4.3 常见误区与排障

  • 花屏或颜色错乱:通常是因为LCD初始化参数错误或像素格式不匹配。检查lcd.init()中的频率设置,过高频率可能导致信号不稳定。
  • 图像颠倒或镜像:可通过lcd.set_hmirror()和lcd.set_vflip()调整。
  • 显示延迟大:不要使用lcd.display()后立即进行耗时操作,应使用双缓冲。即采集图像存入buffer A时,显示buffer B,交替进行。
风险提示:LCD的SPI时钟频率不宜超过20MHz,否则可能导致数据错误。在长线连接或使用杜邦线时,应降低频率至10MHz以下,并缩短连线距离。

4.5 综合实战:构建实时视频监控面板

本案例将综合运用本章知识,实现一个具有帧率显示和动态分辨率切换的监控面板。

背景与目标:设计一个离线视频监控节点,要求:1)默认显示QVGA分辨率30fps画面;2)在画面左上角实时显示当前帧率;3)当检测到画面亮度低于阈值时,自动切换至QQVGA以提高帧率。

关键参数与实现:

import sensor, lcd, time, pyb

lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)

clock = time.clock()
low_light_count = 0

while True:
    clock.tick()
    img = sensor.snapshot()
    # 计算亮度(取中心区域像素均值)
    stats = img.get_statistics(roi=(120, 90, 80, 60))
    avg_brightness = stats.mean()
    
    # 亮度低于80时,切换至QQVGA
    if avg_brightness < 80:
        low_light_count += 1
        if low_light_count > 10 and sensor.width() != 160:
            sensor.set_framesize(sensor.QQVGA)
    else:
        low_light_count = 0
        if sensor.width() != 320:
            sensor.set_framesize(sensor.QVGA)
    
    # 绘制帧率信息
    fps = clock.fps()
    img.draw_string(5, 5, "FPS: %.1f" % fps, color=(255, 0, 0))
    img.draw_string(5, 25, "Bright: %d" % avg_brightness, color=(255, 0, 0))
    
    lcd.display(img)

结果与复盘:在正常光照下,系统稳定运行在30fps;当用手遮挡镜头模拟黑暗环境时,约0.5秒后分辨率切换至QQVGA,帧率提升至60fps,保证了画面的流畅性。此案例验证了动态分辨率调整的可行性,但需要注意,切换分辨率时sensor.set_framesize()会阻塞约100ms,期间画面会短暂停顿,可通过提前预判或使用双摄像头方案规避。

本章详细阐述了K210图像采集的完整链路。掌握图像格式、分辨率与帧率三者之间的制约关系,是进行高效视觉应用开发的基础。在实际项目中,务必根据算法复杂度、内存余量和显示需求,综合权衡这些参数,避免盲目追求高分辨率或高帧率。