因此,我训练了一个对象识别神经网络(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()
以下是一些示例结果:
(最上面的图像是边缘检测阶段的结果)
成功:
不成功:
Kinda成功案例:
并且绘制未找到四边形/平行四边形但找到面积最大的多边形的情况:
所有这些结果都具有完全相同的一组参数(阈值等)
我也尝试过使用cv2.HoughLines进行Hough变换,但是我不知道为什么无论我将累加器阈值设置得多么低,都始终缺少垂直倾斜的线。另外,当我降低阈值时,这些斜线无处不在:
以及我用来绘制霍夫线的代码:
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()
仅使用图像处理技术真的很难达到很高的成功率吗?当然,机器学习可以解决这个问题,就像小菜一碟,但是我认为这是一个过大的选择,无论如何我都没有带注释的数据。
答案 0 :(得分:0)
您可以使用彩色滤光片来检测所需的区域。
车牌的边界似乎经常以白色标记。您可以检测到图像中的白色像素,并在最外面的位置之间绘制线条。
算法类似于:
PyImagesearch的
- 指定要检测的RGB值
- 检测这些RGB值所在的位置(x,y)
- 确定左上角,左下角,右上角和右下角位置
- 在这些位置之间绘制线
This color-detection example可能会帮助您对其进行编码。
当然,在白色汽车上无法检测到白板。
要说明白色汽车,您可以检查在提供的边框图像的边框上是否检测到白色。 如果是这样,请尝试在最外面的蓝色,红色或黑色像素之间绘制线条(因为车牌字母具有这种颜色)。
答案 1 :(得分:0)
我将先通过白色通过阈值过滤器,然后再加上斑点(忽略所有接触边缘的斑点),以获取牌照的大块位置。在您张贴的所有照片中,车牌没有碰到图像的边缘,并且轮廓至少有一个像素。为了获得优势,我将执行以下操作:
获取Blob中的任何点,然后从该点找到Blob中最远的点。结果应该是一个转折点。然后求出最终的角点,并从中找到最远的点。这应该给您两个相对的角。然后找到距两个点的组合距离最大的斑点点。在所有3分中,最后一次重复最远。现在,您拥有所有4个角。要订购它们,请获取中点并在每个角处创建矢量。进行顺时针缠绕。
让我知道您是否仍然需要此解决方案或需要更好的描述,我可以在您的imgur集上编写和测试代码。根据您的示例图片,我对这种策略非常有信心。