【OpenCV】图像变换(四-1)-霍夫变换线段检测

霍夫变换是一种在图像中寻找直线、圆及其他形状的方法。原始的霍夫变化是一种直线变换,即在二值图像中寻找直线的一种相对快速方法,变换可以推广到其他普通的情况,而不仅仅是简单的直线。在这篇博文中,我们先对霍夫变换的线段检测讨论下。

(1)霍夫变换的线段检测理论

如下图所示,在直角坐标系中有一条直线l,原点到该直线的垂直距离是ρ,垂线与X轴的夹角θ,则这条直线是唯一的,且其方程为:

这里写图片描述
【OpenCV】图像变换(四-1)-霍夫变换线段检测_第1张图片

而这条直线用极坐标表示为(ρ,θ),可见直角坐标系中的一条直线对应着极坐标下的一点,这种线到点的变换就是Hough变换。

在直角坐标系中,过任意一点(x0,y0)的直线系,如下图所示,满足
这里写图片描述
其中:
这里写图片描述

【OpenCV】图像变换(四-1)-霍夫变换线段检测_第2张图片

而这些直线在极坐标系中所对应的点(ρ,θ)构成一条正弦曲线,反之,在极坐标系中在这条正弦曲线上的点均对应着直角坐标系中过(x0,y0)的一条直线,如图所示:
【OpenCV】图像变换(四-1)-霍夫变换线段检测_第3张图片

设平面上有若干点,过每点的直线系分别对应于极坐标系上的一条正弦曲线,若这些正弦曲线有共同的交点(ρ’,θ’),如图所示,这些点共线,且这些点对应的直线方程为:
这里写图片描述
【OpenCV】图像变换(四-1)-霍夫变换线段检测_第4张图片

这就是Hough变换检测直线的原理。

在OpenCV中给出了相关的基于霍夫变换的线段检测函数cvHoughLines2(),下面简要介绍下这个函数的各个参数意义。

CvSeq* cvHoughLines2(
    CvArr* image,//输入图像,必须为8位的二值图像
    void* line_storage,//指向保存结果位置的指针
    int method,//CV_HOUGH_STANDARD、PROBABILISTIC等
    double rho,
    double theta,//rho,theta是设置直线的分辨率,单位分别为像素和弧度
    int threshold,//一条直线在累计平面中必须要达到的值
    double param1=0,
    double param2=0
)

上面这个函数返回的结果是一个指向内存块的指针,所以在画出检测到的直线时,要遍历这个序列。下面给出这个程序的示例。

(2)程序示例及运行结果

#include
#include
using namespace std;

int main()
{
    const char *pSrcWindow = "原图";
    const char *pDstWindow = "Hough图";

    IplImage *pSrcImage = cvLoadImage("1.png", CV_LOAD_IMAGE_UNCHANGED);
    IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
    cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
    //通过canny检测得到二值图,因为cvHoughLines2()中第一个参数输入图像必须是8位二值图像
    IplImage *pCannyImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
    cvCanny(pGrayImage, pCannyImage, 30, 90, 3);

    //设置参数数值
    CvMemStorage *line_storage = cvCreateMemStorage();
    double rho = 1;
    double theta = CV_PI / 180;
    int threshold = 50;
    double param1 = 50;
    double param2 = 10;
    //调用函数cvHoughLines2()函数,返回检测到的线段序列
    CvSeq* LineSeq = cvHoughLines2(pCannyImage, line_storage, CV_HOUGH_PROBABILISTIC, rho, theta, threshold, param1, param2);

    //创建输出图像,并将图像从灰度图转换到RGB空间
    IplImage *pDstImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);
    cvCvtColor(pCannyImage, pDstImage, CV_GRAY2BGR);

    //画出检测到的线段,因为在函数cvHoughLines2()返回得到的是一个序列seq,下面其实是这个序列的遍历;
    for (int i = 0; i < LineSeq->total; ++i)
    {
        CvPoint* p = (CvPoint*)cvGetSeqElem(LineSeq, i);
        cvLine(pDstImage, p[0], p[1], CV_RGB(255, 0, 0), 2);
    }

    cvNamedWindow(pSrcWindow, CV_WINDOW_AUTOSIZE);
    cvNamedWindow(pDstWindow, CV_WINDOW_AUTOSIZE);
    cvShowImage(pSrcWindow, pSrcImage);
    cvShowImage(pDstWindow, pDstImage);

    cvWaitKey();

    cvReleaseMemStorage(&line_storage);
    cvReleaseImage(&pSrcImage);
    cvReleaseImage(&pGrayImage);
    cvReleaseImage(&pCannyImage);
    cvReleaseImage(&pDstImage);

    cvDestroyWindow(pSrcWindow);
    cvDestroyWindow(pDstWindow);

    return 0;
}

运行的结果如下:
【OpenCV】图像变换(四-1)-霍夫变换线段检测_第5张图片

你可能感兴趣的:(opencv,霍夫变换,极坐标,直角坐标,序列)