procesamiento - reconocer colores opencv python
¿Cómo detectar líneas en opencv? (4)
Estoy tratando de detectar líneas en el estacionamiento como se muestra a continuación
Lo que espero obtener son las líneas claras y la posición (x, y) en la línea cruzada, sin embargo el resultado no es muy prometedor
Supongo que se debe a dos razones principales.
Algunas líneas están muy rotas o faltan incluso los ojos humanos pueden identificarlas claramente. (Incluso HoughLine puede ayudar a conectar algunas líneas faltantes ya que HoughLine a veces conectaba líneas innecesarias, así que preferiría hacerlo manualmente)
hay algunas lineas repetidas
La tubería general para el trabajo se muestra a continuación.
1. Seleccione algunos colores específicos (blanco o amarillo)
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. Repita la dilatación y la erosión hasta que la imagen no pueda ser cambiada ( reference )
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. Aplique el canal para filtrar las líneas y use HoughLinesP para obtener las líneas.
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)
Me pregunto después del primer paso de seleccionar cierto color, las líneas están con quebrados y ruidos. Pensaría que en este paso deberíamos hacer algo para hacer que la línea discontinua sea una línea completa, menos ruidosa, y luego tratar de aplicar algo para hacer el Canny y Hough lineas, alguna idea?
¿Qué sucede si ajusta maxLineGap o el tamaño de su núcleo de erosión? Alternativamente, puedes encontrar la distancia entre líneas. Tendría que ir a través de pares de líneas como ax1, ay1 a ax2, ay2 cf bx1, by1 a bx2, by2 puede encontrar el punto donde se encuentra el gradiente en ángulos rectos (-1 sobre gradiente de línea) a una línea de cruces b. Geometría escolar básica y ecuaciones simultáneas, algo así como:
x = (ay1 - by1) / ((by2 - by1) / (bx2 - bx1) + (ax2 - ax1) / (ay2 - ay1))
# then
y = by1 + x * (by2 - by1) / (bx2 - bx1)
y compara x, y con ax1, ay1
Es posible que tenga que agregar una verificación de la distancia entre ax1, ay1 y bx1, by1 ya que algunas de sus líneas parecen ser continuaciones de otras líneas y estas podrían eliminarse mediante la técnica del punto más cercano.
Aquí está mi canalización, tal vez pueda brindarte ayuda.
En primer lugar, obtener la imagen gris y procesar 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)
En segundo lugar, el proceso de detección de bordes utiliza Canny.
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)
Luego, usa HoughLinesP para obtener las líneas. Puede ajustar los parámetros para un mejor rendimiento.
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)
Finalmente, dibuja las líneas en tu srcImage.
# Draw the lines on the image
lines_edges = cv2.addWeighted(img, 0.8, line_image, 1, 0)
Aquí está mi actuación final.
Imagen final:
Hay algunas respuestas geniales aquí para la primera parte de su pregunta, pero en cuanto a la segunda parte (encontrar las intersecciones de líneas) no veo mucho.
Le sugiero que eche un vistazo al algoritmo de Bentley-Ottmann .
Hay algunas implementaciones de python del algoritmo here y here .
Edición: Al usar la implementación de Houghlines de VeraPoseidon y la segunda biblioteca vinculada aquí, he logrado obtener el siguiente resultado para la detección de intersecciones. Gracias a Vera y al autor de la biblioteca por su buen trabajo. Los cuadrados verdes representan una intersección detectada. Hay algunos errores, pero este me parece un buen punto de partida. Parece que la mayoría de las ubicaciones en las que realmente desea detectar una intersección tienen múltiples intersecciones detectadas, por lo que probablemente podría ejecutar una ventana del tamaño adecuado sobre la imagen que buscaba múltiples intersecciones y se considera una intersección verdadera como una donde se activó esa ventana.
Aquí está el código que utilicé para producir ese resultado:
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)
Puedes usar algo como este bloque de código para una estrategia para eliminar múltiples intersecciones en un área pequeña:
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)
Sin embargo, tendrás que jugar con la función de ventana.
No estoy seguro de qué es exactamente lo que está preguntando, ya que no hay preguntas en su publicación.
Una técnica agradable y robusta para detectar segmentos de línea es el LSD (detector de segmento de línea), disponible en openCV desde openCV 3.
Aquí hay algunos códigos básicos simples en C ++, que probablemente se pueden convertir a Python fácilmente:
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C://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;
}
Dando este resultado:
Que se ve mejor para el procesamiento posterior que su imagen (sin duplicados de líneas, etc.)