核心思想:二维平面中的每一条直线都对应唯一的一组(r,θ)
由上图写出直线公式:
整理得:
对于图像上的任意一点,通过遍历r(或θ)就可以得到一系列的(r,θ),对边缘(Canny算子提取的图像边缘二值化图片)上的每个点进行遍历,那么位于同一直线上的点的(r,θ)肯定经过同一个(r0,θ0),这个(r0,θ0)对应的直线就是我们检测到的直线啦。(就是投票的思想)
Hough直线检测由于缺乏筛选验证的部分因此可能导致过拟合或者欠拟合(实际上是中间参数选取不合理导致)——也就是说使用Hough直线检测针对不同的图片要使用不同的参数(调试)。
void HoughLinesP(InputArray image, double rho, double theta, int threshold, OutputArray lines, double minLineLength=0, double maxLineGap=0 )
可以看出,后三个参数threshold、minLineLength、maxLineGap决定着直线检测的效果和精度,阈值越大、minLineLength越长、maxLineGap越小,检测的条件越严苛,检测得也就越准,但也会出现检测不出来的情况。
import cv2
import numpy as np
import math
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread('22-2.tif')
img = img[:,650:1050]
#cv_show('1',img)
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#cv_show('1',img_gray)
img_gaus = cv2.GaussianBlur(img_gray,(7,7),0)
#cv_show('1',img_gaus)
ret,dst = cv2.threshold(img_gaus,53,255,cv2.THRESH_BINARY)
#cv_show('1',dst)
img_edge = cv2.Canny(dst,50,50)
#cv_show('1',img_edge)
#h,w = img_gray.shape[:2]
threshold = 150 #累加平面的阈值参数,累加平面中某一数值必须大于阈值才能被判定为直线
minLineLength = 1180 #默认值0最小线段长度,小于该长度的线段不被显现
maxLineGap = 100 #默认值为0,允许将# 同一行点与点连接起来
# 的最大距离
lines = cv2.HoughLinesP(img_edge,1,np.pi/180,threshold,2,minLineLength,maxLineGap)
print(lines.shape)
#length = []
for line in lines:
line=line.reshape(4)
#length.append(math.sqrt((line[0] - line[2]) ** 2 + (line[1] - line[3]) ** 2))
cv2.line(img,(line[0],line[1]),(line[2],line[3]),(0,0,255),1)
#print(length)
cv_show('img',img)
cv2.imwrite('22_line.tif',img)
几点说明:
print(lines.shape)
,可以确定检测出的直线数量。cv2.line()函数
作用:画直线
cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]])
FLD在opencv-contrib-python中,要先安装。
AttributeError: module 'cv2.cv2' has no attribute 'ximgproc'
按照网上的教程,先补个包
pip install opencv-contrib-python
再来
AttributeError: module 'cv2' has no attribute 'gapi_wip_gst_GStreamerPipeline'
原因是opencv-python和opencv-contrib-python只能留一个
(单独卸载opencv-python没解决问题)
这里把opencv-python和opencv-contrib-python再安装一次opencv-contrib-python
问题解决了(撒花)
opencv中的FLD类中有下面三个函数:
下面重点说明createFastLineDetector()函数
https://docs.opencv.org/3.3.1/df/d4c/classcv_1_1ximgproc_1_1FastLineDetector.html
以下为opencv官方代码中对该函数的说明:
// Create FLD detector
// Param Default value Description
// length_threshold 10 - Segments shorter than this will be discarded
// distance_threshold 1.41421356 - A point placed from a hypothesis line
// segment farther than this will be
// regarded as an outlier
// canny_th1 50 - First threshold for
// hysteresis procedure in Canny()
// canny_th2 50 - Second threshold for
// hysteresis procedure in Canny()
// canny_aperture_size 3 - Aperturesize for the sobel
// operator in Canny()
// do_merge false - If true, incremental merging of segments
// will be perfomred
int length_threshold = 10;
float distance_threshold = 1.41421356f;
double canny_th1 = 50.0;
double canny_th2 = 50.0;
int canny_aperture_size = 3;
bool do_merge = false;
Ptr<FastLineDetector> fld = createFastLineDetector(length_threshold,
distance_threshold, canny_th1, canny_th2, canny_aperture_size,
do_merge);
vector<Vec4f> lines_fld;
该函数的功能可以理解为创建一个LSD对象,其输入参数包括:
# coding=utf-8
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 读取输入图片
img = cv2.imread("2-2.tif")
img = img[:,650:1050]
# 将彩色图片转换为灰度图片
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 滤波
img_gaus = cv2.GaussianBlur(img_gray,(7,7),0)
# 阈值处理,为了更好的提取边缘
ret,dst = cv2.threshold(img_gaus,45,255,cv2.THRESH_BINARY)
#cv_show('1',dst)
#img_edge = cv2.Canny(dst,50,80)
#cv_show('1',img_edge)
# 创建一个FLD对象
fld = cv2.ximgproc.createFastLineDetector(length_threshold = 8, distance_threshold = 1, canny_th1 = 20, canny_th2 = 25, canny_aperture_size = 3 , do_merge = True)
#fld = cv2.ximgproc.createFastLineDetector(length_threshold = 10 ,distance_threshold = 1.41421356f ,canny_th1 = 50,canny_th2 = 50,canny_aperture_size = 3,do_merge = False)
# 执行检测结果
dlines = fld.detect(dst)
print(dlines.shape)
# 绘制检测结果
drawn_img = fld.drawSegments(img,dlines)
'''
for dline in dlines:
x0 = int(round(dline[0][0]))
y0 = int(round(dline[0][1]))
x1 = int(round(dline[0][2]))
y1 = int(round(dline[0][3]))
cv2.line(img, (x0, y0), (x1,y1), (0,0,255), 1)
'''
# 显示并保存结果
cv_show('img',drawn_img)
cv2.imwrite('2_FLD.tif', drawn_img)
说明:
cv2.ximgproc.createFastLineDetector
中直接输入灰度图也是ok的;cv2.ximgproc.createFastLineDetector
中所有参数都有默认值,因此可以以cv2.ximgproc.createFastLineDetector()
形式直接使用;fld = cv2.ximgproc.createFastLineDetector(length_threshold = 30, distance_threshold = 20, canny_th1 = 20, canny_th2 = 25, canny_aperture_size = 3 , do_merge = True)
只看了一篇论文:
[1]龚云,颉昕宇.一种改进同态滤波的井下图像增强算法[J/OL].煤炭科学技术:1-8[2022-11-27].DOI:10.13199/j.cnki.cst.2021-0774.
没有专门整理,这里不做记录了。