Opencv学习记录(三) —— 得到图像中目标物坐标的简单处理算法(望指正与补充)

 

先描述一下使用场景:

我要识别一个红灯,已经把目标准确的提取出来了,二值图像中白色为目标物,现在要算出二值图中的白色像素点的坐标。因为之后需要移植到树莓派,所以需要高效的方法。

Opencv学习记录(三) —— 得到图像中目标物坐标的简单处理算法(望指正与补充)_第1张图片             需要找出白色中心点

 

  • 第一想到的肯定就是for    for 了,然而效率太低,320*240迭代下来花费10ms。优点效果好,稳定在目标物的中心

      优化的方法:

         1、在不丢失目标的情况下缩小图像进行扫描    

         2、内循环根据因子迭代,不满足则下一层。也就是在行扫描的时候,如果满足则条件设为后一个像素,不满足则进行下一行扫描。(问题:如果目标区域不连续,该行扫描不完就跳出了)

#传统扫描 :耗时10ms  约占总时间1/3,显然很浪费。优点:在图像处理算法准确的时候坐标精确
#优化方式:1、在不丢失目标的情况下缩小图像进行扫描  2、内循环根据因子迭代,不满足则下一层
def get_Target_Location(image):
    size = image.shape
    #print size
    h = size[0]
    w = size[1]
    num_x = 0
    num_y = 0
    x=0
    y=0
    num = 0
    #tt = cv2.getTickCount()
    for i in range(w):
        for j in range(h):
            if image.item(j,i) & 255:                   #(x,y) = (j,i)
                num_x += i
                num_y += j
                num += 1

    if num > 0:
        x = int(num_x/num)
        y = int(num_y/num)
    #print  (cv2.getTickCount() - tt)/cv2.getTickFrequency()   #  传统扫描:耗时10ms  约占总时间1/3,显然很浪费。优点:在图像处理算法准确的时候坐标精确
    return x,y,num

 

  • 第二种方法,粗略扫描(两点法),从左上角开始扫描,也是一行一行的扫描,当发现有满足的像素时,跳出并记录该点的x。继续在该行从行最大扫描到记录的x点,发现有满足的即结束循环。算出两次记录的平均值,即为目标中点。若找y,则一列一列的扫描,记录两次y算中点。   耗时: 0.5 - 2ms

  问题:1、目标物对称才好确定。 2、两点波动性大 。  3、区域不连续仍然不好确定

def get_mid_x(image):
    size = image.shape
    h = size[0]
    w = size[1]
    flag_back = 0
    x = 0
    y = 0
    ttt = cv2.getTickCount()
    for i in range(0,h,3):
        for j in range(w):
            if image.item(i, j) & 255:
                flag_back = 1
                y = i
                x = j
                break
        if flag_back:
            break
    for k in range(w,x):
        if image.item(y, k) & 255:
            x = (k+x)/2
            return  x,y,1
    print  (cv2.getTickCount() - ttt)/cv2.getTickFrequency()              # 粗略扫描2:耗时  0.5 - 2ms 缺点:目标较近时,波动大
    return x, y, 0

def get_mid_y(image):                   #不需要找y了
    size = image.shape
    h = size[0]
    w = size[1]
    flag_back = 0
    x = 0
    y = 0
    ttt = cv2.getTickCount()
    for i in range(0,w,3):
        for j in range(h):
            if image.item(j, i) & 255:
                flag_back = 1
                y = j
                x = i
                break
        if flag_back:
            break
    for k in range(h,y):
        if image.item(k, x) & 255:
            y = (k+y)/2
            return  x,y,1
    print  (cv2.getTickCount() - ttt)/cv2.getTickFrequency()              # 粗略扫描:耗时  0.5 - 2ms 缺点:目标较近时,波动大
    return x, y, 0

 

  • 结合上两种,只找第一点,然后根据自己的需要(我所需要的是x),进行该行扫描,扫描完成后判断该行满足要求像素多少,若数量达到要求则完成,否则继续扫描下一行直到该行目标像素满足要求。最后取均值得出x的中点。耗时 1 - 3ms..该方法解决了两点不稳定性,并且有效缩短了时间。但所制定的满足要求像素的数量需要确定好。

  • 增加Y轴的值,即得出目标物的长和宽。在第k行找到x后,从图像最下面的x坐标(x,height)开始扫描,到我们得到x的坐标的点(x,k),如果找到满足目标的像素值(255)则跳出循环,中间的则为高度。称之为十字扫描法(效果不错)。
  • def get_mid_X(image, min_p):
        size = image.shape
        h = size[0]
        w = size[1]
        flag_back = 0
        sum_x = 0
        num = 0
        x = 0
        y = 0
        y_num = 0
        # tt = cv2.getTickCount()
        for i in range(0, h, 3):
            for j in range(w):
                if image.item(i, j) & 255:
                    sum_x += j
                    num += 1
                else:
                    if num > min_p:
                        break
            if num > min_p:
                x = int(sum_x / num)
                y = i
                break
    
        if x > 0:
            for k in range(1, h - y):
                if image.item(h - k, x) & 255:
                    y_num = h - k - y
                    break
        # print  (cv2.getTickCount() - ttt)/cv2.getTickFrequency()              # 粗略扫描1:耗时  2ms左右 缺点:目标较近时,波动大
        # print  num
        return x, y, y_num

效果图:分别对应三种。图二即使加了高斯滤波抖动还是比较大

Opencv学习记录(三) —— 得到图像中目标物坐标的简单处理算法(望指正与补充)_第2张图片 Opencv学习记录(三) —— 得到图像中目标物坐标的简单处理算法(望指正与补充)_第3张图片Opencv学习记录(三) —— 得到图像中目标物坐标的简单处理算法(望指正与补充)_第4张图片

代码链接(包括树莓派端实现的自动寻灯小车代码)

你可能感兴趣的:(学习记录)