【opencv+C++】在图像中找四边形
2014-11-15 14:02
393 查看
/* 这个程序的基本思想是:对输入的图像进行滤波去掉噪音,然后进行canny边缘检测,之后进行膨胀,然后寻找轮廓,对轮廓进行多边形的逼近,检测多边形的点数是否是4而且各个角的的余弦是否是小于某个值,程序中认为是0.3,然后就判断该多边形是四边形,之后根据这四个点画出该图像。 ps:我对程序中余弦定理的使用 感觉公式用错了 */ #include "stdafx.h" #include "cv.h" #include "highgui.h" #include <stdio.h> #include <math.h> #include <string.h> 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; //1e-10就是“aeb”的形式,表示a乘以10的b次方。 //其中b必须是整数,a可以是小数。 //?余弦定理CosB=(a^2+c^2-b^2)/2ac??所以这里的计算似乎有问题 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-s 4000 cale and upscale the image to filter out the noise //使用gaussian金字塔分解对输入图像向下采样,首先对它输入的图像用指定滤波器 //进行卷积,然后通过拒绝偶数的行与列来下采样 cvPyrDown( timg, pyr, 7 ); //函数 cvPyrUp 使用Gaussian 金字塔分解对输入图像向上采样。首先通过在图像中插入 0 偶数行和偶数列,然后对得到的图像用指定的滤波器进行高斯卷积,其中滤波器乘以4做插值。所以输出图像是输入图像的 4 倍大小。 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 基于给定的值设置感兴趣的通道。值 0 意味着所有的通道都被选定, 1 意味着第一个通道被选定等等。 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,60, 180, 3 ); // 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 ); cvThreshold( tgray, gray, 50, 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 //cvContourArea 计算整个轮廓或部分轮廓的面积 //cvCheckContourConvexity测试轮廓的凸性 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[] = { "E:\\1.jpg", "E:\\2.jpg", "E:\\3.jpg", "E:\\4.jpg", "E:\\5.jpg", 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,0 ); 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; }
相关文章推荐
- OpenCV3_C++_DrawRect()在图像上画四边形 实例
- 【opencv+C++】在图像中找四边形
- 基于opencv和c++的图像处理:直方图均衡化
- OpenCV —图像像素操作(C++结构)
- OpenCV(C++接口)学习笔记2-像素级的图像操作
- 【开发日记】C#调用C++图像处理算法(opencv)
- 【OpenCV】C++如何使RGB图像变为灰度图像
- Symbian c++调用opencv库进行图像处理
- OpenCV(C++版)图像读取,创建,复制,保存,显示
- OpenCV学习C++接口:图像锐化
- OpenCV学习C++接口:图像锐化
- 利用opencv2和c++实现视频与图像的互相转换
- OpenCV —图像像素操作(C++结构)
- 【第五课:C++和opencv】腐蚀处理图像
- 【第四课:C++和opencv】图像反转
- OpenCV(C++接口)学习笔记1-图像的读取、显示、保存
- 基于opencv和c++的图像处理:直方图匹配
- 【第三课:C++和opencv】图像反转
- 【第七课:C++和opencv】图像的膨胀+控制条
- C++图像辅助工具包Eigen入门代码学习(很好的配合Opencv)