K230基础-图像绘制
第十四章 图像绘制-K230图形化视觉输出
🎯 本章目标:
掌握在 K230 MicroPython 中使用image
模块进行图像绘制与标注的完整能力,学会在摄像头捕获的图像上绘制矩形、线条、文本、十字、圆等图形,用于 AI 推理结果可视化、目标跟踪、人机交互等场景。
1. 图像绘制基础
1.1 绘制上下文:image.Image
对象
所有绘制操作均作用于 image.Image
类型对象,通常由以下方式获得:
img = sensor.snapshot() # 摄像头捕获
# 或
img = image.Image(width, height, color=(0, 0, 0)) # 创建空白图像
✅ 注意:K230 的
image
模块是 CanMV 专用,非标准 MicroPython。
1.2 坐标系统
- 原点
(0, 0)
位于左上角 - X 轴向右增加
- Y 轴向下增加
- 例如:
draw_rectangle(100, 80, 120, 60)
表示:- 起点:(100, 80)
- 宽高:120×60
2. 核心绘制函数详解
2.1 画矩形:draw_rectangle()
img.draw_rectangle(x, y, w, h, color=(255, 0, 0),thickness=1,fill=False)
参数 | 说明 |
---|---|
x, y | 左上角坐标 |
w, h | 宽度和高度 |
color | 颜色(RGB888 或灰度) |
thickness | 线宽(像素) |
fill | 是否填充(实心矩形) |
✅ 用途:目标检测框、UI 边框
示例:绘制红色边框
img.draw_rectangle(50, 30, 100, 80, color=(255, 0, 0), thickness=2)
2.2 画线条:draw_line()
img.draw_line(x1, y1, x2, y2,color=(0, 255, 0),thickness=1)
参数 | 说明 |
---|---|
x1,y1 | 起点 |
x2,y2 | 终点 |
✅ 用途:坐标轴、连接线、轨迹
示例:画对角线
img.draw_line(0, 0, 319, 239, color=(0, 255, 0), thickness=1)
2.3 画十字:draw_cross()
img.draw_cross(x, y,size=5,color=(0, 0, 255),thickness=1)
参数 | 说明 |
---|---|
x, y | 中心点 |
size | 十字臂长(像素) |
✅ 用途:标记中心点、目标定位
示例:在中心画十字
img.draw_cross(160, 120, size=10, color=(255, 255, 0))
2.4 画圆:draw_circle()
img.draw_circle(x, y, r,color=(255, 0, 255),thickness=1,fill=False)
参数 | 说明 |
---|---|
x, y | 圆心 |
r | 半径 |
✅ 用途:圆形目标、UI 元素
示例:画实心圆
img.draw_circle(100, 100, 20, color=(0, 255, 255), fill=True)
2.5 写文本:draw_string()
img.draw_string(x, y, text,color=(255, 255, 255),scale=1,mono_space=True)
参数 | 说明 |
---|---|
x, y | 起始坐标 |
text | 要显示的字符串 |
color | 颜色 |
scale | 字体缩放倍数(1, 2, …) |
mono_space | 是否等宽字体 |
✅ 用途:显示 FPS、标签、状态信息
示例:显示 FPS
fps = clock.fps()
img.draw_string(10, 10, "FPS: %.1f" % fps, color=(0, 255, 0), scale=2)
3. 实战项目一:AI 推理结果可视化
3.1 场景:人脸检测 + 标注
import sensor
import image
import kpu
import time# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)# 加载人脸检测模型
model = kpu.load("/sd/face_detect.kmodel")
kpu.set_outputs(model, 0, 1, 1, 2)clock = time.clock()while True:clock.tick()# 捕获图像img = sensor.snapshot()# 推理fmap = kpu.run_with_output(model, img)plist = kpu.fmap_to_list(fmap)# 绘制检测结果if plist:for res in plist:x, y, w, h = int(res[0]), int(res[1]), int(res[2]), int(res[3])confidence = res[4]# 画检测框(红色)img.draw_rectangle(x, y, w, h, color=(255, 0, 0), thickness=2)# 画置信度文本(绿色)label = "Face %.2f" % confidenceimg.draw_string(x, y-12, label, color=(0, 255, 0), scale=2)else:img.draw_string(10, 10, "No face", color=(255, 255, 255))# 显示 FPSfps = clock.fps()img.draw_string(10, 220, "FPS: %.1f" % fps, color=(255, 255, 0), scale=1)
4. 实战项目二:运动目标标记
4.1 使用帧差法检测运动
import sensor
import imagesensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA) # 160x120
sensor.skip_frames(time=2000)# 获取背景帧
bg = sensor.snapshot()while True:img = sensor.snapshot()# 帧差diff = img.difference(bg)diff.binary([(20, 255)]) # 二值化# 寻找边缘blobs = diff.find_blobs([(100, 255)])if blobs:for b in blobs:if b.pixels() > 100: # 过滤小噪声# 在原图上标记img.draw_rectangle(b.rect(), color=(255, 0, 0))img.draw_cross(b.cx(), b.cy(), color=(0, 255, 0))img.draw_string(b.x(), b.y()-10, "Move", color=(255, 255, 0))# 更新背景(慢速)if time.ticks_ms() % 1000 == 0:bg = img.copy()
5. 实战项目三:UI 界面绘制
5.1 创建虚拟仪表盘
# 创建空白图像(320x240)
img = image.Image(320, 240, color=(0, 0, 0))# 画边框
img.draw_rectangle(5, 5, 310, 230, color=(100, 100, 100), thickness=2)# 画标题
img.draw_string(100, 10, "K230 仪表盘", color=(255, 255, 255), scale=2)# 画数值
temp = 25.6
hum = 60.3
img.draw_string(50, 80, "温度: %.1f°C" % temp, color=(255, 0, 0), scale=2)
img.draw_string(50, 130, "湿度: %.1f%%" % hum, color=(0, 255, 0), scale=2)# 画状态灯
img.draw_circle(280, 100, 15, color=(0, 255, 0), fill=True) # 绿灯(正常)
img.draw_string(250, 130, "运行中", color=(255, 255, 255))
6. 颜色表示
K230 支持 RGB888 或 RGB565 颜色表示:
颜色 | RGB 元组 |
---|---|
红 | (255, 0, 0) |
绿 | (0, 255, 0) |
蓝 | (0, 0, 255) |
黄 | (255, 255, 0) |
青 | (0, 255, 255) |
品红 | (255, 0, 255) |
白 | (255, 255, 255) |
黑 | (0, 0, 0) |
✅ 提示:颜色值范围为 0~255。
7. 高级技巧与优化
7.1 局部刷新优化
避免全屏重绘,只更新变化区域:
# 清除旧文本区域
img.draw_rectangle(10, 220, 100, 20, color=(0, 0, 0), fill=True)
# 重绘新 FPS
img.draw_string(10, 220, "FPS: %.1f" % fps, color=(255, 255, 0))
7.2 图层叠加思想
- 先绘制背景
- 再绘制动态元素
- 最后绘制文本信息
# 1. 捕获图像(背景)
img = sensor.snapshot()# 2. 绘制检测框等
for obj in objects:img.draw_rectangle(...)# 3. 绘制状态信息
img.draw_string(...)
8. 常见问题与调试
❌ 问题1:绘制无效果
排查:
- 是否在正确的
img
对象上绘制?- 坐标是否超出图像范围?
- 颜色是否为
(0,0,0)
(黑色不可见)?
❌ 问题2:文本显示乱码
解决:
- 仅支持 ASCII 字符
- 不支持中文(除非烧录中文字库)
- 使用英文提示
❌ 问题3:图像闪烁或撕裂
优化:
- 减少绘制频率
- 使用
skip_frames()
控制显示帧率- 避免在中断中绘制
9. 性能与限制
操作 | 耗时(QVGA) |
---|---|
draw_rectangle | ~0.5ms |
draw_string | ~1ms(scale=2) |
draw_line | ~0.2ms |
draw_circle | ~1ms |
✅ 建议:
- 单帧绘制不超过 5~10 个图形
- 复杂 UI 可考虑使用 LCD 驱动绘制
✅ 本章你已掌握:
image
模块的完整绘制能力- 矩形、线条、十字、圆、文本的使用
- AI 推理结果可视化
- 运动检测与 UI 绘制
- 性能优化技巧