Canny算子主要用于边缘检测,霍夫变化则用于获取边缘直线。故我们先进行Canny边缘检测,后用霍夫变化。在opencv和openmv都有相关集成的函数,直接调用即可。
霍夫变换之后会得到直线的两个点,我们可以运用这两个点求得直线的斜率(k)和截距(b)。再运用高中的知识便轻而易举的得到直线相交的点,以此为基础来判断图形的形状或进行其他运算。
先求得直线的k和b,其中temp为直线的两个点。[x1,y1,x2,y2]。
def line_feature(temp):
if temp[2] - temp[0] == 0: #防止分母为0报错
k =0
else:
k = (temp[3] - temp[1]) / (temp[2] - temp[0])
b = temp[1] - k * temp[0]
return (k,b)
再求两直线的交点,其中temp_all存放的是两条不同直线的k、b。temp_all = [(k1,b1),(k2,b2)]。这里设n = 0,m =1。
def x_y(n:int, m :int):
if (temp_all[m][0]-temp_all[n][0]) == 0: #防止分母为0报错
x =0
else:
x = (temp_all[m][1] - temp_all[n][1]) / (temp_all[n][0]-temp_all[m][0]) #x = (b_2 - b_1)/(k_2-k_1)
y = temp_all[n][0]*x + temp_all[m][1] #y = k_1 * x + b_1
return x,y
ROI:感兴趣区,即你给图像设定一个方框,在这个方框内进行识别任务。
1、以openmv为例,利用for循环在特定的ROI(否则干扰太大)中遍历所有直线。
2、判断直线的数量是否等于三(三角形三边),在求得三个交点,判断是否都在我们事先设定好的ROI中。如果是则判断为三角形,否则不是三角形。
3、三个交点意味着有两条直线要重复用到,我们写个简单的算法实现改功能。
if i == 3: #判断是否有三条直线
for n in range(3):
if n == 2:
x, y = x_y(0, 2) #得到第三个交点
else:
x, y = x_y(n, n+1) #分别得到三条直线的得到两交点
x = int(x) #转化为整数,否则报错
y = int(y)
if (0<x<320 and 0<y<240): #判断是否在我自己设定的ROI中
img.draw_cross(x,y, color=(0,255,0), size=5,thickness=2) #画出交点
这是最后的效果图
更新:上诉的检测思路大致是可行的,但是若想要落到实地,那还是缺少许多东西。以下例举出几个实际问题,并给出解决思路。
问题一:检测背景太复杂,导致无法正确检测出三角形边缘
解决方案:用二值化,代码参考如下
img = sensor.snapshot()
img.binary([color],invert=False) #color是LAB的元组
问题二:三角形的交接点在可视范围之外,由于两不平行直线总会相交的特性,无论怎么检测都能检测都有交接点。
解决:用if进行判断,只选取在可视范围内的交接点。代码参考如下:
if (0<=x<=160 and 0<=y<=120): #160,120是根据摄像头分别率调整的
img.draw_cross(x,y, color=(255,0,0), size=5,thickness=2) #其中x,y代表交接点
问题三:两直线垂直则出现x或y等于0的情况,导致无法准确划出交接点。
解决:没必要解决,交界点划在边缘也无所谓,你系统已经检测出三角形了,画只是一个可视化手段而已。
问题四:二值化之后再进行边缘检测,线太多。
解决:提高阈值即可。
问题五:OPENMV经常出现显存爆炸,运行中断。
解决:用try…except语句,检测错误便跳过这一帧,下一帧继续检测。并且注意用到的列表要在while循环末进行清空。
最后致各位看过本文章的同学:检测三角形只是我项目的一部分,完整的代码我很难单独拎出来献给各位。希望各位能在学习的路上耐下心来思考、理解,而不是生搬硬套别人的东西,我提供的只能是一个思路,具体如何整合到你们的项目中去,还需要大量发挥你们自己的智慧。