从周围的边界框中提取车牌平行四边形?

时间:2019-04-10 07:32:06

标签: python opencv image-processing computer-vision yolo

因此,我训练了一个对象识别神经网络(YOLOv3),以检测以各种倾斜和直角拍摄的汽车图片车牌周围的边界框,并且该网络确实可靠。但是,现在我想利用图像处理从包围它的包围盒中提取车牌平行四边形,并且无需训练另一个神经网络就可以这样做。样本图片:

sample images

我曾尝试使用OpenCV内置函数执行边缘和轮廓检测,如以下最少的代码所示,但仅设法通过这种方式在一小部分图像上成功实现了

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

def auto_canny(image, sigma=0.25):
    # compute the median of the single channel pixel intensities
    v = np.median(image)

    # apply automatic Canny edge detection using the computed median
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0 + sigma) * v))
    edged = cv2.Canny(image, lower, upper)

    # return the edged image
    return edged


# Load the image
orig_img = cv2.imread(input_file)

img = orig_img.copy()

dim1,dim2, _ = img.shape

# Calculate the width and height of the image
img_y = len(img)
img_x = len(img[0])

#Split out each channel
blue, green, red = cv2.split(img)
mn, mx = 220, 350
# Run canny edge detection on each channel

blue_edges = auto_canny(blue)

green_edges = auto_canny(green)

red_edges = auto_canny(red)

# Join edges back into image
edges = blue_edges | green_edges | red_edges

contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

cnts=sorted(contours, key = cv2.contourArea, reverse = True)[:20]
hulls = [cv2.convexHull(cnt) for cnt in cnts]
perims = [cv2.arcLength(hull, True) for hull in hulls]
approxes = [cv2.approxPolyDP(hulls[i], 0.02 * perims[i], True) for i in range(len(hulls))]

approx_cnts = sorted(approxes, key = cv2.contourArea, reverse = True)
lengths = [len(cnt) for cnt in approx_cnts]

approx = approx_cnts[lengths.index(4)]

#check the ratio of the detected plate area to the bounding box
if (cv2.contourArea(approx)/(img.shape[0]*img.shape[1]) > .2):
    cv2.drawContours(img, [approx], -1, (0,255,0), 1)

plt.imshow(img);plt.show()

以下是一些示例结果:

(最上面的图像是边缘检测阶段的结果)

成功:

successful-examples

不成功:

unsuccessful-examples

Kinda成功案例:

kinda-successful-examples

并且绘制未找到四边形/平行四边形但找到面积最大的多边形的情况:

non-quadrilateral-examples

所有这些结果都具有完全相同的一组参数(阈值等)

我也尝试过使用cv2.HoughLines进行Hough变换,但是我不知道为什么无论我将累加器阈值设置得多么低,都始终缺少垂直倾斜的线。另外,当我降低阈值时,这些斜线无处不在:

hough-transform-examples

以及我用来绘制霍夫线的代码:

lines = cv2.HoughLines(edges,1,np.pi/180,20)
for i in range(len(lines)):
    for rho,theta in lines[i]:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        x1 = int(x0 + 1000*(-b))
        y1 = int(y0 + 1000*(a))
        x2 = int(x0 - 1000*(-b))
        y2 = int(y0 - 1000*(a))

        cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
plt.imshow(img);plt.show()

仅使用图像处理技术真的很难达到很高的成功率吗?当然,机器学习可以解决这个问题,就像小菜一碟,但是我认为这是一个过大的选择,无论如何我都没有带注释的数据。

2 个答案:

答案 0 :(得分:0)

您可以使用彩色滤光片来检测所需的区域。
车牌的边界似乎经常以白色标记。您可以检测到图像中的白色像素,并在最外面的位置之间绘制线条。

算法类似于:

  
      
  1. 指定要检测的RGB值
  2.   
  3. 检测这些RGB值所在的位置(x,y)
  4.   
  5. 确定左上角,左下角,右上角和右下角位置
  6.   
  7. 在这些位置之间绘制线
  8.   
PyImagesearch的

This color-detection example可能会帮助您对其进行编码。

当然,在白色汽车上无法检测到白板。

要说明白色汽车,您可以检查在提供的边框图像的边框上是否检测到白色。 如果是这样,请尝试在最外面的蓝色,红色或黑色像素之间绘制线条(因为车牌字母具有这种颜色)。

答案 1 :(得分:0)

我将先通过白色通过阈值过滤器,然后再加上斑点(忽略所有接触边缘的斑点),以获取牌照的大块位置。在您张贴的所有照片中,车牌没有碰到图像的边缘,并且轮廓至少有一个像素。为了获得优势,我将执行以下操作:

获取Blob中的任何点,然后从该点找到Blob中最远的点。结果应该是一个转折点。然后求出最终的角点,并从中找到最远的点。这应该给您两个相对的角。然后找到距两个点的组合距离最大的斑点点。在所有3分中,最后一次重复最远。现在,您拥有所有4个角。要订购它们,请获取中点并在每个角处创建矢量。进行顺时针缠绕。

让我知道您是否仍然需要此解决方案或需要更好的描述,我可以在您的imgur集上编写和测试代码。根据您的示例图片,我对这种策略非常有信心。