你如何用Python计算OpenCV中的汽车?

时间:2016-02-17 03:23:35

标签: python opencv image-processing

我试图使用OpenCV和Python自动计算图像中的汽车数量。

enter image description here

最初我认为我可以通过一些细分来做到这一点,但我没有取得多大成功。然后我认为霍夫变换可能有助于计算汽车周围的边界,但它只是真正选择了停车位线。我唯一能想到的就是开始训练一些关于汽车和非汽车模板的比赛,但我希望有更简单的东西可以在这里做得很好。我也试过边缘检测,看起来很积极,但不确定如何继续:

enter image description here

4 个答案:

答案 0 :(得分:5)

好的,所以....我可能在这方面做了太多工作,但看起来很简单。

对于我的实施,我决定最好找到空的停车位,并假设所有其他空间都被占用。为了确定一个地点是否为空,我只是将它与道路的停车位大小部分进行比较。这意味着相同的算法无论是亮还是暗等都应该起作用,因为模板是直接从图像中提取的。

此时我只是进行模板匹配(我尝试了各种方法,但cv2.TM_CCORR_NORMED效果最好)。这给出了一个不错的结果,现在我们需要处理它。

enter image description here

我在停车场行周围创建了ROI(感兴趣的区域)。然后我通过每列统计数据将它们折叠为单个向量。我看一下这个意思。 enter image description here

它是一个非常好的指标,你已经可以清楚地看到空白的位置。但深色车仍然存在一些问题,所以现在我们决定看另一个统计数据,方差怎么样?停车场在整个地区都非常稳定。另一方面,汽车有一些变化,窗户,屋顶镜子有一些变化。所以我用"倒置"方差。因此,方差为0时,不是没有变化,而是方差为1.它看起来像这样 enter image description here

这看起来非常有前途!但你知道什么更好吗?结合这两个!所以让我们将它们相乘,我将这个结果称为"概率"因为它应该介于0和1之间 enter image description here

现在你可以真正看到空白区域和黑暗车厢之间的区别。所以我们做一些简单的门槛。这很好,但它没有给你车辆/空位数。在这一点上,我们经历了"概率"逐列,我们在阈值上查找一定数量的连续像素。多少像素?与汽车一样多的像素很宽。这"滞后"类型模型应该抑制任何峰值或虚假数据点。

现在一切都在一起,我们假设空格的数量是不变的(我认为是合理的假设),我们只是说number of cars = number of spaces - number of empty spaces并标记图像

enter image description here

并打印一些结果

found 24 cars and 1 empty space(s) in row 1
found 23 cars and 0 empty space(s) in row 2
found 20 cars and 3 empty space(s) in row 3
found 22 cars and 0 empty space(s) in row 4
found 13 cars and 9 empty space(s) in row 5

当然还有代码。它可能不是最有效的,但我通常是一个matlab人,这是我的第一个openCV / Python项目

import cv2
import numpy as np
from matplotlib import pyplot as plt

# this just keeps things neat
class ParkingLotRow(object):
    top_left=None
    bot_right=None
    roi=None
    col_mean=None
    inverted_variance=None
    empty_col_probability=None
    empty_spaces=0
    total_spaces=None

    def __init__(self,top_left,bot_right,num_spaces):
        self.top_left = top_left
        self.bot_right = bot_right
        self.total_spaces = num_spaces

############################ BEGIN: TWEAKING PARAMETERS ###########################################
car_width = 8       #in pixels
thresh = 0.975      #used to determine if a spot is empty
############################### END: TWEAKING PARAMETERS ###########################################
parking_rows = []

# defines regions of interest, row 1 is on top, row 5 is on bottom, values determined empirically
parking_rows.append(ParkingLotRow((  1, 20),(496, 41),25))     #row 1
parking_rows.append(ParkingLotRow((  1, 87),(462,105),23))     #row 2
parking_rows.append(ParkingLotRow((  1,140),(462,158),23))     #row 3
parking_rows.append(ParkingLotRow((  1,222),(462,240),22))     #row 4
parking_rows.append(ParkingLotRow((  1,286),(462,304),22))     #row 5

#read image
img = cv2.imread('parking_lot.jpg')
img2 = img.copy()

#creates a template, its jsut a car sized patch of pavement
template = img[138:165,484:495]
m, n, chan = img.shape

#blurs the template a bit
template = cv2.GaussianBlur(template,(3,3),2)
h, w, chan = template.shape

# Apply template Matching 
res = cv2.matchTemplate(img,template,cv2.TM_CCORR_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
#adds bounding box around template
cv2.rectangle(img,top_left, bottom_right, 255, 5)

#adds bounding box on ROIs
for curr_parking_lot_row in parking_rows:
    tl = curr_parking_lot_row.top_left
    br = curr_parking_lot_row.bot_right

    cv2.rectangle(res,tl, br, 1, 5)

#displays some intermediate results
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
plt.title('Original, template in blue'), plt.xticks([]), plt.yticks([])

plt.show()

curr_idx = int(0)

#overlay on original picture
f0 = plt.figure(4)
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)),plt.title('Original')


for curr_parking_lot_row in parking_rows:
    #creates the region of interest
    tl = curr_parking_lot_row.top_left
    br = curr_parking_lot_row.bot_right

    my_roi = res[tl[1]:br[1],tl[0]:br[0]]

    #extracts statistics by column
    curr_parking_lot_row.col_mean = np.mean(my_roi, 0)
    curr_parking_lot_row.inverted_variance = 1 - np.var(my_roi,0)
    curr_parking_lot_row.empty_col_probability = curr_parking_lot_row.col_mean * curr_parking_lot_row.inverted_variance

    #creates some plots
    f1 = plt.figure(1)
    plt.subplot('51%d' % (curr_idx + 1)),plt.plot(curr_parking_lot_row.col_mean),plt.title('Row %d correlation' %(curr_idx + 1))

    f2 = plt.figure(2)
    plt.subplot('51%d' % (curr_idx + 1)),plt.plot(curr_parking_lot_row.inverted_variance),plt.title('Row %d variance' %(curr_idx + 1))

    f3 = plt.figure(3)
    plt.subplot('51%d' % (curr_idx + 1))
    plt.plot(curr_parking_lot_row.empty_col_probability),plt.title('Row %d empty probability ' %(curr_idx + 1))
    plt.plot((1,n),(thresh,thresh),c='r')

    #counts empty spaces
    num_consec_pixels_over_thresh = 0
    curr_col = 0

    for prob_val in curr_parking_lot_row.empty_col_probability:
        curr_col += 1

        if(prob_val > thresh):
            num_consec_pixels_over_thresh += 1
        else:
            num_consec_pixels_over_thresh = 0

        if (num_consec_pixels_over_thresh >= car_width):
            curr_parking_lot_row.empty_spaces += 1

            #adds mark to plt
            plt.figure(3)   # the probability graph
            plt.scatter(curr_col,1,c='g')

            plt.figure(4)   #parking lot image
            plt.scatter(curr_col,curr_parking_lot_row.top_left[1] + 7, c='g')

            #to prevent doubel counting cars, just reset the counter
            num_consec_pixels_over_thresh = 0

    #sets axis range, apparantlly they mess up when adding the scatters
    plt.figure(3)
    plt.xlim([0,n])

    #print out some stats
    print('found {0} cars and {1} empty space(s) in row {2}'.format(
        curr_parking_lot_row.total_spaces - curr_parking_lot_row.empty_spaces,
        curr_parking_lot_row.empty_spaces,
        curr_idx +1))

    curr_idx += 1

#plot some figures
plt.show()

答案 1 :(得分:2)

这看起来像是您可能想要利用图像的颜色分量的情况。显然,平均亮度值的直线阈值将消除黑漆的汽车。一种可能性是探索颜色关系(红色到绿色,蓝色到绿色,红色到蓝色)以及饱和度。 Hue可能不会让你感觉太多,因为大多数车都是灰色的。

如果您可以限制您感兴趣的区域,我认为您的边缘检测方法可以正常工作。为了获得更好的优势并消除停车线,在运行边缘检测之前,请在彩色图像上使用2x2的侵蚀过滤器。然后我建议使用更强大的边缘检测方法(如sobel或prewitt)。你应该得到这样的东西(我的是在所有3个颜色通道上运行):

3 channel sobel edge detect after erosion

然后,您可以根据需要转换为二进制(不应该是必需的)或只计算相关ROI中的像素。

ROIs

如果您正在尝试创建移动相机,多个批次,多个角度的东西,那么您将需要一个更复杂的系统。但是对于一个固定的相机,这样的东西应该可以工作。

答案 2 :(得分:1)

快速的matlab代码,可以很容易地转换为python来帮助你入门......

b = rgb2hsv(I);
se = strel('rectangle', [2,4]); %# structuring element
BW = b(:,:,3)>0.5; 
BW2 = bwareaopen(BW,30);
BW3 = imerode(BW2, se); 
BW4 = imdilate(BW3, se);
CC = bwconncomp(BW4);

从这里你知道,我们需要查看CC的放置结果并计算宽高比,因为你大致了解汽车的大小。这是BW4的结果。

enter image description here

答案 3 :(得分:0)

汽车是具有高密度角落的物体,因此可以为您提供一些额外信息,以确定图像区域是否可能是汽车。我只是用

goodFeaturesToTrack

maxCorners = 10000,qualityLevel = 0.01和minDistance = 1并获得此结果

detected corners on image

分别

detected corners

仅此一点非常嘈杂,但也许你可以将它与其他分割方法结合起来。例如,您可以计算一个预期的汽车尺寸矩形"基于颜色分割并搜索具有高密度角的这种矩形。如果您有一个非常结构化的情况,例如示例图像,那么您知道"汽车应该在哪里,你只能检查这些区域。