图解 cv2.HoughLines & cv2.line 参数原理

Posted Flying Bulldog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解 cv2.HoughLines & cv2.line 参数原理相关的知识,希望对你有一定的参考价值。

功能实现:利用cv.HoughLines寻找图像中霍夫直线,然后用cv2.line绘制红色的直线。

拓展:计算整幅图像的平均灰度值,以及经过筛选的霍夫直线的平均灰度值,并进行比较。

目录

一、效果图以及参数讲解 

二、图解霍夫直线的返回参数

三、源码(包含注释)

四、拓展


一、效果图以及参数讲解 

 图1 原图

 图2 边缘处理后的图像

图3 绘制红色霍夫直线的图像 

lines = cv2.HoughLines(image_edge, 1, np.pi/180, 180)

  • image_edge:经过图像边缘处理后的图像
  • 1:像素之间的距离为1
  • np.pi/180:直线角度范围,2pi/(pi/180) = 360°
  • 180:一条预选直线上的最少像素点个数

注意:

如果距离是1,180个像素即可生成直线,如果距离是2,至少360个像素才可以生成直线。

cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1) 

  • img:在图像img上绘制直线
  • (x1, y2)、(x2, y2):直线的两个端点,直接相连便可得到所需直线
  • (0, 0, 255):红色
  • 1:设置直线的宽度为1

注意:

直线的两个端点可以是负数。

二、图解霍夫直线的返回参数

cv2.HoughLines 的返回参数 line ==  ,其中,第一个参数表示图像原点距离直线的长度,第二个参数表示沿着x轴的角度大小。

如下图所示,首先通过 cv.HoughLines 得到 line ,此时已经确定了直线的位置,然后需要确定直线上的两个坐标点来充当 cv.line 的输入参数,最后,在源图像上通过 cv.line 来绘制红色直线。

 图4 图解cv2.HoughLines的返回参数

        # 延长直线的长度,保证在整幅图像上绘制直线
        x1 = int(x0 + 2000 * (-b))
        y1 = int(y0 + 2000 * (a))
        x2 = int(x0 - 2000 * (-b))
        y2 = int(y0 - 2000 * (a))

前面讲到, 霍夫直线值仅仅返回两个参数,并不会直接返回直线上的坐标点,我们在选取直线坐标点的时候,需要尽量选取图像外部的点(即负数),这样才会过整幅图像绘制直线。

三、源码(包含注释)

import cv2
import numpy as np
from numpy import mean


# 读取图像以及图像的宽和高
img = cv2.imread('./img.png')
h = img.shape[0]
w = img.shape[1]

# 求取图像的平均灰度值
img_gray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY)
all_gray = []
for i in range(h):
    for j in range(w):
        all_gray.append(img_gray[i, j])
print('图像的平均灰度值:', mean(all_gray))

# Canny算子寻找图像的边缘
image_edge = cv2.Canny(img, 200, 200)

# 寻找霍夫直线
lines = cv2.HoughLines(image_edge, 1, np.pi/180, 180)

# 绘画霍夫直线
if lines is not None:
    for n, line in enumerate(lines):
        # 沿着左上角的原点,作目标直线的垂线得到长度和角度
        rho = line[0][0]
        theta = line[0][1]
        # if np.pi / 3 < theta < np.pi * (3 / 4):
        a = np.cos(theta)
        b = np.sin(theta)
        # 得到目标直线上的点
        x0 = a * rho
        y0 = b * rho

        # 延长直线的长度,保证在整幅图像上绘制直线
        x1 = int(x0 + 2000 * (-b))
        y1 = int(y0 + 2000 * (a))
        x2 = int(x0 - 2000 * (-b))
        y2 = int(y0 - 2000 * (a))

        # 连接两点画直线
        # print((x1, y1), (x2, y2))  # (-148, 993) (335, -947)
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 1)

        # ===============================CAB================================ #
        xDis = x2 - x1  # x的增量
        yDis = y2 - y1  # y的增量
        if (abs(xDis) > abs(yDis)):
            maxstep = abs(xDis)
        else:
            maxstep = abs(yDis)
        xUnitstep = xDis / maxstep  # x每步骤增量
        yUnitstep = yDis / maxstep  # y的每步增量
        x = x1
        y = y1
        average_gray = []
        for k in range(maxstep):
            x = x + xUnitstep
            y = y + yUnitstep
            # print("x: %d, y:%d" % (x, y))
            if 0 < x < h and 0 < y < w:
                # print(img_gray[int(x), int(y)])
                average_gray.append(img[int(x), int(y)])
        print('第霍夫直线的平均灰度值:'.format(n), mean(average_gray))  # 平均115,阴影的边界在125以上,堵料的边界在105左右
        # ================================================================== #

    print('直线的数量:', len(lines))
else:
    print('直线的数量:', 0)

# 可视化图像
cv2.imshow('0', img)
cv2.imshow('1', image_edge)
cv2.waitKey(0)

四、拓展

因项目的需求,需要比对霍夫直线和整幅图像的平均灰度值的大小关系,所以在上面的源码中,我把此项功能加入到其中,希望对你有所帮助。


>>> 如有疑问,欢迎评论区一起探讨。

OpenCV-标准霍夫变换cv::HoughLines

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 

函数原型

void HoughLines( InputArray image, OutputArray lines,
                 double rho, double theta, int threshold,
                 double srn = 0, double stn = 0,
                 double min_theta = 0, double max_theta = CV_PI );

参数说明

  1. InputArray类型的image,输入图像,需为8位的单通道二进制图像。
  2. InputArray类型的lines,调用HoughLines函数后存储了霍夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量(r,t)表示。r为离坐标原点的距离,t为弧度线条旋转角度。
  3. double类型的rho,以像素为单位的距离精度。
  4. double类型的theta,以弧度为单位的角度精度。
  5. int类型的threshold,累加平面的阈值参数,即识别某部分为图中一直线时它在累加平面中必须达到的值。大于阈值的线段才可以被检测通过并返回到结果中。
  6. double类型的srn,默认值0。对于多尺度的霍夫变换,这是第三个参数rho的除数距离。粗略的累加器进步尺寸是rho,而精确的累加器进步尺寸为rho/srn。
  7. double类型的stn,默认值0。对于多尺度的霍夫变换,这是第四个参数theta的除数距离。粗略的累加器进步尺寸是theta,而精确的累加器进步尺寸为theta/srn。
  8. double类型的min_theta,对于标准和多尺度霍夫变换,检查线的最小角度。必须介于 0 和 max_theta 之间。
  9. double类型的max_theta,对于标准和多尺度霍夫变换,检查线的最大角度。必须介于 min_theta 和 CV_PI 之间。

霍夫变换概述

       在图像处理和计算机视觉领域中,如何从当前图像中提取所需要的特征信息是图像识别的关键所在。在许多应用场合中需要快速准确地检测出直线或圆。其中非常有效的一种方法就是应用霍夫变换,这也是图像处理中从图像中识别几何形状的基本方法之一,应用很广。

       霍夫变换作为图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为结果。该方法最早于1962年由PaulHough首次提出,最初的变换是用来检测直线和曲线的,早期要求知道物体边界线的解析方程,但不需要有关区域位置的先验知识。这种方法的突出优点是分割结果的Robustness,即对数据的不完全或噪声不是非常敏感。然而,要获得描述边界的解析表达常常是不可能的。后于1972年由Richard Duda等人推广使用,经典霍夫变换用来检测图像中的直线,后来扩展到任意形状物体的识别,多为圆和椭圆。霍夫变换运用两个坐标空间之间的变换,将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。

霍夫变换原理

       OpenCV中提供了霍夫变换的调用函数,标准霍夫变换和多尺度霍夫变换为HoughLines函数。该函数适用于寻找直线,首先对图像进行边缘检测的处理,获取二值灰度图,再输入至函数中得到直线段集合的数据。

       下面介绍其实现原理:

1)一条直线在图像二维空间中可以通过两个变量表示,既可以是笛卡尔坐标系,也可以是极坐标系。笛卡尔坐标系中由参数斜率m和截距b表示,极坐标系中由参数极径r和极角t表示。

2)采用极坐标系表示直线,有下列关系式:

3)上述直线表达式可以变换为:

4)对于x0和y0而言,可以将通过这个点的一族直线统一定义为:

5)转换为r和t的极坐标系下,x0和y0成了常数系数,改变r和t可以得到一个极坐标系下的曲线,该曲线上的一个点就表示过x0和y0点的一条直线。对不同的x和y可以得到不同的极坐标曲线,如果这些极坐标系曲线汇聚于一点,说明这些不同的x和y都有同一个r0和t0,也就是说在笛卡尔坐标系下,这些不同的x和y都属于同一个直线,该直线的表达式中t就是t0,r就是r0,即实现了直线的识别。

6)以上的说明表明,一般来说,一条直线能够通过在极坐标系寻找交于一点的曲线数量来检测。而越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。我们还可以通过设置直线上点的阈值来定义多少条曲线交于一点,才认定为检测到一条直线。

测试代码

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void main()

	Mat src = imread("test.png");
	Mat mid, dst;
	Canny(src, mid, 100, 200, 3);
	cvtColor(mid, dst, COLOR_GRAY2BGR);
	// 标准霍夫变换,直线检测
	vector<Vec2f>lines;
	HoughLines(mid, lines, 1, CV_PI / 180.0, 200, 0, 0);
	for (size_t i = 0; i < lines.size(); ++i)
	
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(dst, pt1, pt2, Scalar(255, 255, 0), 1, LINE_AA);
	

	imshow("src", src);
	imshow("mid", mid);
	imshow("result", dst);
	waitKey(0);
	system("pause");

测试效果

图1 原图
图2  边缘检测图
图3 直线检测效果图

       上述蓝色的线就是应用霍夫变换找出来的直线,但是该代码所找的直线是无限长直线,不是线段。

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

以上是关于图解 cv2.HoughLines & cv2.line 参数原理的主要内容,如果未能解决你的问题,请参考以下文章

算法图解之快速排序

算法图解

算法算法图解笔记_快速排序

《算法图解》读书笔记 - 快速排序

《算法图解》读书笔记 - 快速排序

20 万字的 C++ 八股文&图解源码,发布!