Maixcam学习笔记-寻址色块和直线
目录
1.深入解释“面向对象”
为什么需要实例?
2.为什么需要先创建disp = display.Display()?
为什么需要先创建实例(Object)?
1. 实例是类的具体化
2. 资源隔离与状态管理
3.寻找色块
4.寻线
1.深入解释“面向对象”
Python中的类(Class)就像设计图,实例(Instance)是根据设计图造出来的具体物体。
-
**
display
是一个类**:它定义了如何操作屏幕(比如show()
方法)。 -
**
disp
是一个实例**:它是根据display
类创建的具体屏幕对象。
为什么需要实例?
-
封装状态: 实例内部会保存自己的状态(比如显存地址、分辨率)。 (就像遥控器保存了电视的当前设置。)
-
避免冲突: 如果你创建多个实例(比如
disp1
和disp2
),它们可以独立控制不同的屏幕,互不干扰。
1.导入模块
from maix import display, camera, app, time
作用:从maix
库中导入4个模块:
-
display
:控制屏幕显示。 -
camera
:操作摄像头捕获图像。 -
app
:管理应用程序生命周期(如退出信号)。 -
time
:提供时间相关的功能(如帧率计算)。
cam = camera.Camera(522, 320)
-
作用:创建一个摄像头对象,设置分辨率为522x320像素。
-
参数:摄像头分辨率(宽522,高320),需根据硬件支持的格式设置。
2.为什么需要先创建disp = display.Display()
?
-
硬件资源管理:
-
Display
类封装了与屏幕交互的底层操作(如显存分配、刷新率设置)。 -
必须先创建实例(
disp
)以初始化这些资源,否则无法调用show()
。
-
-
面向对象设计:
-
屏幕是独立的硬件模块,通过对象(
disp
)管理其状态(如分辨率、色彩模式)。 -
直接调用全局函数(如
display.show(img)
)无法维护状态,可能导致资源冲突。
-
-
多显示屏支持:
-
如果设备有多个屏幕,可以通过创建多个
Display
实例分别控制。
-
disp = display.Display()
-
作用:创建一个显示屏对象,用于后续图像渲染。
-
关键点:
Display
类负责管理显示设备的底层资源(如显存、缓冲区)。必须先创建实例,才能调用其方法操作屏幕。
disp.show(img)
-
作用:将图像渲染到屏幕上。
-
关键点:
disp
是Display
类的实例,必须通过其实例方法show()
操作屏幕,直接调用display.show(img)
无法工作,因为缺少硬件上下文。
为什么需要先创建实例(Object)?
1. 实例是类的具体化
-
类(Class):相当于设计图纸,定义了一类对象的结构(属性)和行为(方法)。
-
实例(Instance):根据类创建的具体对象,是类的物理存在,占用内存并保存实际数据。
-
类比:类是“汽车设计图”,实例是“根据图纸制造的汽车”。
2. 资源隔离与状态管理
-
独立内存空间:每个实例拥有独立的属性值(状态),不同实例的状态互不影响。
-
例如,两个
Display
实例(disp1
和disp2
)可以控制不同的屏幕,各自维护显存和分辨率。
-
-
生命周期控制:实例的创建和销毁可以精准管理资源(如显存、文件句柄、网络连接)。
while not app.need_exit():
-
作用:持续运行循环,直到应用收到退出信号。
-
**
app.need_exit()
**:检测是否有人触发退出(如按下关闭按钮)。 -
**
not
**:反转逻辑,循环在“不需要退出”时继续执行。
img = cam.read()
作用:从摄像头捕获一帧图像,返回图像数据(通常是RGB或BGR格式的数组)。
3.寻找色块
from maix import image, camera, displaycam = camera.Camera(320, 240)
disp = display.Display()# 根据色块颜色选择对应配置
thresholds = [[0, 80, 40, 80, 10, 80]] # red
# thresholds = [[0, 80, -120, -10, 0, 30]] # green
# thresholds = [[0, 80, 30, 100, -120, -60]] # bluewhile 1:img = cam.read()blobs = img.find_blobs(thresholds, pixels_threshold=500)for blob in blobs:img.draw_rect(blob[0], blob[1], blob[2], blob[3], image.COLOR_GREEN)disp.show(img)
find_blobs会返回坐标,
pixels_threshold=500 是一个像素点数量的阈值,用来过滤一些不需要的小色块
area_threshold:面积阈值,如果 blob 面积小于 area_threshold,则不返回 blob,默认为 10
通过串口协议获取识别结果#
寻找色块APP支持通过串口(默认波特率为115200)上报检测到的色块信息。
由于上报信息只有一条,这里直接用示例来说明上报信息的内容。
例如上报信息为:
AA CA AC BB 14 00 00 00 E1 08 EE 00 37 00 15 01 F7 FF 4E 01 19 00 27 01 5A 00 A7 20
Copy
-
AA CA AC BB
:协议头部,内容固定 -
14 00 00 00
:数据长度,除了协议头部和数据长度外的总长度 -
E1
:标志位,用来标识串口消息标志 -
08
:命令类型,对于寻找色块APP应用该值固定为0x08 -
EE 00 37 00 15 01 F7 FF 4E 01 19 00 27 01 5A 00
:已找到色块的四个顶点坐标,每个值用小端格式的2字节表示。EE 00
和37 00
表示第一个顶点坐标为(238, 55),15 01
和F7 FF
表示第二个顶点坐标为(277, -9),4E 01
和19 00
表示第三个顶点坐标为(334, 25),27 01
和5A 00
表示第四个顶点坐标为(295, 90)。 -
A7 20
:CRC 校验值,用以校验帧数据在传输过程中是否出错
4.寻线
from maix import camera, display, imagecam = camera.Camera(320, 240)
disp = display.Display()# thresholds = [[0, 80, 40, 80, 10, 80]] # red
thresholds = [[0, 80, -120, -10, 0, 30]] # green
# thresholds = [[0, 80, 30, 100, -120, -60]] # bluewhile 1:img = cam.read()lines = img.get_regression(thresholds, area_threshold = 100)for a in lines:img.draw_line(a.x1(), a.y1(), a.x2(), a.y2(), image.COLOR_GREEN, 2)theta = a.theta()rho = a.rho()if theta > 90:theta = 270 - thetaelse:theta = 90 - thetaimg.draw_string(0, 0, "theta: " + str(theta) + ", rho: " + str(rho), image.COLOR_BLUE)disp.show(img)
-
img.get_regression
用来寻找直线,thresholds
是一个颜色阈值列表,每个元素是一个颜色阈值,同时找到多个阈值就传入多个,每个颜色阈值的格式为[L_MIN, L_MAX, A_MIN, A_MAX, B_MIN, B_MAX]
,这里的L
、A
、B
是LAB
颜色空间的三个通道,L
通道是亮度,A
通道是红绿通道,B
通道是蓝黄通道。pixels_threshold
是一个像素面积的阈值,用来过滤一些不需要直线。
-
for a in lines
用来遍历返回的Line
对象, 其中a
就是当前的Line
对象。通常get_regression
函数只会返回一个Line
对象,如果需要寻找多条直线,可以尝试使用find_line
方法
-
使用
img.draw_string
在左上角显示直线与x轴的夹角,a.theta()
是直线与y轴的夹角, 这里为了方便理解转换成直线与x轴的夹角theta
,a.rho()
是原点与直线的垂线的长度.