《学习openCV》例程解析 ex_8_3 (轮廓)

/*

效果图:


我本人感觉例程有误,下面是修改后的英文(如:max_level)和例程,
运行时按住除ESC 键以外任意一个按键,可观察到轮廓从下往上的顺序
依次画出。外部轮廓为红色,内部轮廓为蓝色。

*/

/**
In this example, we find contours on an input image and then proceed to draw them 
one by one. This is a good example to play with yourself and see what effects result from 
changing either the contour finding mode (CV_RETR_LIST in the code) or the max_level 
that is used to draw the contours (0 in the code). If you set max_level to a larger number, 
notice that the example code steps through the contours returned by cvFindContours() 
by   means   of  h_next.   Thus,  for  some   topologies   (CV_RETR_TREE, CV_RETR_CCOMP,  etc.),   you 
may see the same contour more than once as you step through. See Example 8-3. 

Example 8-3. Finding and drawing contours on an input image 
*/


#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "stdio.h"

#define CVX_RED CV_RGB(0xff, 0x00, 0x00)
#define CVX_GREEN CV_RGB(0x00, 0xff, 0x00)
#define CVX_BLUE CV_RGB(0x00, 0x00, 0xff)

int main()
{
	IplImage* img_8uc1 = NULL;
	cvNamedWindow("img_contour", CV_WINDOW_AUTOSIZE);

	if (img_8uc1 = cvLoadImage("lena.jpg", 0))		
		//CV_LOAD_IMAGE_GRAYSCALE == 0 加载lena.jpg 灰度图
	{
		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);
		//对灰度图img_8uc1 像进行阈值操作得到二值图像 img_edge

		CvMemStorage* storage = cvCreateMemStorage();
		//创建一个内存储存器 默认为 64K

		CvSeq* first_contour = NULL;
		//创建一个动态序列指针,用其指向第一个存储轮廓单元地址

		int NC = cvFindContours(	
			//cvFindContours从二值图像中检索轮廓,并返回检测到的轮廓的个数
			img_edge,		
			storage,				//存储轮廓元素的储存容器
			&first_contour,			//指向第一个输出轮廓
			sizeof (CvContour),		
			CV_RETR_LIST			//提取所有轮廓,并且放置在 list 中
			);
		
		printf("Total Contours Detected: %d\n", NC);

		cvCvtColor(img_8uc1, img_8uc3, CV_GRAY2BGR);
		//色彩空间转换,将img_8uc1 转换为BGR空间,img_8uc3 为转换后结果
		
		int n = 0;
		//用于下面轮廓的记数
		for (CvSeq* c=first_contour; c!=NULL; c = c->h_next)
		{	//从第一个轮廓开始遍历,直到所有轮廓都遍历结束
			cvDrawContours(
				img_8uc3,	//用于绘制轮廓的图像
				c,			//指向目前轮廓所在地址空间
				CVX_RED,	//外层轮廓颜色
				CVX_BLUE,	//内层轮廓颜色
				0,			//等级为0,绘制单独的轮廓
				1,			//轮廓线条粗细
				8			//线段类型为(8邻接)连接线
				);

			printf("Contour #%d\n", n);
			//输出第 n 个轮廓

			cvShowImage("img_contour", img_8uc3);
			//显示目前已绘制的轮廓图像

			printf("%d elements:\n", c->total);
			//输出构成目前轮廓点的个数

			for (int i=0; i<c->total; i++)
			{
				CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, c, i);
				//查找轮廓序列中索引所指定的点,并返回指向该点的指针
				printf("  (%d, %d)\n", p->x, p->y);
				//输出该点坐标
			}
			
			if (cvWaitKey() == 27)		
				//按下ESC 键退出循环
				break;
			n++;
		}
		printf("Finished all contours. Hit ESC to finish\n");

		while (cvWaitKey() != 27);
		
		cvReleaseImage(&img_edge);
		cvReleaseImage(&img_8uc3);
	}
	cvDestroyWindow("img_contour");
	cvReleaseImage(&img_8uc1);
	return 0;
}


原文地址:https://www.cnblogs.com/zcube/p/4196446.html