4、图像采集基础:使用K210摄像头采集图像,掌握图像格式、分辨率设置、帧率控制及显示到LCD屏幕的方法
K210作为一款集成机器视觉与听觉能力的边缘计算芯片,其离线视觉应用的核心起点便是图像采集。在无网络环境下,K210需要独立完成从摄像头感光、数据搬运、格式转换到最终显示或送入AI模型推理的完整链路。本章将围绕K210的DVP(Digital Video Port)摄像头接口与LCD显示通路,深入讲解图像格式、分辨率、帧率控制以及如何将采集到的图像实时显示在LCD屏幕上。理解这一基础环节,是后续进行人脸检测、物体分类等视觉任务的前提。
上图展示了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格式。
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,因此不能频繁切换。
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 判断方法:定位帧率瓶颈
当实际帧率低于预期时,可通过以下步骤排查:
- 使用
sensor.snapshot()获取一帧图像,测量耗时。 - 关闭LCD显示,仅采集图像,对比帧率变化。若帧率显著提升,则瓶颈在LCD刷新。
- 关闭算法处理,仅显示图像,对比帧率。若帧率提升,则瓶颈在算法。
- 检查摄像头输出时钟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 |
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,交替进行。
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图像采集的完整链路。掌握图像格式、分辨率与帧率三者之间的制约关系,是进行高效视觉应用开发的基础。在实际项目中,务必根据算法复杂度、内存余量和显示需求,综合权衡这些参数,避免盲目追求高分辨率或高帧率。