#include "cv.h"
#include "highgui.h"
#include <iostream>
using namespace std;
int slider_pos=23;//阈值
IplImage *image02 =0,*image03 = 0,*image04 = 0;
void process_image(int h);
int main(int argc ,char **argv)
{
const char *filename ="D:\\test\\18.jpg";
cout<<slider_pos<<" ";
if ((image03 = cvLoadImage(filename,0))==0)//读入图像为灰度图像
{
return -1;
}
image02 = cvCloneImage(image03);
image04 = cvCloneImage(image03);
cvNamedWindow("Source",1);
cvNamedWindow("Result",1);
cvShowImage("Source",image03);
cvCreateTrackbar("Threshold","Result",&slider_pos,255,process_image);
process_image(0);
cvWaitKey(0);
cvSaveImage("1.jpg",image04);
cvReleaseImage(&image02);
cvReleaseImage(&image03);
cvDestroyWindow("Source");
cvDestroyWindow("Result");
return 0;
}
// 删除小面积图形
IplImage* bwareaopen(IplImage *img, int areaThreshold)
{
CvSeq* contour = NULL;
double tmparea = 0.0;
CvMemStorage* storage = cvCreateMemStorage(0);
// IplImage* img= cvLoadImage(dlg.GetPathName(),CV_LOAD_IMAGE_ANYCOLOR);
IplImage* img_Clone=cvCloneImage(img);
// 访问二值图像每个点的值
uchar *pp;
//------------搜索二值图中的轮廓,并从轮廓树中删除面积小于某个阈值minarea的轮廓-------------//
CvScalar color = cvScalar(255,0,0);//CV_RGB(128,0,0);
CvContourScanner scanner = NULL;
scanner = cvStartFindContours(img,storage,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));
// 开始遍历轮廓树
CvRect rect;
while (contour=cvFindNextContour(scanner))
{
tmparea = fabs(cvContourArea(contour));
rect = cvBoundingRect(contour,0);
if (tmparea < areaThreshold)
{
// 当连通域的中心点为黑色时,而且面积较小则用白色进行填充
pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2);
if (pp[0]==255)
{
for(int y = rect.y;y<rect.y+rect.height;y++)
{
for(int x =rect.x;x<rect.x+rect.width;x++)
{
pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*y+x);
if (pp[0]==255)
{
pp[0]=0;
}
}
}
}
}
}
return img_Clone;
}
// 对图像进行闭操作
IplImage* imclose(IplImage* img)
{
// 创建5*5结构元素等同于strel('disk',2)的效果
int mask[25]={0, 0, 1, 0, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0,
0, 0, 1, 0, 0};
IplConvKernel* element=cvCreateStructuringElementEx( 5, 5, 0, 0,CV_SHAPE_CUSTOM, mask);
// 先膨胀
cvDilate(img,img,element,1);
// 后腐蚀
cvErode(img,img,element,1);
return img;
}
// 对图像空洞进行填充
IplImage* imfill(IplImage* img)
{
CvScalar white = CV_RGB( 255, 255, 255 );
IplImage* dst = cvCreateImage( cvGetSize(img), 8, 3);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvFindContours(img, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
cvZero( dst );
for( ; contour != 0; contour = contour->h_next )
{
cvDrawContours( dst, contour, white, white, 0, CV_FILLED);
}
IplImage* bin_imgFilled = cvCreateImage(cvGetSize(img), 8, 1);
cvInRangeS(dst, white, white, bin_imgFilled);
return bin_imgFilled;
}
//这个函数寻找出轮廓、用椭圆拟合画出
void process_image(int h)
{
CvMemStorage *stor;
CvSeq *cont;
CvBox2D32f *box;
CvPoint *PointArray;
CvPoint2D32f *PointArray2D32f;
stor = cvCreateMemStorage(0);
cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);
cvThreshold(image03,image02,slider_pos,255,CV_THRESH_BINARY);
// 删除小面积
bwareaopen(image02,100);
// 闭操作
imclose(image02);
// 填充
imfill(image02);
cvFindContours(image02,stor,&cont,sizeof(CvContour),
CV_RETR_LIST,CV_CHAIN_APPROX_NONE,cvPoint(0,0));
cvZero(image02);
cvZero(image04);
//绘制所有轮廓并用椭圆拟合
for (;cont;cont = cont ->h_next)
{
int i;
int count= cont->total;//轮廓个数
CvPoint center;
CvSize size;
/*个数必须大于6,这是cvFitEllipse_32f的要求*/
if (count<6)
{
continue;
}
//分配内存给点集
PointArray = (CvPoint *)malloc(count*sizeof(CvPoint));
PointArray2D32f = (CvPoint2D32f*)malloc(count*sizeof(CvPoint2D32f));
//分配内存给椭圆数据
box = (CvBox2D32f *)malloc(sizeof(CvBox2D32f));
//得到点集(这个方法值得借鉴)
cvCvtSeqToArray(cont,PointArray,CV_WHOLE_SEQ);
//将CvPoint点集转化为CvBox2D32f集合
for (i=0;i<count;i++)
{
PointArray2D32f[i].x=(float)PointArray[i].x;
PointArray2D32f[i].y=(float)PointArray[i].y;
}
//拟合当前轮廓
cvFitEllipse(PointArray2D32f,count,box);
double c=sqrt((box->size.height)*(box->size.height)/4-(box->size.width)*(box->size.width)/4);
double lxl=2*c/box->size.height;
if(box->size.height>50 || box->size.width>50){
cout<<"离心率:"<<lxl<<" ";
std::cout<<box->size.height<<" ";
std::cout<<box->size.width<<" ";
std::cout<<box->size.height/box->size.width<<endl;}
//绘制当前轮廓
cvDrawContours(image04,cont,CV_RGB(255,255,255),CV_RGB(255,255,255),
0,1,8,cvPoint(0,0));
//将椭圆数据从浮点转化为整数表示
center.x = cvRound(box->center.x);
center.y = cvRound(box->center.y);
size.width = cvRound(box->size.width*0.5);
size.height = cvRound(box->size.height*0.5);
box->angle = -box->angle;
//画椭圆
cvEllipse(image04,center,size,box->angle,0,360,CV_RGB(0,0,255),1,CV_AA,0);
free(PointArray);
free(PointArray2D32f);
free(box);
}
cvShowImage("Result",image04);
}