My Vision Tutorials Index
This tutorial assumes the reader:
(1) Has a basic knowledge of Visual C++
(2) Has some familiarity with computer vision concepts
(3) Has read the previous tutorials in this series
The rest of the tutorial is presented as follows:
Important Note!
More information on the topics of these tutorials can be found in this book: Learning OpenCV: Computer Vision with the OpenCV Library
Step 1: Sequences(序列)
In order to work with contours, several other OpenCV functions and data types must be considered(为了轮廓的处理工作, OpenCV一些其他的函数和数据类型必须被考虑). OpenCV uses an entity called memory storage for dynamic objects(OpenCV中使用了一个被称为动态内存存储对象的实体). One type of memory storage is a sequence, which is a linked list of objects(一个内存存储类型是一个序列,它是一个对象的链表). A sequence is created like this: CvSeq* yourvariable = cvCreateSeq(int seq_flags, int header_size, int elem_size, CvMemStorage* storage(创建一个序列是这样的:CvSeq* yourvariable = cvCreateSeq(int seq_flags, int header_size, int elem_size, CvMemStorage* storage). Individual elements in a sequence can be accessed with char* cvGetSeqElem( seq, index )(序列中的单个元素可以通过char* cvGetSeqElem( seq, index )被访问). A sequence can be used as a stack with functions like push, char* cvSeqPush( CvSeq* seq, void* element = NULL) and pop, char* cvSeqPop( CvSeq* seq, void* element = NULL)(一个序列可以作为一个堆栈功能,如推进,用char* cvSeqPush( CvSeq* seq, void* element = NULL)和离去(流出),用char* cvSeqPop( CvSeq* seq, void* element = NULL)). Sequence objects can also be converted to arrays(序列对象也可以转换为数组). Sequences are used for storing contours (序列用于存储轮廓). For more in depth details about the flags for creating sequences and various methods of accessing and manipulating sequence elements, please see the book(对于有关细节更加深入的标志,用于创建序列和序列的元素访问和操纵的各种方法,请参阅本书).
Step 2: Contour Examples(轮廓范例)
Contours at Various Thresholds(在不同阈值下的轮廓)
Contours are sequences of points defining a line/curve in an image(轮廓是图像中确定一条直线/曲线的点序列). Contour matching can be used to classify image objects(轮廓匹配可用于图像对象的分类). The following is a basic example for finding contours at various thresholds(以下是寻找不同阈值轮廓的基本示例). cvThreshold is used to binarize the image, and then the contours are found with int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int headersize = sizeof(CvContour), int mode = CV_RETR_LIST, int method = CV_CHAIN_APPROX_SIMPLE, CvPoint offset = cvPoint(0,0) )( cvThreshold用于二值化图像,然后int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int headersize = sizeof(CvContour), int mode = CV_RETR_LIST, int method = CV_CHAIN_APPROX_SIMPLE, CvPoint offset = cvPoint(0,0) )用于发现轮廓). Then the contours are drawn using void cvDrawContours( CvArr* img, CvSeq* contour, CvScalar external_color, CvScalar hole_color, int max_level, int thickness = 1, int line_type = 8, CvPoint offset = cvPoint(0,0) )(然后用void cvDrawContours( CvArr* img, CvSeq* contour, CvScalar external_color, CvScalar hole_color, int max_level, int thickness = 1, int line_type = 8, CvPoint offset = cvPoint(0,0) )绘制轮廓). A trackbar is used to control the threshold(一个滑块用来控制阈值). Here is the code(以下是代码):
IplImage* g_image = NULL;
IplImage* g_gray = NULL;
int g_thresh = 100;
CvMemStorage* g_storage = NULL;
void on_trackbar(int){
if( g_storage == NULL ){
g_gray = cvCreateImage( cvGetSize( g_image ), 8, 1 );
g_storage = cvCreateMemStorage(0);
} else {
cvClearMemStorage( g_storage );
}
CvSeq* contours = 0;
cvCvtColor( g_image, g_gray, CV_BGR2GRAY );
cvThreshold( g_gray, g_gray, g_thresh, 255, CV_THRESH_BINARY );
cvFindContours( g_gray, g_storage, &contours );
cvZero( g_gray );
if( contours ){
cvDrawContours(
g_gray,
contours,
cvScalarAll(255),
cvScalarAll(255),
100 );
}
cvShowImage( "Contours", g_gray );
}
int _tmain(int argc, _TCHAR* argv[])
{
g_image = cvLoadImage( "MGC.jpg" );
cvNamedWindow( "Contours", 1 );
cvCreateTrackbar( "Threshold", "Contours", &g_thresh, 255, on_trackbar );
on_trackbar(0);
cvWaitKey();
return 0;
}
Finding and Drawing Contours on an Input Image
(在输入图像上找出和绘制轮廓)
This example draws external and internal contours with different colors, and draws them one at a time so that by pressing escape you can cycle through the contours(这个例子用不同颜色绘制外部和内部的轮廓,并且一次绘制它们一个,只有这样,按通过的轮廓逃避你可以骑自行车). Here is the code(以下是代码):
int _tmain(int argc, _TCHAR* argv[])
{
cvNamedWindow( "Contours 2", 1 );
IplImage* img_8uc1 = cvLoadImage( "MGC.jpg", 0 );
IplImage* img_edge = cvCreateImage( cvGetSize(img_8uc1), 8, 1 );
IplImage* img_8uc3 = cvCreateImage( cvGetSize(img_8uc1), 8, 3 );
cvThreshold( img_8uc1, img_edge, 128, 255, CV_THRESH_BINARY );
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* first_contour = NULL;
int Nc = cvFindContours(
img_edge,
storage,
&first_contour,
sizeof(CvContour),
CV_RETR_LIST );
int n=0;
printf( "Total Contours Detected: %d\n", Nc );
CvScalar red = CV_RGB(250,0,0);
CvScalar blue = CV_RGB(0,0,250);
for( CvSeq* c=first_contour; c!=NULL; c=c->h_next ){
cvCvtColor( img_8uc1, img_8uc3, CV_GRAY2BGR );
cvDrawContours(
img_8uc3,
c,
red, // Red
blue, // Blue
1, // Vary max_level and compare results
2,
8 );
printf( "Contour #%dn", n );
cvShowImage( "Contours 2", img_8uc3 );
printf( " %d elements:\n", c->total );
for( int i=0; itotal; ++i ){
CvPoint* p = CV_GET_SEQ_ELEM( CvPoint, c, i );
printf(" (%d,%d)\n", p->x, p->y );
}
cvWaitKey();
n++;
}
printf( "Finished all contours.\n");
cvCvtColor( img_8uc1, img_8uc3, CV_GRAY2BGR );
cvShowImage( "Contours 2", img_8uc3 );
cvWaitKey();
cvDestroyWindow( "Contours 2" );
cvReleaseImage( &img_8uc1 );
cvReleaseImage( &img_8uc3 );
cvReleaseImage( &img_edge );
return 0;
}
Step 3: Other Contour Functions(其他的轮廓功能)
I want to touch on more processing that can be done with contours, please see the text to understand how to implement these functions(我想谈谈更多可用轮廓完成的处理,请看这段文字,了解如何实现这些功能). A contour can be approximated as a polygon with cvApproxPoly()(一个轮廓可以用cvApproxPoly近似地看为为一个多边形). The dominant points can be found from a contour, a dominant point being on that is on a corner essentially, using cvFindDominantPoints()(占主导地位的点可以从一个轮廓发现,一个显着点是在这实质上是在一个角落里,用cvFindDominantPoints()实现).Other characteristic like length and the the bounding box can be measured(其他特征如长度和边框可以被测). Contours can be matched using moments, Hu moments, hierarchical matching, convexity characteristics, and geometrical histograms(轮廓可以通过使用时刻,胡矩,分级匹配,凸性特征,几何直方图来匹配).
Final Words(结束语)
This tutorial's objective was to show how to use sequences, and find contours in images, and assorted functions related to contour matching(本教程的目标是展示如何使用序列,发现在图像的轮廓,以及各种相关的轮廓匹配功能).
Click here to email me.
Click here to return to my Tutorials page.