opencv 检测直线、线段、圆、矩形

转自:http://blog.csdn.net/byxdaz/archive/2009/12/01/4912136.aspx

 

检测直线:cvHoughLines,cvHoughLines2

检测圆:cvHoughCircles

检测矩形:opencv中没有对应的函数,下面有段代码可以检测矩形,是通过先找直线,然后找到直线平行与垂直的四根线。

 

检测直线代码:

/* This is a standalone program. Pass an image name as a first parameter of the program.

   Switch between standard and probabilistic Hough transform by changing "#if 1" to "#if 0" and back */

#include <cv.h>

#include <highgui.h>

#include <math.h>

 

int main(int argc, char** argv)

{

    const char* filename = argc >= 2 ? argv[1] : "pic1.png";

    IplImage* src = cvLoadImage( filename, 0 );

    IplImage* dst;

    IplImage* color_dst;

    CvMemStorage* storage = cvCreateMemStorage(0);

    CvSeq* lines = 0;

    int i;

 

    if( !src )

        return -1;

   

    dst = cvCreateImage( cvGetSize(src), 8, 1 );

    color_dst = cvCreateImage( cvGetSize(src), 8, 3 );

   

    cvCanny( src, dst, 50, 200, 3 );

    cvCvtColor( dst, color_dst, CV_GRAY2BGR );

#if 0

    lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 100, 0, 0 );

 

    for( i = 0; i < MIN(lines->total,100); i++ )

    {

        float* line = (float*)cvGetSeqElem(lines,i);

        float rho = line[0];

        float theta = line[1];

        CvPoint 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));

        cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, CV_AA, 0 );

    }

#else

    lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 50, 10 );

    for( i = 0; i < lines->total; i++ )

    {

        CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);

        cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 );

    }

#endif

    cvNamedWindow( "Source", 1 );

    cvShowImage( "Source", src );

 

    cvNamedWindow( "Hough", 1 );

    cvShowImage( "Hough", color_dst );

 

    cvWaitKey(0);

 

    return 0;

}

 

 

检测圆代码:

#include <cv.h>

#include <highgui.h>

#include <math.h>

 

int main(int argc, char** argv)

{

    IplImage* img;

    if( argc == 2 && (img=cvLoadImage(argv[1], 1))!= 0)

    {

        IplImage* gray = cvCreateImage( cvGetSize(img), 8, 1 );

        CvMemStorage* storage = cvCreateMemStorage(0);

        cvCvtColor( img, gray, CV_BGR2GRAY );

        cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 ); // smooth it, otherwise a lot of false circles may be detected

        CvSeq* circles = cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/4, 200, 100 );

        int i;

        for( i = 0; i < circles->total; i++ )

        {

             float* p = (float*)cvGetSeqElem( circles, i );

             cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 3, CV_RGB(0,255,0), -1, 8, 0 );

             cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(255,0,0), 3, 8, 0 );

        }

        cvNamedWindow( "circles", 1 );

        cvShowImage( "circles", img );

    }

    return 0;

}

 

 

检测矩形代码:

/*在程序里找寻矩形*/

#ifdef _CH_

#pragma package <opencv>

#endif

 

 #ifndef _EiC

#include "cv.h"

#include "highgui.h"

#include <stdio.h>

#include <math.h>

#include <string.h>

#endif

 

int thresh = 50;

IplImage* img = 0;

IplImage* img0 = 0;

CvMemStorage* storage = 0;

CvPoint pt[4];

const char* wndname = "Square Detection Demo";

 

// helper function:

// finds a cosine of angle between vectors

// from pt0->pt1 and from pt0->pt2

 double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )

{   

    double dx1 = pt1->x - pt0->x;   

    double dy1 = pt1->y - pt0->y;   

    double dx2 = pt2->x - pt0->x;

    double dy2 = pt2->y - pt0->y;

    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);

}

 

// returns sequence of squares detected on the image.

// the sequence is stored in the specified memory storage

CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )

{

    CvSeq* contours;

    int i, c, l, N = 11;

    CvSize sz = cvSize( img->width & -2, img->height & -2 );

    IplImage* timg = cvCloneImage( img ); // make a copy of input image

    IplImage* gray = cvCreateImage( sz, 8, 1 );

    IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );

    IplImage* tgray;

    CvSeq* result;

    double s, t;

    // create empty sequence that will contain points -

    // 4 points per square (the square's vertices)

    CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );

 

    // select the maximum ROI in the image

    // with the width and height divisible by 2

    cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); 

    

    // down-scale and upscale the image to filter out the noise

    cvPyrDown( timg, pyr, 7 );

    cvPyrUp( pyr, timg, 7 );

    tgray = cvCreateImage( sz, 8, 1 );    

 

    // find squares in every color plane of the image

    for( c = 0; c < 3; c++ )

    {    

         // extract the c-th color plane

        cvSetImageCOI( timg, c+1 );

        cvCopy( timg, tgray, 0 ); 

        

       // try several threshold levels   

      for( l = 0; l < N; l++ )    

     {        

         // hack: use Canny instead of zero threshold level.      

        // Canny helps to catch squares with gradient shading      

         if( l == 0 )      

         {         

             // apply Canny. Take the upper threshold from slider 

               // and set the lower to 0 (which forces edges merging)

                 cvCanny( tgray, gray, 0, thresh, 5 );  

              // dilate canny output to remove potential   

             // holes between edge segments 

                cvDilate( gray, gray, 0, 1 );        

          }    

         else  

         {      

             // apply threshold if l!=0:

                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 

               cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); 

           } 

 

         // find contours and store them all as a list

            cvFindContours( gray, storage, &contours, sizeof(CvContour),  

                        CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );  

 

         // test each contour

            while( contours )

            {

                // approximate contour with accuracy proportional

                // to the contour perimeter

                result = cvApproxPoly( contours, sizeof(CvContour), storage,

                    CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );

                // square contours should have 4 vertices after approximation

                // relatively large area (to filter out noisy contours)

                // and be convex.

                // Note: absolute value of an area is used because

                // area may be positive or negative - in accordance with the

                // contour orientation

                if( result->total == 4 &&

                    fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&

                    cvCheckContourConvexity(result) )

                {

                    s = 0;

 

                    for( i = 0; i < 5; i++ )

                    {

                        // find minimum angle between joint 

                       // edges (maximum of cosine)

                        if( i >= 2 )

                        {

                            t = fabs(angle(

                            (CvPoint*)cvGetSeqElem( result, i ),

                            (CvPoint*)cvGetSeqElem( result, i-2 ),

                            (CvPoint*)cvGetSeqElem( result, i-1 )));

                            s = s > t ? s : t;

                        }

                    }

 

                                       

                // if cosines of all angles are small 

                // (all angles are ~90 degree) then write quandrange

                    // vertices to resultant sequence

                     if( s < 0.3 )

                        for( i = 0; i < 4; i++ ) 

                           cvSeqPush( squares, 

                               (CvPoint*)cvGetSeqElem( result, i ));

                }

                // take the next contour 

               contours = contours->h_next;

            }

        }

    }

       

    // release all the temporary images

    cvReleaseImage( &gray );

    cvReleaseImage( &pyr );

    cvReleaseImage( &tgray );

    cvReleaseImage( &timg );

 

    return squares;

}

 

  // the function draws all the squares in the image

void drawSquares( IplImage* img, CvSeq* squares )

{   

    CvSeqReader reader;

    IplImage* cpy = cvCloneImage( img );

    int i;

        // initialize reader of the sequence

    cvStartReadSeq( squares, &reader, 0 );

        // read 4 sequence elements at a time (all vertices of a square)

    for( i = 0; i < squares->total; i += 4 )

    {

        CvPoint* rect = pt;

        int count = 4;

 

        // read 4 vertices

        memcpy( pt, reader.ptr, squares->elem_size );

        CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

        memcpy( pt + 1, reader.ptr, squares->elem_size );

        CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

        memcpy( pt + 2, reader.ptr, squares->elem_size );

        CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

        memcpy( pt + 3, reader.ptr, squares->elem_size );

        CV_NEXT_SEQ_ELEM( squares->elem_size, reader );

 

        // draw the square as a closed polyline

         cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );

    }

 

   // show the resultant image

    cvShowImage( wndname, cpy );

    cvReleaseImage( &cpy );

 

 void on_trackbar( int a )

{

    if( img )

        drawSquares( img, findSquares4( img, storage ) );

}

char* names[] = { "pic1.png", "pic2.png", "pic3.png",

                  "pic4.png", "pic5.png", "pic6.png", 0 };

 

 int main(int argc, char** argv)

{

    int i, c;

    // create memory storage that will contain all the dynamic data

    storage = cvCreateMemStorage(0);

     for( i = 0; names[i] != 0; i++ )

    {

        // load i-th image

        img0 = cvLoadImage( names[i], 1 );

        if( !img0 )

        {

            printf("Couldn't load %s/n", names[i] );

            continue;

        }

        img = cvCloneImage( img0 );

 

        // create window and a trackbar (slider) with parent "image" and set callback

        // (the slider regulates upper threshold, passed to Canny edge detector)

         cvNamedWindow( wndname, 1 );

        cvCreateTrackbar( "canny thresh", wndname, &thresh, 1000, on_trackbar );

 

        // force the image processing

        on_trackbar(0);

        // wait for key.

        // Also the function cvWaitKey takes care of event processing

        c = cvWaitKey(0);

        // release both images

        cvReleaseImage( &img );

        cvReleaseImage( &img0 );

        // clear memory storage - reset free space position

        cvClearMemStorage( storage );

        if( c == 27 )

            break;

    } 

       cvDestroyWindow( wndname ); 

       return 0;

}

 #ifdef _EiC

main(1,"squares.c");

#endif

其它参考博客:

1、http://blog.csdn.net/superdont/article/details/6664254

2、http://hi.baidu.com/%CE%C4%BF%A1%B5%C4%CF%A3%CD%FB/blog/item/3a5cb2079158b304738b65f2.html

#include <cv.h>
#include <highgui.h>
#include <math.h>

int main()
{
    IplImage* src;
if( (src=cvLoadImage("5.bmp", 1)) != 0)
    {
        IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
        IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
        CvMemStorage* storage = cvCreateMemStorage(0);//存储检测到线段,当然可以是N*1的矩阵数列,如果

实际的直线数量多余N,那么最大可能数目的线段被返回
        CvSeq* lines = 0;
        int i;
IplImage* src1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);

cvCvtColor(src, src1, CV_BGR2GRAY); //把src转换成灰度图像保存在src1中,注意进行边缘检测一定要

换成灰度图
        cvCanny( src1, dst, 50, 200, 3 );//参数50,200的灰度变换

        cvCvtColor( dst, color_dst, CV_GRAY2BGR );
#if 1
        lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 150, 0, 0 );//标准霍夫变

换后两个参数为0,由于line_storage是内存空间,所以返回一个CvSeq序列结构的指针

        for( i = 0; i < lines->total; i++ )
        {
            float* line = (float*)cvGetSeqElem(lines,i);//用GetSeqElem得到直线
            float rho = line[0];
            float theta = line[1];//对于SHT和MSHT(标准变换)这里line[0],line[1]是rho(与像素相关单位的距

离精度)和theta(弧度测量的角度精度)
            CvPoint pt1, pt2;
            double a = cos(theta), b = sin(theta);
            if( fabs(a) < 0.001 )
            {
                pt1.x = pt2.x = cvRound(rho);
                pt1.y = 0;
                pt2.y = color_dst->height;
            }
            else if( fabs(b) < 0.001 )
            {
                pt1.y = pt2.y = cvRound(rho);
                pt1.x = 0;
                pt2.x = color_dst->width;
            }
            else
            {
                pt1.x = 0;
                pt1.y = cvRound(rho/b);
                pt2.x = cvRound(rho/a);
                pt2.y = 0;
            }
            cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
        }
#else
        lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 10 );
        for( i = 0; i < lines->total; i++ )
        {
            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
            cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );
        }
#endif
        cvNamedWindow( "Source", 1 );
        cvShowImage( "Source", src );

        cvNamedWindow( "Hough", 1 );
        cvShowImage( "Hough", color_dst );

        cvWaitKey(0);
    }
}

line_storage
检测到的线段存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回),或者是包含线段参数的特殊类型(见下面)的具有单行/单列的矩阵(CvMat*)。矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的线段。如果 line_storage 是矩阵,而实际线段的数目超过矩阵尺寸,那么最大可能数目的线段被返回(线段没有按照长度、可信度或其它指标排序).
method
Hough 变换变量,是下面变量的其中之一:
CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是直线与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。因此,矩阵类型必须是 CV_32FC2 type.
CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高). 它返回线段分割而不是整个线段。每个分割用起点和终点来表示,所以矩阵(或创建的序列)类型是 CV_32SC4.
CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。
rho
与象素相关单位的距离精度
theta
弧度测量的角度精度
threshold
阈值参数。如果相应的累计值大于 threshold, 则函数返回的这个线段.
param1
第一个方法相关的参数:
对传统 Hough 变换,不使用(0).
对概率 Hough 变换,它是最小线段长度.
对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).
param2
第二个方法相关参数:
对传统 Hough 变换,不使用 (0).
对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时,将其合二为一。
对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).
函数 cvHoughLines2 实现了用于线段检测的不同 Hough 变换方法. Example. 用 Hough transform 检测线段

3、http://www.opencv.org.cn/index.php/Hough%E7%BA%BF%E6%AE%B5%E6%A3%80%E6%B5%8B

你可能感兴趣的:(opencv 检测直线、线段、圆、矩形)