我有一张图片:
在此图像中,OpenCV Hough变换无法使用来检测-45度大线
minLineLength = 150
maxLineGap = 5
line_thr = 150
linesP = cv.HoughLinesP(dst, 1, np.pi / 180, line_thr, None, minLineLength, maxLineGap)
找到的唯一行是:
我也尝试过各种阈值,但在这里找不到线。
如果我这样手动裁剪图像:
然后我可以清楚地看到OpenCV Hough变换找到了正确的行:
我想在非裁剪版本中找到同一行。在非裁剪版本上找到任何建议吗?
在某些情况下,X轴长度根本没有线,或者该线没有一直延伸。 例子
答案 0 :(得分:1)
我是使用 ImageMagick 在终端中的命令行上完成此操作的,但是您可以使用 OpenCV 完全相同的技术。
第1步
拍摄图像并将其旋转45度,在需要时引入黑色像素作为背景:
convert 45.jpg -background black -rotate 45 result.png
第2步
现在,在上一条命令的基础上,将每个像素设置为以1px宽,250px高的框为中心的中间值:
convert 45.jpg -background black -rotate 45 -statistic median 1x250 result.png
第3步
现在,再次基于上一个命令,将其旋转回45度:
convert 45.jpg -background black -rotate 45 -statistic median 1x250 -rotate -45 result.png
因此,总的来说,整个处理过程是:
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
您也可以使用mean
统计信息加上阈值阈值而不是median
,因为它比查找中位数的排序要快,但是它往往会导致拖尾:
convert 45.jpg -background black -rotate 45 -statistic mean 1x250 result.png
您新添加的图像被处理为以下结果:
答案 1 :(得分:1)
我实现了一个比其他答案略微简单的算法,但是这次是使用 OpenCV 在Python中实现的。
基本上,它不是对垂直列像素取平均值,而是对列中的像素求和,然后选择最亮的列。如果我显示带填充的旋转图像,并在下面显示另一列代表各列总和的图像,则应查看其工作原理:
#!/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)
并使用一些基本三角学来计算原始图像中的含义。
以下是输出:
关键字:线检测,检测线,旋转,填充,边框,投影,项目,图像,图像处理,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)
最后,您应该得到类似的东西。请注意,此处的代码仅供参考。
答案 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]
由于与上述相同的原因,在同一区域附近检测到5条线。使用形态学运算或距离变换减小像素大小应该可以解决此问题。
[110 392 121 598]
[112 393 119 544]
[141 567 147 416]
[ 29 263 29 112]
[ 0 93 179 272]