霍夫变换——HoughLines、HoughLinesP和HoughCircles

一、霍夫变换

1、霍夫变换是一种在图像中寻找直线、圆形及其他简单形状的方法。
2、笛卡尔空间与霍夫空间映射关系

  • 笛卡尔空间内的一条直线确定了霍夫空间内的一个点。
  • 霍夫空间内的一个点确定了笛卡尔空间内的一条直线。

3、霍夫变换选择直线的基本思路:选择由尽可能多条线汇成的点。

二、直线检测

1、绘制直线方法

  • 垂直方向的直线,计算它与图像水平边界的交叉点,在两个交叉点之间画线。
  • 水平方向的直线,在图像的第一列和最后一列之间画线。

2、cv.line优点

没有必要检查交叉点是否位于图像内部,即使点的坐标超出了图像的范围,也能正确画出线来。

3、基本霍夫变换——HoughLines函数
(1)要求:所操作的原图像是一个二值图像,变换之前先将原图像进行二值化或进行canny边缘检测。
(2)HoughLines检测到的是图像中的直线而不是线段,即检测到的直线是没有端点的。
(3)代码

# 直线检测
def line_detection(image):
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)
    """
    HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None)
        image:8位,单通道二值源图像
        rho:以像素为单位的距离r的精度,一般为1.
        theta:角度0的精度, CV.PI/180表示搜索所有可能的角度。
        threshold:阈值,线段超过设定的阈值才被检测出来。值越小,判定出的直线就越多。
        lines:检测到的直线的参数vector(ρ,θ) or (ρ,θ,votes) ;ρ是距坐标原点的距离,θ是以弧度表示的线旋转角度(0∼垂直直线,π/2∼水平直线) ,votes 曲线交点累加计数
        srn:
        stn:
        min_theta:检查线条的最小角度。必须介于0和maxθ之间。
        max_theta:要检查线条的最大角度。必须介于minθ和CV_PI之间
    """
    lines = cv.HoughLines(edges, 1, np.pi / 180, 200)
    # 遍历lines,绘制出所有的直线
    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * a)
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * a)
        cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv.imshow('image_lines', image)

霍夫变换——HoughLines、HoughLinesP和HoughCircles_第1张图片
霍夫变换——HoughLines、HoughLinesP和HoughCircles_第2张图片
2、概率霍夫变换——HoughLinesP函数

概率霍夫变换没有考虑所有的点,只需要一个足以进行检测的随机点子集即可。

def line_detect_possible_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)
    """
    HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
        minLineLength:用来控制“接受直线的最小长度”的值,默认0
        maxLineGap:用来控制接受共线线段之间的最小间隔,如果两点之间的最大间隔大于maxLineGap,认为这两点不在一条线上,默认0
    """
    lines = cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
    cv.imshow('line_detect_possible_demo', image)

霍夫变换——HoughLines、HoughLinesP和HoughCircles_第3张图片
霍夫变换——HoughLines、HoughLinesP和HoughCircles_第4张图片

三、圆检测

霍夫圆变换中,需要考虑圆半径和圆心(x坐标,y坐标)共3个系数,采用的策略是两轮筛选。第1轮筛选找出可能存在圆的位置(圆心),第2轮再根据第1轮的结果筛选出半径大小。

def Mdetect_circles_demo(image):
    """
    :param image: pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None)
    :return: src:输入图像,8位,三通道的彩色图像
             sp:定义的漂移物理空间半径大小
             sr:定义的漂移色彩空间半径大小
             dst:输出图像,跟输入src有同样的大小和数据格式
             maxLevel:定义金字塔的最大层数
             termcrit:定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合
    """
    # pyrMeanShiftFiltering:漂移圆检测
    dst = cv.pyrMeanShiftFiltering(image, 50, 30)
    circles = np.uint16(np.around(dst))
    for i in circles[0, :]:
        cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)
        cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)
    cv.imshow('Mdetect_circles_demo', image)


def circles_demo(image):
    # 消除噪声
    cimage = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    circle = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
    circles = np.uint16(np.around(circle))
    for i in circles[0, :]:
        # 取圆心
        cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)
    cv.imshow('circles_demo', image)


def detect_circles_demo(image):
    # 消除噪声
    cimage = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    """
    HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
        image:8位单通道灰度图像
        method:检测方法,HOUGH_GRADIENT:基于梯度做比较快且是唯一可用的参数值
        dp:累加器分辨率,用来指定图像分辨率与圆心累加器分辨率的比率。1表示输入图像和累加器具有相同的分辨率。
        minDist:圆心间的最小间距。如果存在圆心间距离小于该值的圆,仅有一个会被检测出来。如20:把小于20最近的多个合并成一个圆。
        circles:返回值,由圆心坐标和半径构成的numpy.ndarry
        param1:缺省,默认100.对应是canny边缘检测器的高阈值(底阈值是高阈值的二分之一)
        param2:圆心位置必须收到的投票数。值越大,检测到的圆越少;越小,检测到的圆越多。缺省,默认100.
        minRadius:圆半径的最小值,小于该值的圆不会被检测出来。缺省,默认0,不起作用。
        maxRadius:圆半径的最大值,大于该值的圆不会被检测出来。缺省,默认0,不起作用。
    """
    circle = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
    """
    around(a, decimals=0, out=None)
        a:输入列表或矩阵
        decimals:为n对输入近似后保留小数点后n位,默认为0,若值为-n,则对小数点左边第n位近似
        out:保存近似返回结果
    """
    circles = np.uint16(np.around(circle))
    for i in circles[0, :]:
        # 图像,中心点位置,半径,颜色
        """
        circle(img, center, radius, color, thickness=None, lineType=None, shift=None)
            img:单通道或多通道的图像
            center:圆心坐标
            radius:半径,数值为整数类型
            color:圆线条的颜色
            thickness:圆线条的粗细,值越大则线条越粗。
            lineType:线条的类型。CV_AA(采用了高斯滤波)三个值,分别代表8邻接连接线,4邻接连接线和反锯齿连接线,默认值为8邻接。
            shift:圆心坐标点和半径值的小数点位数,数值为整数类型。
        """
        # 圆变换
        cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)
    cv.imshow('detect_circles_demo', image)

你可能感兴趣的:(python,opencv,图像处理)