Bootstrap

OPENCV轮廓

//学习OPENCV,第8章:轮廓
//内存存储器:大小相同的内存块组成的双向链表
//cvCreateImage从内存存储器中分配并释放内存
/*
一个轮廓对应一系列的点,也就是图像中的一条曲线。
在OPENCV中一般用序列来存储轮廓信息。序列中每个元素对应曲线中的一个点的位置。
*/
#include <cv.h>
#include <highgui.h>

//Some defines we left out of the book
#define CVX_RED 	CV_RGB(0xff,0x00,0x00)
#define CVX_GREEN	CV_RGB(0x00,0xff,0x00)
#define CVX_BLUE	CV_RGB(0x00,0x00,0xff)

IplImage* g_image = NULL;
IplImage* g_gray = NULL;
int g_thresh = 100;
CvMemStorage* g_storage = NULL;

void on_trackbar(int);

int main( int argc, char** argv )
{
	//-------------------------------------------------------------------	
	//创建窗口用于显示图像,滑动条用于设置阈值,然后对二值化后的图像进行轮廓提取并绘制
	//当控制参数的滑动条变化时,图像被更新
	if(!(g_image = cvLoadImage("D:\\AI_Proj\\OPENCV\\dog.jpg")))
		return -1;
	cvNamedWindow("src");
	cvShowImage("src",g_image);
	cvNamedWindow("Contours",1);
	cvCreateTrackbar("Threshold","Contours",&g_thresh,255,on_trackbar);
	on_trackbar(0);//回调函数需要显示调用???
	cvReleaseImage(&g_gray);
	cvDestroyWindow("Contours");
	cvReleaseImage(&g_image);
	cvDestroyWindow("src");
	cvWaitKey();
	
	//-------------------------------------------------------------------
	//检测出输入图像轮廓并逐个绘制
	//cvNamedWindow("",1);
	IplImage* img_8uc1 = NULL;
  
	//Changed this a little for safer image loading and help if not
	if(!(img_8uc1 = cvLoadImage("D:\\AI_Proj\\OPENCV\\dog.jpg", CV_LOAD_IMAGE_GRAYSCALE )))
		return -1;
	
	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, //Nc返回找到所有轮廓的个数
							&first_contour,//函数会自动分配该指针,不需要手动分配和释放,指向轮廓树的首地址
							sizeof(CvContour),//对象分配信息
							CV_RETR_LIST);//轮廓类型:检查所有轮廓并保存到表list中
	//显示二值化后的图像轮廓
	cvNamedWindow("img_edge");
	cvShowImage("img_edge",img_edge);
	cvNamedWindow("img_8uc3");
	int n=0,k;
	printf("\n\nHit any key to draw the next contour, ESC to quit\n\n");
	printf("Total Contours Detected: %d\n",Nc);
	//遍历轮廓
	for(CvSeq* c=first_contour;c!=NULL;c=c->h_next) 
	{
		cvCvtColor(img_8uc1,img_8uc3,CV_GRAY2BGR);//在BRG图像中绘制轮廓
		//绘制轮廓P267
		cvDrawContours(img_8uc3,c,CVX_RED,CVX_BLUE,
						0,//maxlevel=0表示与输入轮廓属于同一等级的所有轮廓(实验现象看每次只画一个轮廓)
						2,8);
		printf("Contour #%d\n",n);
		cvShowImage("img_8uc3",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((k = cvWaitKey()&0x7F) == 27)
			break;
		n++;
	}
	printf("Finished all contours. Hit key to finish\n");
	//cvCvtColor(img_8uc1,img_8uc3,CV_GRAY2BGR);
	//cvShowImage("",img_8uc3);
	cvWaitKey(0);
	cvDestroyWindow("img_edge");
	cvDestroyWindow("img_8uc3");
	//cvReleaseImage(&img_8uc1);
	cvReleaseImage(&img_8uc3);
	cvReleaseImage(&img_edge);
	return 0;
}

//通过滑动条回调函数改变二值化阈值,从中检索轮廓,并绘制
void on_trackbar(int) 
{
	//创建图像并开辟内存,将RGB转化为GRAY图像,并二值化分割
	if(g_storage==NULL) 
	{
		g_gray = cvCreateImage(cvGetSize(g_image),8,1);
		g_storage = cvCreateMemStorage(0);
	} 
	else
		//cvReleaseMemStorage释放内存存储器所有空间到系统
		//cvClearMemStorage清空内存存储器。不返还给系统,可以实现重复使用内存存储器中的内存空间
		cvClearMemStorage(g_storage);
		

	CvSeq* contours = 0;
	//将图像转换为8位单通道灰度图
	cvCvtColor(g_image,g_gray,CV_BGR2GRAY);
	//将图像二值化
	cvThreshold(g_gray,g_gray,g_thresh,255,CV_THRESH_BINARY);
	//从二值图像中检索轮廓,并返回检测到的轮廓的个数contours。P259
	cvFindContours(	g_gray,//必须是8位单通道,二值化图像,会修改源图像
					g_storage,//将找到的轮廓存储到此内存
					&contours);//指向轮廓树首地址,无需手动创建或释放指针 
	cvZero(g_gray);
	if(contours != NULL) //用于在图像上绘制外部和内部轮廓
		cvDrawContours(	g_gray,//要绘制轮廓的图像;同其他绘图函数,轮廓是ROI的修剪结果。
						contours,//指向第一个轮廓的指针
						cvScalarAll(255),//外轮廓的颜色
						cvScalarAll(255),//内轮廓的颜色
						1);//画轮廓的最大层数 ,如何处理通过节点树变量连接到一个轮廓上的其他任何轮廓
	cvShowImage("Contours",g_gray);//显示添加轮廓的图像
	
	cvWaitKey();	
}





;