无人机实验笔记(识别交点 / 巡线)

六眼飞鱼酱① 提交于 2019-11-28 20:12:02

        由于我们的实验场地并不是一根纯黑线,中间的交线会对识别造成一定的影响,从而导致无人机在交线处飞偏,所以就想识别交点坐标,保证无人机始终在直线上飞行,最后的实验结果也很理想。

      识别交线代码是在网上看到的一段代码,后来发现它的算法思路很新奇,且应用过程中发现它的用武之地还蛮多的。

算法思路:

      这是一张二值化后的图,对应像素值:白色:255,黑色:0。 我用数值表示为:

      这是一张5*7大小的二值图,白色像素值为255,黑色像素值为0,我的目的是要求得(3,4)这个交点坐标。以求X坐标为例,先将每一列的值相加存入数组得到 [255, 255, 1785, 255, 255] ,可以看到出现了一个最大值1785,然后将相邻的列相减(从第二列开始,后一列减去前一列)的值存入另一个数组得到 [0,1530,-1530,0] ,可以看到出现了一个极大值和极小值,而这两个值对应的索引(列号)就是我们需要的值。取得极大值的索引:2; 极小值的索引: 3 。对应二值图可以看到,2就是我们需要求的X坐标的左邻列,3+1 就是X坐标的右邻列。最后求的 X = (2+4)/2 = 3 。同理,Y= (3 +5 )/2 = 4 。

代码:

import cv2
import numpy as np
import imutils


frame = cv2.imread("Cross 2.jpg")
frame = imutils.resize(frame, width=160)     #调整图片大小

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret, th1 = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY_INV)   #转化为二值图
mask = cv2.dilate(th1, None, iterations=1)   #膨胀一下,补足一些残缺部分

ROImask = mask[0:120, 50:110]

cnts2 = cv2.findContours(ROImask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnts2 = cnts2[0] if imutils.is_cv2() else cnts2[1]

if (len(cnts2) > 0):
    #取得面积最大的轮廓并重绘(减少噪音干扰)
    area = [cv2.contourArea(i) for i in cnts2]
    area = np.array(area)
    index = np.argmax(area)
    img = np.zeros(ROImask.shape)
    im = cv2.drawContours(img, cnts2, index, 255, -1)

    #求交点X坐标 (可以封装成函数)
    x_acc = np.sum(im, axis=0)
    x_diff = np.diff(x_acc)
    x_index1 = np.argmax(x_diff)
    x_index2 = np.argmin(x_diff) + 1
    x_max = max(x_diff)
    x_min = min(x_diff)

    if (x_max < 1000 and x_min > -1000):
        Postion_x = 80         #图像中点
    else:
        Postion_x = (x_index1 + x_index2) // 2 + 50    #ROImask取的范围在[50,110],所以+50

    # 求交点Y坐标
    y_acc = np.sum(im, axis=1)
    y_diff = np.diff(y_acc)
    y_index1 = np.argmax(y_diff)
    y_index2 = np.argmin(y_diff) + 1
    y_max = max(y_diff)
    y_min = min(y_diff)

    if (y_max < 1000 and y_min > -1000):
        Postion_y = 60    #图像中点
    else:
        Postion_y = (y_index1 + y_index2) // 2

else:
    Postion_x = 80
    Postion_y = 60

cv2.circle(frame, (Postion_x, Postion_y), 4, (0, 0, 255), -1) #画出交点

print('Postion_x,Postion_y', Postion_x, Postion_y)

cv2.imshow('mask', mask)
cv2.imshow('frame', frame)

cv2.waitKey(0)



 结果图:

代码说明:

ROImask = mask[0:120, 50:110]

cnts2 = cv2.findContours(ROImask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnts2 = cnts2[0] if imutils.is_cv2() else cnts2[1]

        只取了二值图中间一部分[50,110]来求解,因为无人机在飞行起点与终点,左右两边直线外的图像会带来干扰,索性只取了中间一段来求交点。当无人机飞出了终点,也就是cnts2没有轮廓点了,可以做额外的动作,比如降落。

if (x_max < 1000 and x_min > -1000):
        Postion_x = 80
else:
        Postion_x = (x_index1 + x_index2) // 2 + 50

    这里做了一个最大最小值判断,如果图像上不存在交点,只是一根单纯的直线。例如下图,它只能找到直线的中点Y坐标。

       这时X坐标应为图像的中点(或者往某一方向飞行所需的定值)。所以,用这个算法巡线也完全OK。( // 2 为取整。)

        缺陷:飞行时需将无人机摆正(不用完全与直线重合),因为算法是对像素的操作,如果无人机与直线倾斜的角度大了,得到的图像存在一定角度,算法就失效了。

其它应用:

  1、 绕矩形框飞行,正如一个矩形框的拐角,可以作为条件判断来控制无人机的飞行方向。

  2、在交点处悬停  

源码下载:

https://github.com/LNanL/drone

矩形框代码没有测飞过,因为没有场地。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!