霍夫变换

  • 在许多应用场合中需要快速准确地检测出直线或者圆。其中一种非常有效的解决问题的方法是霍夫(Hough)变换,其为图像处理中从图像中识别几何形状的基本方法之一
  • 霍夫变换是图像处理中的一种特征提取的技术.
  • 最基本的霍夫变换是从黑白图像中检测直线(线段)
  • 霍夫变换在OpenCV中分为 霍夫线变换霍夫圆变换 两种

霍夫线变换

  • 霍夫线变换是一种用来寻找直线的方法.
  • 在使用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像.
  • OpenCV支持三种不同的霍夫线变换. 分别是:
    标准霍夫变换(Standard Hough Transform,SHT)
    多尺度霍夫变换(Multi-Scale Hough Transform,MSHT)
    累计概率霍夫变换(Progressive Probabilistic Hough Transform ,PPHT)

相关函数学习

  • HoughLines
/*
OpenCV中的霍夫直线检测的函数为HoughLines
改进版本的HoughLinesP函数(统计概论霍夫直线检测)
*/
void HoughLines(
InputArray image,  //输入8-比特、单通道 (二值) 图像
OutputArray lines,  //输出的角度和r长度: lines为输出直线向量,两个元素的向量(ρ,θ)代表一条直线,ρ是从原点(图像的左上角)的距离,θ是直线的角度(单位是弧度),0表示垂直线,π/2表示水平线 
double rho, //与像素相关单位的距离精度
double theta, //弧度测量的角度精度
int threshold, //阈值参数。如果相应的累计值大于 threshold, 则函数返回的这个线段.
double srn=0, double stn=0  //多尺度变换,距离精度 rho 的分母,角度精度 theta 的分母。
);
  • HoughLinesP
// 通过统计概率的霍夫线变换找到线段
void HoughLinesP(
InputArray image,  //输入 8-比特、单通道 (二值) 图像
OutputArray lines, //输出线段的两个端点,保存为(x_1, y_1, x_2, y_2)
double rho, //与象素相关单位的距离精度,((width + height) * 2 + 1) / rho 表示r的空间范围,一般取1
double theta, //弧度测量的角度精度,(CV_PI/theta)表示霍夫空间角度方向的大小
int threshold, //阈值参数。如果相应的累计值大于 threshold, 则函数返回的这个线段.
double minLineLength=0,  //最小的线段长度
double maxLineGap=0  //这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于maxLineGap时,将其合二为一
);

demo学习

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

static void help()
{
    cout << "\nThis program demonstrates line finding with the Hough transform.\n"
            "Usage:\n"
            "./houghlines <image_name>, Default is ./pic1.png\n" << endl;
}

int main(int argc, char** argv)
{
    cv::CommandLineParser parser(argc, argv,
        "{help h||}{@image|./pic1.png|}"
    );
    if (parser.has("help"))
    {
        help();
        return 0;
    }
    string filename = parser.get<string>("@image");
    if (filename.empty())
    {
        help();
        cout << "no image_name provided" << endl;
        return -1;
    }
    Mat src = imread(filename, 0);
    if(src.empty())
    {
        help();
        cout << "can not open " << filename << endl;
        return -1;
    }

    Mat dst, cdst;
    Canny(src, dst, 50, 200, 3);
    cvtColor(dst, cdst, COLOR_GRAY2BGR);

#if 0
    vector<Vec2f> lines;
    HoughLines(dst, lines, 1, CV_PI/180, 100, 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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
#else
    vector<Vec4i> lines;
    HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
    for( size_t i = 0; i < lines.size(); i++ )
    {
        Vec4i l = lines[i];
        line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
    }
#endif
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();

    return 0;
}