Итак, я обучил нейронную сеть распознавания объектов (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()
Вот несколько примеров результатов:
(Изображения в верхнем ряду - результаты этапа обнаружения краев)
Successfuls:
Unsuccessfuls:
Успешные дела:
И случай, когда четырехугольник / параллелограмм не найден, но многоугольник с наибольшей найденной площадью нарисован:
все эти результаты с точно таким же набором параметров (пороги, ... и т. Д.)
Я также пытался применить преобразование Хафа, используя 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()
Неужели так сложно добиться высокого успеха, используя только методы обработки изображений? Конечно, машинное обучение решило бы эту проблему как кусок пирога, но я думаю, что это было бы излишним, и у меня все равно нет аннотированных данных для него.