opencv学习十五:直线检测

直线检测

原理介绍:

1、对于直角坐标系中的任意一点A(x0,y0),经过点A的直线满足Y0=k*X0+b.(k是斜率,b是截距)

2、那么在X-Y平面过点A(x0,y0)的直线簇可以用Y0=k*X0+b表示,但对于垂直于X轴的直线斜率是无穷大的则无法表示。因此将直角坐标系转换到极坐标系就能解决该特殊情况。

3、在极坐标系中表示直线的方程为ρ=xCosθ+ySinθ(ρ为原点到直线的距离),如图所示:
在这里插入图片描述在这里插入图片描述变换图示
在这里插入图片描述
霍夫直线检测的两种方法
1.获取灰度图像
2.canny边缘检测
3.获取霍夫直线信息
4.算出直线位置,画出每条直线

直线检测代码实现方法1

一:标准霍夫线变换

void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
参数:
image:边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)
lines:储存着检测到的直线的参数对 的容器,存储的是rho,theta
rho:参数极径 以像素值为单位的分辨率. 我们使用 1 像素.
theta:参数极角 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
theta:要”检测” 一条直线所需最少的的曲线交点
srn and stn: 参数默认为0.

cv2.HoughLines函数输出的是[float, float]形式的ndarray,其中每个值表示检测到的线(ρ , θ)中浮点点值的参数。

import cv2 as cv
import numpy as np


def line_detection(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)#apertureSize,Canny边缘检测梯度那一步,窗口大小是3   apertureSize是sobel算子大小,只能为1,3,5,7
    lines = cv.HoughLines(edges, 1, np.pi/180, 200) #函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
    for line in lines:
        print(type(lines))
        rho, theta = line[0]  #获取极值ρ长度和θ角度
        a = np.cos(theta) #获取角度cos值
        b = np.sin(theta)#获取角度sin值
        x0 = a * rho #获取x轴值
        y0 = b * rho #获取y轴值  x0和y0是直线的中点
        x1 = int(x0 + 1000 * (-b)) #获取这条直线最大值点x1
        y1 = int(y0 + 1000 * (a)) #获取这条直线最大值点y1
        x2 = int(x0 - 1000 * (-b)) #获取这条直线最小值点x2
        y2 = int(y0 - 1000 * (a)) #获取这条直线最小值点y2  其中*1000是内部规则
        cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2) #开始划线
    cv.imshow("image_lines", image)

src = cv.imread("C:/Users/lenovo/Desktop/opencv/daima/banknum/template-matching-ocr/images/sudoku.png")  #读取图片位置
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
line_detection(src)
cv.waitKey(0)
cv.destroyAllWindows()

运行截图:
在这里插入图片描述但这样会在一些情况下导致虚假检测,如像素偶然对齐或多条直线穿过同样的对齐像素造成的多重检测。

二:HoughLinesP概率霍夫变换(是加强版)使用简单,效果更好,检测图像中分段的直线(而不是贯穿整个图像的直线)

void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold,double minLineLength=0, double maxLineGap=0 )
参数:
image: 边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图) *
lines: 储存着检测到的直线的参数对 的容器,也就是线段两个端点的坐标
rho :  参数极径 以像素值为单位的分辨率. 我们使用 1 像素.
theta: 参数极角 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
threshold: 要”检测” 一条直线所需最少的的曲线交点
minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.线段的最小长度
maxLineGap:线段上最近两点之间的阈值
代码如下:

import cv2 as cv
import numpy as np


def line_detect_possible_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)  # apertureSize,Canny边缘检测梯度那一步,窗口大小是3
    lines = cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)  #函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
    #minLineLength-线的最短长度,比这个线短的都会被忽略
    #maxLineGap-两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线。
    for line in lines:
        print(type(line))
        x1, y1, x2, y2 = line[0]
        cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv.imshow("line_detect_possible_demo", image)

src = cv.imread("C:/Users/lenovo/Desktop/opencv/daima/banknum/template-matching-ocr/images/sudoku.png")  #读取图片位置
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
line_detect_possible_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

运行截图:
在这里插入图片描述
def HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None):
第一个参数是需要处理的原图像,该图像必须为cannay边缘检测后的图像;
第二和第三参数:步长为1的半径和步长为π/180的角来搜索所有可能的直线第四个参数是阈值,概念同霍夫变换第五个参数:minLineLength-线的最短长度,比这个线短的都会被忽略。

第六个参数:maxLineGap-两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线。

猜你喜欢

转载自blog.csdn.net/weixin_44145452/article/details/112767669