一种基于openmv的分辨圆形,三角形,矩形的思路
openmv作为一个开源,低成本,功能强大的机器视觉模,在很多视觉领域都有涉及应用。我在作为一个新手接触openmv,探索到了一种比较有效的分辨识别圆形,三角,矩形等色块的办法,在此分享给大家。
我使用的openmv摄像头有自己的官方手册以及相关使用说明:星曈科技,里面对各个功能以及相关API都有一定的说明。
前几天因为比赛,尝试使用openmv摄像头(听说openmv和硬件通信等方面比较方便,因为官方文档都有现成的示例改一改就行了。而opencv需要自己写串口通信,我又不太会)。
题目要求是分辨出一个随机颜色(红色,绿色,蓝色)的图形(矩形,圆形,三角形)。
我采用的方法是先用寻找blob色块的方式,找出红色,蓝色,绿色三种颜色的色块,然后做每个色块的最小外接矩形。然后根据该色块的面积占比外接矩形面积的比值来判别这是个什么图形。
openmv里有现成的find_line_segments,find_circles,find_rects等函数。圆形和矩形都是现成的,只是三角形比较麻烦,得先找出线段。然后官方文档给出的办法是通过判断三条线段的角度和是否为180°来判定是否为三角形。这种方法不仅成功率不高,而且对我们的广角高糊摄像头来说,会出现的问题实在是太多了。
- 首先对广角摄像头来说,能看到的地方太多了,会识别出无数条乱七八糟的直线,即使是选定感性ROI区域,但是题目中三角形摆放位置不一定在正中心,需要自行寻找。
- 其次我们的摄像头清晰度不够,导致摄像头识别出的图像像素点过大,同一条直线可能被识别成为数条直线。
考虑到该题是以颜色为基础的,因此我想到了blob检测色块的方式。openmv自带的blob检测色块的api还是很强大的:
import sensor, image, time, math
#thresholds是指颜色阈值,把你想要检测的颜色阈值写成一个元组放进这个list
#即可。因为我实验从早做到晚,不同时间,同一个颜色拍出来效果也不同,所以多
#设置了几个阈值,引起的误差也并不大
thresholds = [(6, 47, 121, 6, 93, 6), # generic_red_thresholds
(0, 63, 18, -74, 57, 20), # generic_green_thresholds
(23, 69, 89, -12, -7, -63),
(20, 37, 20, 60, -1, 45),
(24, 36, -1, 20, -55, -25),
(30, 44, -46, -9, 7, 44),
(21, 100, 118, 19, 40, -116)] # generic_blue_thresholds
sensor.reset() #初始化设置
sensor.set_pixformat(sensor.RGB565) #设置为彩色
sensor.set_framesize(sensor.SVGA) #设置清晰度
sensor.skip_frames(time = 2000) #跳过前2000ms的图像
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock() #创建一个clock便于计算FPS,看看到底卡不卡
sensor.set_auto_gain(False) # 关闭自动自动增益。默认开启的。
sensor.set_auto_whitebal(False) #关闭白平衡。在颜色识别中,一定要关闭白平衡。
while(True): #不断拍照
clock.tick()
img = sensor.snapshot().lens_corr(1.8) #拍摄一张照片,lens_corr函数用于非鱼眼畸变矫正,默认设置参数为1.8,
for blob in img.find_blobs(thresholds,pixels_threshold=200,roi = (100,80,600,440),area_threshold=200):
#openmv自带的寻找色块函数。
#pixels_threshold是像素阈值,面积小于这个值的色块就忽略
#roi是感兴趣区域,只在这个区域内寻找色块
#are_threshold是面积阈值,如果色块被框起来的面积小于这个值,会被过滤掉
print('该形状占空比为',blob.density())
#density函数居然可以自动返回色块面积/外接矩形面积这个值,太神奇了,官方文档还是要多读!
if blob.density()>0.805:#理论上矩形和他的外接矩形应该是完全重合
#但是测试时候发现总会有偏差,多次试验取的这个值。下面圆形和三角形亦然
print("检测为长方形 ",end='')
img.draw_rectangle(blob.rect())
print('长方形长',blob.w(),'宽',blob.h())
elif blob.density()>0.65:
print("检测为圆 ",end='')
img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20)
img.draw_circle((blob.cx(), blob.cy(),int((blob.w()+blob.h())/4)))
print('圆形半径',(blob.w()+blob.h())/4)
elif blob.density()>0.40:
print("检测为三角型 ",end='')
img.draw_cross(blob.cx(), blob.cy())
print('三角型边长',blob.w())
else: #基本上占空比小于0.4的都是干扰或者三角形,索性全忽略了。
print("no dectedtion")
print(clock.fps()) #最后显示一下每秒处理几帧图片。如果FPS过低,可能就是算法过于复杂或者图像太大了,需要降低清晰度。当然直接换个摄像头也可以
给大家看一下该代码跑示例时候的效果,我觉得还是挺不错的。我把圆形和矩形都框出来了,三角形太难框了,我就在他中心画了个十字架。
很简单的一个思路,正好看官方文档看到了相关api就想到了这个办法。不过最后我们还是放弃了openmv,一来是之前没接触过,心理有点膈应。二来是不够了解openmv,他的API虽然都很好用,但是都集成化了,我看不到底层是如何实现的,因此要加上附加的小功能就变得很麻烦,不如opencv写的舒服。
下篇文章给大家讲讲我们如何用opencv解决这个问题的