首页 > 解决方案 > 通过使用其质心之间的欧几里得距离来提高检测精度

问题描述

我正在做一个项目,我必须从鸟瞰的视频帧中检测彩色汽车。

在此处输入图像描述 在此处输入图像描述

对于检测,我使用直方图反投影来获得假设只包含目标感兴趣区域的二值图像。

该过程运行良好,直到我尝试通过在包含具有相似颜色分布的对象的视频上对其进行测试来概括检测(就像我在桌子下爬行并且我的 T 恤的部分可见)

在此处输入图像描述1 2-a3

如您所见,汽车和无关物体都在移动,检测结果为:

b1

b2

如您所见,共享相似颜色分布的不相关对象显示在二进制图像中。但是,感谢堆栈溢出专家,我可以通过添加以下约束告诉算法选择代表目标对象的 blob 来改进检测:

1-矩形检查 2-面积和比率检查

有了上述约束,我可以摆脱检测到的大型不相关对象。然而,对于小物体(见二值图像),它的作用不大,因为目标物体(红色小车)的矩形范围在(0.72 到 1)之间,而小的不相关物体确实落在这个范围内。所以我决定添加另一个约束,计算每 5 个连续帧移动的汽车质心之间的距离,并根据该距离通过流动计算阈值:

 import scipy.spatial.distance
 from collections import  deque

 #defining the Centroid
 centroids=deque(maxlen=40) #double ended queue containing the detected centroids
 .
 .
 .
 centroids.appendleft(center)
 #center comes from detection process. e.g centroids=[(120,130), (125,132),...
 Distance = scipy.spatial.distance.euclidean(pts1_red[0], pts1_red[5])                        
 if D<=50:
    #choose that blob

因此在不同的视频上进行了测试,结果质心之间的距离在 0 到 50 之间(汽车停止时为 0)。

所以我的问题是:

有没有办法我可以投资这个属性,以便它有助​​于增强检测,从而使检测忽略 T 恤?,因为当汽车不再可见并且不相关的物体停留时,它会计算距离差不相关的物体,这个距离会变小,直到小于 50!

提前致谢

标签: pythonopencvimage-processingscipyobject-detection

解决方案


根据OP提供的信息,这是解决此问题的一种方法。

示例图像

我创建了一些示例图像,它们大致代表了随时间移动的对象。中心对象表示我们正在寻找的汽车,而其他对象已被分类器错误地检测到。

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

前四张图像表示一辆汽车(中心物体)从左向右移动,以及另外两个被错误检测到的物体。在第五张图像中,汽车已移出框架,但仍然存在两个错误检测。第六帧包括一辆新车进入该帧,并有其他不正确的检测。

解决方案 - 代码

注释包含有关算法的信息。我们正在计算每个 blob 的质心,并将其与先前检测/提取的 blob 的质心进行比较。

import os
import cv2
import numpy as np
# Reading files and sorting them in the right order
all_files = os.listdir(".")
all_images = [file_name for file_name in all_files if file_name.endswith(".png")]
all_images.sort(key=lambda k: k.split(".")[0][-1])
print(all_images) # 

# Initially, no centroid information is available. 
previous_centroid_x = -1
previous_centroid_y = -1
 
DIST_THRESHOLD = 30
for i, image_name in enumerate(all_images):
    rgb_image = cv2.imread(image_name)
    height, width = rgb_image.shape[:2]
    gray_image = cv2.cvtColor(rgb_image, cv2.COLOR_BGR2GRAY)
    ret, thresh = cv2.threshold(gray_image, 127, 255, 0)
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  
    blankImage = np.zeros_like(rgb_image)
    for cnt in contours:
        # Refer to https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#moments
        M = cv2.moments(cnt)
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
        # Refer to https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/
        # https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_properties/py_contour_properties.html#contour-properties
        extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
        extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
        extTop = tuple(cnt[cnt[:, :, 1].argmin()][0])
        extBot = tuple(cnt[cnt[:, :, 1].argmax()][0])
        color = (0, 0, 255)
        if i == 0: # First frame - Assuming that you can find the correct blob accurately in the first frame
            # Here, I am using a simple logic of checking if the blob is close to the centre of the image. 
            if abs(cY - (height / 2)) < DIST_THRESHOLD: # Check if the blob centre is close to the half the image's height
                previous_centroid_x = cX # Update variables for finding the next blob correctly
                previous_centroid_y = cY
                DIST_THRESHOLD = (extBot[1] - extTop[1]) / 2 # Update centre distance error with half the height of the blob
                color = (0, 255, 0) 
        else:
            if abs(cY - previous_centroid_y) < DIST_THRESHOLD: # Compare with previous centroid y and see if it lies within Distance threshold
                previous_centroid_x = cX
                previous_centroid_y = cY
                color = (0, 255, 0) 

        cv2.drawContours(blankImage, [cnt], 0, color, -1) 
        cv2.circle(blankImage, (cX, cY), 3, (255, 0, 0), -1)
        cv2.imwrite("result_" + image_name, blankImage)
    

更新阈值使算法能够跨帧跟踪对象的质心。由于对象可以上下移动一点,我们希望将在当前帧中找到的对象的质心与在前一帧中找到的汽车的质心进行匹配。

解决方案 - 结果

绿色 - 选定的 blob 红色 - 拒绝的 blob 对象中心也已标记以供参考。

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

注意- 这不是一个完美的解决方案。它有几个限制,但它可以帮助您为您的问题设计一个近似的解决方案。


推荐阅读