使用OpenCV也有一段时间了,中间遇到了不少问题。一般都是到网络上找答案或者自己试验,现在把这些经验好好整理下,方便自己查找也方便同行参考。

最新更新日期:2009.09.26

一、轮廓(Contour)

1.cvDrawContours()可以填充轮廓内部。

cvDrawContours(gray, contour,cvScalar(255,255,255,0),cvScalar(255,255,255,0),0,CV_FILLED );//用黑色填充轮廓内部

2.得到所有轮廓中面积最大的一个

CvSeq *GetAreaMaxContour(CvSeq *contour)
 {//在给定的contour中找到面积最大的一个轮廓,并返回指向该轮廓的指针
  double contour_area_temp=0,contour_area_max=0;
  CvSeq * area_max_contour = 0 ;//指向面积最大的轮廓
  CvSeq* c=0;
  //printf( "Total Contours Detected: %d/n", Nc );
  for(c=contour; c!=NULL; c=c->h_next )
  {//寻找面积最大的轮廓,即循环结束时的area_max_contour
   contour_area_temp = fabs(cvContourArea( c, CV_WHOLE_SEQ )); //获取当前轮廓面积
   if( contour_area_temp > contour_area_max )
   {
    contour_area_max = contour_area_temp; //找到面积最大的轮廓
    area_max_contour = c;//记录面积最大的轮廓
   }
  }
  return area_max_contour;
 }

二、其他

1. 图像旋转

void   RotateImage(IplImage *src,IplImage *dst,CvPoint center,float angle,float factor)
{//以点center为旋转中心,对src旋转angle度并缩放factor倍。
	float m[6];
	CvMat mat=cvMat(2,3,CV_32FC1,m);
	m[0] = (float)(factor*cos(-angle*CV_PI/180.));
	m[1] = (float)(factor*sin(-angle*CV_PI/180.));
	m[2] = center.x;
	m[3] = -m[1];
	m[4] = m[0];
	m[5] = center.y;
	cvSetZero(dst);
	cvGetQuadrangleSubPix(src,dst,&mat);
}

2.把轮廓包括的区域摆正

CvBox2D RegionRotate(IplImage *src,IplImage *dst,CvSeq *contour)
{//传进来一个contour,然后计算它的最小包围矩形minRect,再把原图以包围矩形中心为旋转中心旋转minRect.angle°,得到调正的图像。
	//dst 是通过cvClone()src得到的
	CvMat *mat_contour = cvCreateMat(1,contour->total,CV_32FC2);//双通道
	CvPoint2D32f *ptr_mat=(CvPoint2D32f*)(mat_contour->data.ptr);
	for (int i=0;i!=contour->total;++i)
	{
		CvPoint *ptr_seq=(CvPoint*)(cvGetSeqElem(contour,i));
		*ptr_mat=cvPointTo32f(*ptr_seq);//显示把CvPoint转换成CvPoint2D32F
		ptr_mat++;
	}//把轮廓变成矩阵
	CvBox2D minRect = cvMinAreaRect2(mat_contour);//得到最小包围矩形
	//CvMat *rot = cvCreateMat(2,3,CV_32FC1);
	//cv2DRotationMatrix(cvPoint2D32f(src->width*0.5f,src->height*0.5f),minRect.angle,0.6,rot);//计算得到旋转矩阵----这里计算得到的矩阵不能使图像变换到想要的旋转结果
	float m[6];
	CvMat mat=cvMat(2,3,CV_32FC1,m);
	float factor=1.0;//缩放
	float angle = -minRect.angle;
	float w=0,h=0;
	w=minRect.center.x; h=minRect.center.y;
	RotateImage(src,dst,cvPoint(w,h),angle,factor);
	//cvEllipseBox(dst,minRect,cvScalar(0,0,255));
	cvReleaseMat(&mat_contour);
	return minRect;//返回最佳包围盒
}

3、cvGetMat()

CvMat* cvGetMat( const CvArr* arr, CvMat* header, int* coi=NULL, int allowND=0 );

可以从一个IplImage *arr得到CvMat *matFromImage.但只是把原来图像的IplImage头变成了CvMat头,数据体部分并没有复制,所以如果此时Release了arr,则再访问matFromImage就会出现错误。

另外第二个参数是临时变量,声明一个CvMat型的就可以了。

CvMat tempMat,*matFromImg;
matFromImg = cvGetMat(Ibin,&tempMat);//temMat是临时变量

4、判断矩阵的数据类型

int type=CV_MAT_TYPE(mat->type);//CvMat *mat
switch (type)
{
	case CV_8SC1 :
	case CV_8UC1 : ... ; break;
	case CV_32SC1: ... ; break;
	case CV_32FC1: ... ; break;
	case CV_64FC1: ... ; break;
	case CV_32FC2: ... ; break;
	default:break;
}

5、cvSaveImage(filename,image);

其中如果filename是一个路径,而路径中有一个不存在的文件夹,那么该函数就会报错。也就是该函数不会自动创建文件夹。

6、之前用OpenCV做的一个程序出现了内存泄露的问题。于是找各种方法解决。首先发现OpenCV公布了1.2版,changelog里提到更新了内存管理部分,所以打算用1.2版修改原来的程序;另外找到了一篇关于OpenCV内存泄露的博客,指出了几种可能出现泄漏的情况,所以准备检查自己写的那部份是不是有问题。

2009.09.26

7、1.2版的OpenCV中,cvLoadImage()貌似不支持中文文件路径!1.1下面写的程序,文件路径里包含中文没问题,换到1.2下就加载不上图像,然后换个不包含中文的路径发现可以了!!!!囧!

2009.11.21

cvCreateHist()生成的直方图在没有经过cvCalcHist()之前内部数据均默认为0!




使用OpenCV也有一段时间了,中间遇到了不少问题。一般都是到网络上找答案或者自己试验,现在把这些经验好好整理下,方便自己查找也方便同行参考。

最新更新日期:2009.09.26

一、轮廓(Contour)

1.cvDrawContours()可以填充轮廓内部。

cvDrawContours(gray, contour,cvScalar(255,255,255,0),cvScalar(255,255,255,0),0,CV_FILLED );//用黑色填充轮廓内部

2.得到所有轮廓中面积最大的一个

CvSeq *GetAreaMaxContour(CvSeq *contour)
 {//在给定的contour中找到面积最大的一个轮廓,并返回指向该轮廓的指针
  double contour_area_temp=0,contour_area_max=0;
  CvSeq * area_max_contour = 0 ;//指向面积最大的轮廓
  CvSeq* c=0;
  //printf( "Total Contours Detected: %d/n", Nc );
  for(c=contour; c!=NULL; c=c->h_next )
  {//寻找面积最大的轮廓,即循环结束时的area_max_contour
   contour_area_temp = fabs(cvContourArea( c, CV_WHOLE_SEQ )); //获取当前轮廓面积
   if( contour_area_temp > contour_area_max )
   {
    contour_area_max = contour_area_temp; //找到面积最大的轮廓
    area_max_contour = c;//记录面积最大的轮廓
   }
  }
  return area_max_contour;
 }

二、其他

1. 图像旋转

void   RotateImage(IplImage *src,IplImage *dst,CvPoint center,float angle,float factor)
{//以点center为旋转中心,对src旋转angle度并缩放factor倍。
	float m[6];
	CvMat mat=cvMat(2,3,CV_32FC1,m);
	m[0] = (float)(factor*cos(-angle*CV_PI/180.));
	m[1] = (float)(factor*sin(-angle*CV_PI/180.));
	m[2] = center.x;
	m[3] = -m[1];
	m[4] = m[0];
	m[5] = center.y;
	cvSetZero(dst);
	cvGetQuadrangleSubPix(src,dst,&mat);
}

2.把轮廓包括的区域摆正

CvBox2D RegionRotate(IplImage *src,IplImage *dst,CvSeq *contour)
{//传进来一个contour,然后计算它的最小包围矩形minRect,再把原图以包围矩形中心为旋转中心旋转minRect.angle°,得到调正的图像。
	//dst 是通过cvClone()src得到的
	CvMat *mat_contour = cvCreateMat(1,contour->total,CV_32FC2);//双通道
	CvPoint2D32f *ptr_mat=(CvPoint2D32f*)(mat_contour->data.ptr);
	for (int i=0;i!=contour->total;++i)
	{
		CvPoint *ptr_seq=(CvPoint*)(cvGetSeqElem(contour,i));
		*ptr_mat=cvPointTo32f(*ptr_seq);//显示把CvPoint转换成CvPoint2D32F
		ptr_mat++;
	}//把轮廓变成矩阵
	CvBox2D minRect = cvMinAreaRect2(mat_contour);//得到最小包围矩形
	//CvMat *rot = cvCreateMat(2,3,CV_32FC1);
	//cv2DRotationMatrix(cvPoint2D32f(src->width*0.5f,src->height*0.5f),minRect.angle,0.6,rot);//计算得到旋转矩阵----这里计算得到的矩阵不能使图像变换到想要的旋转结果
	float m[6];
	CvMat mat=cvMat(2,3,CV_32FC1,m);
	float factor=1.0;//缩放
	float angle = -minRect.angle;
	float w=0,h=0;
	w=minRect.center.x; h=minRect.center.y;
	RotateImage(src,dst,cvPoint(w,h),angle,factor);
	//cvEllipseBox(dst,minRect,cvScalar(0,0,255));
	cvReleaseMat(&mat_contour);
	return minRect;//返回最佳包围盒
}

3、cvGetMat()

CvMat* cvGetMat( const CvArr* arr, CvMat* header, int* coi=NULL, int allowND=0 );

可以从一个IplImage *arr得到CvMat *matFromImage.但只是把原来图像的IplImage头变成了CvMat头,数据体部分并没有复制,所以如果此时Release了arr,则再访问matFromImage就会出现错误。

另外第二个参数是临时变量,声明一个CvMat型的就可以了。

CvMat tempMat,*matFromImg;
matFromImg = cvGetMat(Ibin,&tempMat);//temMat是临时变量

4、判断矩阵的数据类型

int type=CV_MAT_TYPE(mat->type);//CvMat *mat
switch (type)
{
	case CV_8SC1 :
	case CV_8UC1 : ... ; break;
	case CV_32SC1: ... ; break;
	case CV_32FC1: ... ; break;
	case CV_64FC1: ... ; break;
	case CV_32FC2: ... ; break;
	default:break;
}

5、cvSaveImage(filename,image);

其中如果filename是一个路径,而路径中有一个不存在的文件夹,那么该函数就会报错。也就是该函数不会自动创建文件夹。

6、之前用OpenCV做的一个程序出现了内存泄露的问题。于是找各种方法解决。首先发现OpenCV公布了1.2版,changelog里提到更新了内存管理部分,所以打算用1.2版修改原来的程序;另外找到了一篇关于OpenCV内存泄露的博客,指出了几种可能出现泄漏的情况,所以准备检查自己写的那部份是不是有问题。

2009.09.26

7、1.2版的OpenCV中,cvLoadImage()貌似不支持中文文件路径!1.1下面写的程序,文件路径里包含中文没问题,换到1.2下就加载不上图像,然后换个不包含中文的路径发现可以了!!!!囧!

2009.11.21

cvCreateHist()生成的直方图在没有经过cvCalcHist()之前内部数据均默认为0!