Как определить строки в opencv?

Я пытаюсь обнаружить линии на стоянке, как показано ниже

Empty parking lot

Я надеюсь получить четкие линии и (x, y) позицию в пересеченной линии, однако результат не очень перспективен

Parking lot with Hough Lines drawn

Я думаю, это связано с двумя основными причинами

  1. некоторые линии очень сломаны или отсутствуют, даже человеческие глаза могут четко идентифицировать их. (Даже HoughLine может помочь связать некоторые недостающие строки, так как HoughLine иногда соединял ненужные строки вместе, поэтому я предпочел бы сделать это вручную)

  2. есть несколько повторяющихся строк

Общий трубопровод для работы показан ниже

1. выберите некоторые конкретные цвета (белые или желтые)

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

# white color mask
img = cv2.imread(filein)
#converted = convert_hls(img)
image = cv2.cvtColor(img,cv2.COLOR_BGR2HLS)
lower = np.uint8([0, 200, 0])
upper = np.uint8([255, 255, 255])
white_mask = cv2.inRange(image, lower, upper)
# yellow color mask
lower = np.uint8([10, 0,   100])
upper = np.uint8([40, 255, 255])
yellow_mask = cv2.inRange(image, lower, upper)
# combine the mask
mask = cv2.bitwise_or(white_mask, yellow_mask)
result = img.copy()
cv2.imshow("mask",mask) 

Binary image

2. повторите дилатацию и эрозию до тех пор, пока изображение не будет изменено (ссылка)

height,width = mask.shape
skel = np.zeros([height,width],dtype=np.uint8)      #[height,width,3]
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))
temp_nonzero = np.count_nonzero(mask)
while(np.count_nonzero(mask) != 0 ):
    eroded = cv2.erode(mask,kernel)
    cv2.imshow("eroded",eroded)   
    temp = cv2.dilate(eroded,kernel)
    cv2.imshow("dilate",temp)
    temp = cv2.subtract(mask,temp)
    skel = cv2.bitwise_or(skel,temp)
    mask = eroded.copy()

cv2.imshow("skel",skel)
#cv2.waitKey(0)

After the erosion and dialation

3. примените canny для фильтрации линий и используйте HoughLinesP для получения строк

edges = cv2.Canny(skel, 50, 150)
cv2.imshow("edges",edges)
lines = cv2.HoughLinesP(edges,1,np.pi/180,40,minLineLength=30,maxLineGap=30)
i = 0
for x1,y1,x2,y2 in lines[0]:
    i+=1
    cv2.line(result,(x1,y1),(x2,y2),(255,0,0),1)
print i

cv2.imshow("res",result)
cv2.waitKey(0)

After Canny

Я удивляюсь, что после первого шага выбора определенного цвета линии со сломанными и шумами, я бы подумал, что на этом этапе мы должны сделать что-то, чтобы сделать ломаную линию полной, менее шумной линией, а затем попытаться применить что-то, чтобы сделать Линии Canny и Hough, любые идеи?

Ответ 1

Вот мой конвейер, может быть, он может вам помочь.

Сначала получите серое изображение и обработайте GaussianBlur.

img = cv2.imread('src.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)

Во-вторых, обнаружение края процесса использует Canny.

low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)

Затем используйте HoughLinesP для получения строк. Вы можете настроить параметры для лучшей производительности.

rho = 1  # distance resolution in pixels of the Hough grid
theta = np.pi / 180  # angular resolution in radians of the Hough grid
threshold = 15  # minimum number of votes (intersections in Hough grid cell)
min_line_length = 50  # minimum number of pixels making up a line
max_line_gap = 20  # maximum gap in pixels between connectable line segments
line_image = np.copy(img) * 0  # creating a blank to draw lines on

# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line segments
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
                    min_line_length, max_line_gap)

for line in lines:
    for x1,y1,x2,y2 in line:
    cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),5)

Наконец, нарисуйте линии на вашем srcImage.

# Draw the lines on the  image
lines_edges = cv2.addWeighted(img, 0.8, line_image, 1, 0)

Вот моя последняя работа.

Конечное изображение:

enter image description here

Ответ 2

Я не уверен, что именно вы спрашиваете, поскольку в вашей публикации нет никаких вопросов.

Одним из хороших и надежных методов определения сегментов линии является LSD (детектор сегментов линии), доступный в openCV с openCV 3.

Вот простой простой код C++, который, вероятно, может быть легко преобразован в python:

int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/parking.png");
    cv::Mat gray;
    cv::cvtColor(input, gray, CV_BGR2GRAY);


    cv::Ptr<cv::LineSegmentDetector> det;
    det = cv::createLineSegmentDetector();



    cv::Mat lines;
    det->detect(gray, lines);

    det->drawSegments(input, lines);

    cv::imshow("input", input);
    cv::waitKey(0);
    return 0;
}

Предоставление этого результата:

enter image description here

Что выглядит лучше для дальнейшей обработки, чем ваше изображение (без дубликатов строк и т.д.)

Ответ 3

Здесь есть несколько отличных ответов на первую часть вашего вопроса, но что касается второй части (нахождение пересечений линий), я не вижу многого.

Я бы предложил вам взглянуть на алгоритм Бентли-Оттмана.

Есть несколько реализаций python алгоритма здесь и здесь.

Изменение: используя реализацию VeraPoseidon Houghlines и вторую связанную с ней библиотеку, мне удалось получить следующий результат для обнаружения пересечения. Поблагодарите Веру и автора библиотеки за их хорошую работу. Зеленые квадраты представляют собой обнаруженное пересечение. Есть несколько ошибок, но для меня это кажется действительно хорошим отправным пунктом. Кажется, что в большинстве местоположений, на которых вы действительно хотите обнаружить пересечение, обнаружено несколько пересечений, поэтому вы могли бы запустить окно соответствующего размера над изображением, которое искало несколько пересечений и считало истинное пересечение, как тот, где это окно активировалось.

Bentley-Ottmann applied to Houghlines

Вот код, который я использовал для создания этого результата:

import cv2
import numpy as np
import isect_segments_bentley_ottmann.poly_point_isect as bot


img = cv2.imread('parking.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)

low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)

rho = 1  # distance resolution in pixels of the Hough grid
theta = np.pi / 180  # angular resolution in radians of the Hough grid
threshold = 15  # minimum number of votes (intersections in Hough grid cell)
min_line_length = 50  # minimum number of pixels making up a line
max_line_gap = 20  # maximum gap in pixels between connectable line segments
line_image = np.copy(img) * 0  # creating a blank to draw lines on

# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line segments
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
                    min_line_length, max_line_gap)
print(lines)
points = []
for line in lines:
    for x1, y1, x2, y2 in line:
        points.append(((x1 + 0.0, y1 + 0.0), (x2 + 0.0, y2 + 0.0)))
        cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 5)

lines_edges = cv2.addWeighted(img, 0.8, line_image, 1, 0)
print(lines_edges.shape)
#cv2.imwrite('line_parking.png', lines_edges)

print points
intersections = bot.isect_segments(points)
print intersections

for inter in intersections:
    a, b = inter
    for i in range(3):
        for j in range(3):
            lines_edges[int(b) + i, int(a) + j] = [0, 255, 0]

cv2.imwrite('line_parking.png', lines_edges)

Вы можете использовать что-то вроде этого блока кода для стратегии удаления нескольких пересечений в небольшой области:

for idx, inter in enumerate(intersections):
    a, b = inter
    match = 0
    for other_inter in intersections[idx:]:
        c, d = other_inter
        if abs(c-a) < 15 and abs(d-b) < 15:
            match = 1
            intersections[idx] = ((c+a)/2, (d+b)/2)
            intersections.remove(other_inter)

    if match == 0:
        intersections.remove(inter)

Выходное изображение: Cleaned Output

Однако вам придется играть с функцией окон.

Ответ 4

что произойдет, если вы настроите maxLineGap или размер вашего ядра эрозии. Кроме того, вы можете найти расстояние между линиями. Вам нужно будет идти, если пары строк говорят, что ax1, ay1 - ax2, ay2 cf bx1, by1 - bx2, by2 вы можете найти точку, где градиент под прямым углом (-1 по градиенту линии) до линии пересечений b, Базовая школьная геометрия и одновременные уравнения, что-то вроде:

x = (ay1 - by1) / ((by2 - by1) / (bx2 - bx1) + (ax2 - ax1) / (ay2 - ay1))
# then
y = by1 + x * (by2 - by1) / (bx2 - bx1)

и сравните x, y с ax1, ay1

PS вам может потребоваться добавить проверку расстояния между ax1, ay1 и bx1, by1, поскольку некоторые из ваших линий выглядят как продолжение других линий, и это может быть устранено методом ближайшей точки.