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

Posted

技术标签:

【中文标题】从周围的边界框中提取车牌平行四边形?【英文标题】:Extracting the license plate parallelogram from the surrounding bounding box? 【发布时间】:2019-08-31 14:07:09 【问题描述】:

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

我曾尝试使用 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()

这里有一些示例结果:

(最上面一行是边缘检测阶段的结果)

成功:

不成功:

有点成功:

以及没有找到四边形/平行四边形但绘制出面积最大的多边形的情况:

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

我也尝试过使用 cv2.HoughLines 应用霍夫变换,但我不知道为什么无论我将累加器阈值设置得有多低,垂直倾斜的线总是会丢失。此外,当我降低阈值时,我会突然发现这些对角线:

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

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()

仅使用图像处理技术就很难达到高成功率吗?当然,机器学习会像小菜一碟一样解决这个问题,但我认为这有点矫枉过正,而且我也没有带注释的数据。

【问题讨论】:

如果您使用一组有限的相机,并且可以物理访问它们,那么使用校准使图像不失真可能会有所帮助(这样世界上的直线,例如板边缘,就可以直接显示在未失真的图片)。 @GabrielDevillers 不幸的是,车牌图像是用户上传的图像。无法访问任何摄像头。 在应用精明和/或轮廓检测之前,您显然需要应用一些预处理。可以上传几张原图让我试试吗? @RickM。没错,但是什么样的预处理是个问题。我在这里上传了一些示例:imgur.com/a/IsSYttk 也可以随意对图像进行上采样,即使使用不同的分辨率我有时会得到不同的结果。 @Moalana 我会试一试并尽快回复您。 【参考方案1】:

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

算法看起来像:

    指定要检测的 RGB 值 检测这些 RGB 值出现的位置 (x,y) 确定左上角、左下角、右上角和右下角的位置 在这些位置之间画线

来自 PyImagesearch 的This color-detection example 可能会帮助您编写代码。

当然,检测白车牌不适用于白色汽车。

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

【讨论】:

【参考方案2】:

我会做一个白色通过阈值过滤器,然后是一个 blob(忽略所有接触边缘的 blob)来获取您的车牌批量位置。在您发布的所有照片中,车牌都没有触及图像边缘,并且至少有一个像素的轮廓。为了获得角落,我会做以下事情:

取 blob 中的任意一点,然后找到 blob 中距该点最远的点。结果应该是一个角点。然后取得到的角点并找到最远的点。这应该给你两个对角。然后找到与两个点的组合距离最大的斑点点。重复最后一次,距离所有 3 点最远。现在你有所有 4 个角。要订购它们,请获取中点并为每个角创建向量。做一个顺时针缠绕。

如果您仍然需要此解决方案或需要更好的描述,请告诉我,我可以在您的 imgur 集上编写和测试代码。根据您的示例图片,我对这个策略非常有信心。

【讨论】:

如果我周末有时间,我会以任何一种方式抛出示例代码以获取乐趣。

以上是关于从周围的边界框中提取车牌平行四边形?的主要内容,如果未能解决你的问题,请参考以下文章

OpenStreetMap pbf 文件 - 在边界框中提取所有街道/道路交叉点

从车辆图像中提取车牌

如何用Python提取和识别车牌号?

如何用ni vision模块来将车牌从背景中提取出来??

如何写公式提取车牌号

如何写公式提取车牌号