请使用openmv ide的内部视觉库,编写一个代码。要求是识别黑色矩形框,然后将其中心点标注出来
时间: 2025-07-30 21:19:31 浏览: 26
<think>我们使用OpenMV内置的视觉库来识别黑色矩形框,并标注其中心点。
步骤:
1. 初始化摄像头
2. 设置图像格式和大小
3. 寻找矩形:通过寻找色块(黑色)然后找到其外接矩形,再通过形状判断(矩形通常有四个角点,且面积较大)
4. 计算矩形中心点并标注
注意:黑色在LAB颜色空间中比较明显,我们可以用LAB颜色空间的阈值来检测黑色。
但注意:在OpenMV中,默认使用RGB565,我们可以转换为LAB,但也可以直接使用灰度图来检测黑色(因为黑色在灰度图中值很低)。
这里我们采用两种方法结合:
- 首先,使用灰度图阈值二值化(将黑色区域变成白色,其他变成黑色),然后通过寻找二值化后的白色区域来找到黑色区域。
- 或者,使用LAB颜色空间的L通道(亮度),因为黑色亮度很低。
但是OpenMV的find_blobs函数支持LAB阈值,所以我们直接使用LAB阈值来检测黑色。
黑色在LAB颜色空间中的阈值(经验值):
L: 0~50 (亮度很低)
A: -128~127 (这里我们取中间值附近,因为黑色是中性色,A和B通道接近0,但实际上在光照变化下会有波动,所以可以放宽)
B: -128~127
但是注意:在OpenMV中,LAB阈值范围是(0,100)和(-128,127)的映射,具体如下:
L: [0, 100] -> 0~100
A: [-128, 127] -> 0~255(实际映射为128加值,即0对应-128,255对应127)
B: 同A
因此,我们设定黑色的LAB阈值范围:
L: (0, 50) # 亮度很低
A: (0, 130) # 对应-128到2(因为130对应2,计算方式:130-128=2)
B: (0, 130) # 同上
但这样设置可能不够准确,我们可以先通过阈值编辑器调整。
另一种简单方法:使用灰度图,设置低阈值(如0, 50)来检测黑色。
这里我们使用灰度图方法,因为黑色在灰度图中容易检测,且处理速度快。
步骤:
1. 设置传感器为灰度模式(sensor.GRAYSCALE)或使用RGB565然后转换为灰度图(但直接灰度模式更快)
2. 二值化图像,将黑色区域变为白色(因为find_blobs寻找的是白色区域)
注意:我们可以使用`img.binary([(0, 50)])` 将灰度值在0到50之间的像素变为白色(255),其余变为黑色(0)
3. 然后寻找白色色块(即原来的黑色区域)
4. 对每个色块,通过`blob.rect()`得到矩形,然后计算中心点。
但是,我们想要的是矩形框(可能是长方形),所以需要进一步判断形状。我们可以通过色块的宽高比和面积来大致判断是否为矩形。
另外,我们也可以使用`img.find_rects()`函数来直接寻找矩形,但是这个函数寻找的是矩形轮廓,可能更适合。
这里我们提供两种方法:
方法一:使用find_blobs(色块)然后通过宽高比和面积过滤
方法二:使用find_rects(矩形)直接寻找矩形
由于要求是黑色矩形框,注意:矩形框可能是空心的(即中间是空的),所以用色块可能只能检测到边框,而中间是空的。因此,如果矩形是实心的,那么用色块可以;如果是空心的,那么色块会检测到四个边,而不是一个整体。
因此,我们假设矩形是实心的(比如黑色实心矩形)。如果是空心的,那么我们需要使用边缘检测然后寻找矩形轮廓(即使用find_rects)。
这里我们先按实心矩形处理,使用find_blobs。
代码步骤(方法一:find_blobs):
1. 初始化摄像头
2. 设置灰度模式
3. 循环:获取图像,二值化(将黑色变为白色),然后寻找白色色块
4. 对每个色块,判断其面积(大于一定值)和宽高比(在矩形范围内,比如宽高比大于2:1或小于1:2,但具体根据实际情况调整)
5. 计算中心点并画出来
方法二(使用find_rects):
1. 初始化摄像头
2. 设置灰度模式
3. 循环:获取图像,然后使用`img.find_rects()`函数
4. 对每个找到的矩形,计算中心点
注意:find_rects函数需要先进行边缘检测(函数内部会做),所以对于低对比度的目标可能效果不好。而黑色矩形如果和背景对比度低,可能检测不到。
根据实际需求,我们选择方法一,因为实心矩形用色块检测更稳定。
但是,如果矩形是空心的,那么方法一可能无法检测到整个矩形(只能检测到边框的线条,而每个线条都很小),此时需要调整:我们可以降低二值化的阈值,使得边框线条也能被检测到,然后通过合并多个色块或者使用形态学操作来连接线条,但这样比较复杂。
因此,我们先假设是实心矩形。如果是空心矩形,则建议使用方法二。
这里我们给出两种方法的代码,用户根据实际情况选择。
方法一代码(实心矩形):
```python
import sensor, image, time
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE) # 灰度模式
sensor.set_framesize(sensor.QVGA) # 320x240
sensor.skip_frames(time=2000) # 等待设置生效
sensor.set_auto_gain(False) # 关闭自动增益
sensor.set_auto_whitebal(False) # 关闭白平衡
# 设置黑色阈值(灰度值)
black_threshold = (0, 50) # 灰度值在0到50之间为黑色
while(True):
img = sensor.snapshot()
# 二值化图像:将黑色区域变为白色(255),其他变为黑色(0)
img.binary([black_threshold], invert=True) # invert=True表示将阈值内的像素置为255,否则为0。这里我们想要黑色区域变成白色,所以反相
# 寻找白色色块(即原来的黑色区域)
blobs = img.find_blobs([(255, 255)], area_threshold=100, merge=True)
# 遍历每个色块
for blob in blobs:
# 过滤掉面积太小的色块
if blob.area() < 2000: # 面积阈值根据实际情况调整
continue
# 计算宽高比
ratio = blob.w() / blob.h()
# 假设矩形宽高比在0.5到2之间(即正方形或长方形,排除细长条)
if ratio < 0.5 or ratio > 2:
continue
# 画出色块矩形框
img.draw_rectangle(blob.rect(), color=127) # 灰色矩形框
# 计算中心点
center_x = blob.cx()
center_y = blob.cy()
# 画出中心点
img.draw_cross(center_x, center_y, color=127, size=10)
# 打印中心点坐标
print("Center: ({}, {})".format(center_x, center_y))
# 显示图像
img.draw_string(0, 0, "Black Rectangle Detection", color=127)
```
方法二(空心矩形,使用find_rects):
```python
import sensor, image, time
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
while(True):
img = sensor.snapshot()
# 寻找矩形
# 注意:find_rects函数的参数threshold是边缘检测的阈值,需要根据实际情况调整
rectangles = img.find_rects(threshold=2000) # threshold值越大,要求边缘越明显
for rect in rectangles:
# 获取矩形的四个角点
corners = rect.corners()
# 计算中心点:四个角点坐标的平均值
center_x = (corners[0][0] + corners[1][0] + corners[2][0] + corners[3][0]) // 4
center_y = (corners[0][1] + corners[1][1] + corners[2][1] + corners[3][1]) // 4
# 画出矩形轮廓
img.draw_rectangle(rect.rect(), color=127)
# 画出矩形的四个角点(可选)
for i in range(4):
img.draw_circle(corners[i][0], corners[i][1], 5, color=127)
# 画出中心点
img.draw_cross(center_x, center_y, color=127, size=10)
print("Center: ({}, {})".format(center_x, center_y))
img.draw_string(0, 0, "Rectangle Detection", color=127)
```
注意:方法二的find_rects函数需要边缘明显,所以如果黑色矩形与背景对比度不高,可能检测不到。可以尝试调整threshold参数(默认1000,我们这里设为2000,要求更高对比度,避免误检)。
用户可以根据实际情况选择合适的方法。如果是实心矩形,方法一更简单稳定;如果是空心矩形,则用方法二。
另外,如果环境光线变化,可能需要动态调整阈值。可以使用自动阈值方法,或者增加曝光控制。
相关问题:
1. 如何优化黑色矩形检测的稳定性?
2. 在光照变化的环境中如何自适应调整阈值?
3. 如何检测多个黑色矩形并分别标注中心点?
4. 如何将中心点坐标通过串口发送给其他设备(如STM32)?</think>### OpenMV 识别黑色矩形中心点代码实现
以下是在 OpenMV IDE 中使用内置视觉库识别黑色矩形并标注中心点的完整代码:
```python
import sensor, image, time, pyb
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # 设置彩色图像格式
sensor.set_framesize(sensor.QVGA) # 320x240分辨率
sensor.skip_frames(time=2000) # 等待摄像头稳定
sensor.set_auto_gain(False) # 关闭自动增益
sensor.set_auto_whitebal(False) # 关闭自动白平衡
# 定义黑色阈值 (LAB色彩空间)
# L: 亮度(0-100), A: 绿色到红色(-128-127), B: 蓝色到黄色(-128-127)
BLACK_THRESHOLD = (0, 40, -20, 20, -20, 20) # 调整这些值以适应环境
# 创建时钟对象跟踪帧率
clock = time.clock()
while(True):
clock.tick()
img = sensor.snapshot()
# 1. 寻找黑色色块
blobs = img.find_blobs([BLACK_THRESHOLD],
area_threshold=500, # 最小面积阈值
pixels_threshold=500, # 最小像素数
merge=True, # 合并相邻色块
margin=10) # 合并边距
# 2. 处理检测到的色块
for blob in blobs:
# 3. 计算矩形中心点
center_x = blob.cx()
center_y = blob.cy()
# 4. 标注矩形和中心点
img.draw_rectangle(blob.rect(), color=(0, 255, 0)) # 绿色矩形框
img.draw_cross(center_x, center_y, color=(255, 0, 0), size=10) # 红色中心十字
# 5. 显示中心坐标
img.draw_string(center_x + 10, center_y - 10,
f"({center_x},{center_y})",
color=(255, 255, 255))
# 显示帧率
img.draw_string(5, 5, f"FPS: {clock.fps():.1f}", color=(255, 255, 255))
```
### 关键步骤说明:
1. **色彩空间选择**:
- 使用 LAB 色彩空间比 RGB 更适合检测黑色
- 阈值范围:`(L_min, L_max, A_min, A_max, B_min, B_max)`
- 黑色特征:低亮度(L),A/B通道接近0
2. **参数调整技巧**:
```python
# 在OpenMV IDE中使用阈值编辑器实时调整
# 菜单栏 -> 工具 -> 机器视觉 -> 阈值编辑器
```
3. **性能优化建议**:
- 降低分辨率:`sensor.set_framesize(sensor.QQVGA)` (160x120)
- 缩小检测区域:`roi=(x, y, w, h)`
- 增加合并参数:`merge=True, margin=20`
4. **矩形特征过滤**:
```python
# 在循环内添加形状过滤
if blob.roundness() < 0.7: # 矩形比圆形更"不圆"
continue
if blob.w()/blob.h() < 0.5 or blob.w()/blob.h() > 2.0: # 宽高比过滤
continue
```
### 常见问题解决:
1. **检测不稳定**:
- 增加环境光照或使用补光灯
- 添加形态学操作:`img.erode(1)` 消除噪点
2. **多个矩形检测**:
```python
# 只保留最大矩形
if len(blobs) > 0:
largest_blob = max(blobs, key=lambda b: b.area())
# 处理largest_blob...
```
3. **坐标系统转换**:
```python
# 将图像坐标转换为实际物理坐标
def pixel_to_mm(x_pixel, y_pixel):
mm_per_pixel = 0.1 # 根据实际校准
return (x_pixel * mm_per_pixel, y_pixel * mm_per_pixel)
```
> 实际应用中,黑色检测效果会受到光照条件显著影响[^1]。建议在固定光照环境下使用或添加自适应阈值调整。
### 扩展应用:
- 与STM32通信发送坐标:`uart.write(f"{center_x},{center_y}\n")`
- 添加位置滤波稳定输出:
```python
from pyb import millis
last_pos = (0, 0)
last_time = millis()
# 在循环内
current_time = millis()
dt = (current_time - last_time) / 1000.0
alpha = 0.2 # 滤波系数
filtered_x = alpha * center_x + (1 - alpha) * last_pos[0]
filtered_y = alpha * center_y + (1 - alpha) * last_pos[1]
last_pos = (filtered_x, filtered_y)
```
阅读全文
相关推荐



















