Comment détecter les lignes dans opencv?
je suis en train d'essayer de détecter les lignes de stationnement, comme illustré ci-dessous
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
je suppose que c'est dû à deux raisons principales
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)
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)
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)
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)
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 ?
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:
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:
qui semble meilleur pour un traitement ultérieur que votre image (pas de duplicata de ligne, etc.))
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.
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)
vous devrez cependant jouer avec la fonction fenêtrage.
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.