用于45度线的OpenCV线检测

时间:2018-11-27 06:09:49

标签: image opencv image-processing opencv3.0 hough-transform

我有一张图片:

original image where opencv houghP transform can't find the -45 degree line

在此图像中,OpenCV Hough变换无法使用来检测-45度大线

minLineLength = 150 
maxLineGap = 5 
line_thr = 150 
linesP = cv.HoughLinesP(dst, 1, np.pi / 180, line_thr, None, minLineLength, maxLineGap) 

找到的唯一行是:

lines found

我也尝试过各种阈值,但在这里找不到线。

如果我这样手动裁剪图像:

cropped version where line is found

然后我可以清楚地看到OpenCV Hough变换找到了正确的行:

line found

我想在非裁剪版本中找到同一行。在非裁剪版本上找到任何建议吗?

在某些情况下,X轴长度根本没有线,或者该线没有一直延伸。 例子

enter image description here enter image description here

4 个答案:

答案 0 :(得分:1)

我是使用 ImageMagick 在终端中的命令行上完成此操作的,但是您可以使用 OpenCV 完全相同的技术。

第1步

拍摄图像并将其旋转45度,在需要时引入黑色像素作为背景:

convert 45.jpg -background black -rotate 45 result.png

enter image description here

第2步

现在,在上一条命令的基础上,将每个像素设置为以1px宽,250px高的框为中心的中间值:

convert 45.jpg -background black -rotate 45 -statistic median 1x250 result.png

enter image description here

第3步

现在,再次基于上一个命令,将其旋转回45度:

convert 45.jpg -background black -rotate 45 -statistic median 1x250 -rotate -45 result.png

enter image description here


因此,总的来说,整个处理过程是:

convert input.jpg -background black -rotate 45 -statistic median 1x250 -rotate -45 result.png

很明显,然后将其裁剪回原始大小,并与原始文件并排附加以进行检查:

convert 45.jpg -background black -rotate 45 -statistic median 5x250 -rotate -45 +repage -gravity center -crop 184x866+0+0 result.png
convert 45.jpg result.png +append result.png 

enter image description here


您也可以使用mean统计信息加上阈值阈值而不是median,因为它比查找中位数的排序要快,但是它往往会导致拖尾:

convert 45.jpg -background black -rotate 45 -statistic mean 1x250 result.png

enter image description here

您新添加的图像被处理为以下结果:

enter image description here

答案 1 :(得分:1)

我实现了一个比其他答案略微简单的算法,但是这次是使用 OpenCV 在Python中实现的。

基本上,它不是对垂直列像素取平均值,而是对列中的像素求和,然后选择最亮的列。如果我显示带填充的旋转图像,并在下面显示另一列代表各列总和的图像,则应查看其工作原理:

enter image description here

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image as greyscale
im = cv2.imread('45.jpg',cv2.IMREAD_GRAYSCALE)

# Pad with border so it isn't cropped when rotated
bw=300
bordered = cv2.copyMakeBorder(im, top=bw, bottom=bw, left=bw, right=bw, borderType= cv2.BORDER_CONSTANT)

# Rotate -45 degrees
w, h = bordered.shape
M = cv2.getRotationMatrix2D((h/2,w/2),-45,1)
paddedrotated = cv2.warpAffine(bordered,M,(h,w))
# DEBUG cv2.imwrite('1.tif',paddedrotated)

# Sum the elements of each column and find column with most white pixels
colsum = np.sum(paddedrotated,axis=0,dtype=np.float)
col = np.argmax(colsum)
# DEBUG cv2.imwrite('2.tif',colsum)

# Fill with black except for the line we have located which we make white
paddedrotated[:,:] = 0
paddedrotated[:,col] = 255

# Rotate back to straight
w, h = paddedrotated.shape
M = cv2.getRotationMatrix2D((h/2,w/2),45,1)
straight = cv2.warpAffine(paddedrotated,M,(h,w))

# Remove padding and save to disk
straight = straight[bw:-bw,bw:-bw]
cv2.imwrite('result.png',straight)

请注意,您实际上不必将图像旋转回直线,也可以将其裁剪回原始大小。您实际上可以在第一行显示以下内容后停止:

col = np.argmax(colsum)

并使用一些基本三角学来计算原始图像中的含义。

以下是输出:

enter image description here


关键字:线检测,检测线,旋转,填充,边框,投影,项目,图像,图像处理,Python,OpenCV,仿射,霍夫(Hough)

答案 2 :(得分:1)

问题显然是您要搜索的行不是行。它实际上看起来像是一列由相连的圆圈和盒子组成的火车。因此,我建议您执行以下操作:

使用查找轮廓查找图像中的所有轮廓

img = cv.imread('image.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, 0)
img2, contours, hierarchy = cv.findContours(thresh, CHAIN_APPROX_SIMPLE ,cv.RETR_EXTERNAL)

这将返回许多轮廓,因此请使用循环仅保存足够长的轮廓。由于图像尺寸为814x1041像素,因此如果图像轮廓至少是图像宽度的10%(几乎为100)(我必须明显优化此值),我就认为轮廓很长

long_contours = []
for contour in contours[i]:
    perimeter = cv2.arcLength(contour,True)
    if (perimeter > 0.1 * 1018)  # 10% of the image width
        long_contours.append(contour)

现在在那些可能也是直线的长轮廓周围绘制一个旋转的边界矩形。如果长轮廓的宽度远大于其高度或长宽比较大(例如8,则还需要优化此值),则将其视为一条线。

for long_contour in long_contours:
    rect = cv2.minAreaRect(long_contour)
    aspec_ratio =  rect.width / rect.height

    if aspec_ratio > 8 : 
       box = cv2.boxPoints(rect)
       box = np.int0(box)
       cv2.drawContours(img,[box],0,(255,255,255),cv.FILLED)

最后,您应该得到类似的东西。请注意,此处的代码仅供参考。

Rotated rectangle over a suspected line

答案 3 :(得分:1)

您的原始代码可以作为哨子。唯一的问题是您的图像包含太多信息,这些信息会弄乱累加器得分。如果将线路阈值提高到255,一切都会正常进行。

minLineLength = 150 
maxLineGap = 5
line_thr = 255
linesP = cv2.HoughLinesP(dst, 1, np.pi / 180.0, line_thr, None, minLineLength, maxLineGap) 

以下是使用该值的结果。 由于白色像素尺寸较大,因此这里检测到3条线。

[  1  41 286 326]
[  0  42 208 250]
[  1  42 286 327]

enter image description here

由于与上述相同的原因,在同一区域附近检测到

5条线。使用形态学运算或距离变换减小像素大小应该可以解决此问题。

[110 392 121 598]
[112 393 119 544]
[141 567 147 416]
[ 29 263  29 112]
[  0  93 179 272]

enter image description here

此处未找到任何行。 enter image description here