Comment détecter les lignes dans opencv?

je suis en train d'essayer de détecter les lignes de stationnement, comme illustré ci-dessous

Empty parking lot

ce que j'espère obtenir est les lignes claires et (x,y) la position dans la ligne croisée, mais le résultat n'est pas très prometteur

Parking lot with Hough Lines drawn

je suppose que c'est dû à deux raisons principales

  1. certaines lignes sont très brisées ou manquantes même les yeux humains peuvent clairement les identifier. (Même HoughLine peut aider pour connecter quelques disparus les lignes puisque HoughLine connectait parfois des lignes inutiles ensemble, donc je préfère le faire manuellement)

  2. il y a quelques répété lignes

le pipeline général pour le travail est montré comme ci-dessous

1. sélectionnez les couleurs spécifiques (blanc ou jaune)

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. répétez la dilatation et l'érosion jusqu'à ce que l'image ne peut pas être changé (référence )

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. appliquez le Candy pour filtrer les lignes et utilisez HoughLinesP pour obtenir les lignes

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

je me demande après la première étape de sélection de certaines couleurs, les lignes sont avec des bris et des bruits , je pense que dans cette étape, nous devrions faire quelque chose pour rendre la ligne brisée une ligne complète, moins bruyante, et ensuite essayer d'appliquer quelque chose pour faire les lignes Canny et Hough, des idées ?

17
demandé sur Alexander Reynolds 2017-07-26 12:19:29

4 réponses

Voici mon pipeline, peut-être que cela peut vous aider.

tout d'abord, obtenir l'image grise et traiter 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)

Deuxièmement, le processus de détection de bord utilisation Habile.

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

puis, utilisez HoughLinesP pour obtenir les lignes. vous pouvez ajuster les paramètres pour une meilleure performance.

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)

enfin, dessinez les lignes sur votre image.

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

voici ma finale performance.

Image Finale:

enter image description here

14
répondu veraposeidon 2017-08-09 04:57:19

Je ne suis pas sûr de ce que vous demandez exactement, puisqu'il n'y a pas de question dans votre message.

une technique agréable et robuste pour détecter les segments de ligne est le LSD (détecteur de segment de ligne), disponible en openCV depuis openCV 3.

voici un simple code C++ de base, qui peut probablement être converti en python facilement:

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;
}

donnant ce résultat:

enter image description here

qui semble meilleur pour un traitement ultérieur que votre image (pas de duplicata de ligne, etc.))

8
répondu Micka 2017-08-03 10:30:03

il y a quelques bonnes réponses ici à la première partie de votre question, mais pour la deuxième partie (trouver les intersections de ligne) Je ne vois pas beaucoup.

je vous suggère de jeter un coup d'oeil à la Bentley-Ottmann algorithme.

il y a quelques implémentations python de l'algorithme ici et ici.

Edit: en utilisant L'implémentation Houghlines de VeraPoseidon et la seconde bibliothèque liée ici, j'ai réussi à obtenir le résultat suivant pour l'intersection de détection. Vera et l'auteur de la bibliothèque méritent d'être félicités pour leur excellent travail. Les carrés verts représentent une intersection détectée. Il y a quelques erreurs, mais ça me semble être un très bon point de départ. Il semble que la plupart des endroits que vous voulez vraiment détecter une intersection ont plusieurs intersections détectées, de sorte que vous pourriez probablement exécuter une fenêtre de taille appropriée sur l'image qui a cherché de multiples intersections et considéré comme un véritable carrefour où la fenêtre active.

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)

vous pouvez utiliser quelque chose comme ce bloc de code pour une stratégie pour supprimer les intersections multiples dans une petite zone:

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)

image de sortie:Cleaned Output

vous devrez cependant jouer avec la fonction fenêtrage.

5
répondu Saedeas 2018-04-04 18:32:11

que se passe-t-il si vous ajustez maxLineGap ou la taille de votre noyau d'érosion? Vous pouvez aussi trouver la distance entre les lignes. Vous devriez aller bien que les paires de lignes disent ax1, ay1 à ax2, ay2 C. F. bx1, by1 à bx2, by2 vous pouvez trouver le point où le gradient à angle droit (-1 au-dessus du gradient de la ligne) à une ligne traverse B. Géométrie de base de l'école et équations simultanées, quelque chose comme:

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

et comparer x, y avec ax1, ay1

PS vous pourriez avoir besoin d'ajouter un vérifiez la distance entre ax1, ay1 et bx1,by1 car certaines de vos lignes semblent être des continuations d'autres lignes et celles-ci pourraient être éliminées par la technique du point le plus proche.

1
répondu paddyg 2017-07-26 10:09:48