如何检测opencv中的行?

2024-04-19 23:46:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在检测停车场的线路,如下所示

Empty parking lot

我希望得到的是在交叉线上的清晰线和(x,y)位置,但是结果不是很有希望

Parking lot with Hough Lines drawn

我想主要是因为两个原因

  1. 有些纹路断了,甚至连人眼都看不清 识别他们。(即使是HoughLine也可以帮助连接一些丢失的 因为HoughLine有时会连接不必要的线路 一起,所以我宁愿手动操作)

  2. 有一些重复的行

工程总管道如下

一。选择一些特定的颜色(白色或黄色)

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。重复扩张和侵蚀,直到图像无法改变(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)

 After the erosion and dialation

三。用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

我不知道在选择了某个颜色的第一步后,线是有断线和噪音的,我想在这一步我们应该做些什么,使断线完整,噪音更小的线,然后尝试应用一些东西来做精明和豪夫线,有什么想法吗?


Tags: importimgmatplotlibnpmaskcv2upperlower
3条回答

我不知道你到底在问什么,因为你的帖子里没有问题。

从openCV 3开始,openCV中就出现了LSD(线段检测器),这是一种很好的检测线段的健壮技术。

这里有一些简单的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

比你的图像更适合进一步处理(没有行重复等)

这里有一些很好的答案来回答你的第一部分问题,但是对于第二部分(寻找直线交点),我没有看到太多。

我建议你看看Bentley-Ottmann算法。

有一些算法herehere的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

不过,你得玩窗口功能。

这是我的管道,也许它能给你一些帮助。

首先,获取灰度图像并处理高斯模糊。

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

相关问题 更多 >