www.pudn.com > WBImageAnalysis.rar > ObjectRecognition.cpp


#include ".\objectrecognition.h" 
#include "cv.h" 
#include "cxcore.h" 
#include "highgui.h" 
#include "math.h" 
 
struct SAccumulatorElem 
{ 
  int totalpoints; 
  int* xpos; 
  int* ypos; 
  int* pos; 
  double EllipseParams[5]; 
}; 
 
struct SEllipseParams 
{ 
	double x0; 
	double y0; 
	double angle; 
	double a; 
	double b; 
}; 
 
CObjectRecognition::CObjectRecognition(void) 
{ 
	m_iThresh1=10; 
	m_iThresh2=200; 
} 
 
CObjectRecognition::~CObjectRecognition(void) 
{ 
} 
 
/*----FindLine------识别图像中的直线--------------------- 
 
src:     待识别的图像 
返回:    直线(长度、角度)or 直线(两端点的坐标) 
 
---------------------------------------------------------*/ 
CvSeq* CObjectRecognition::FindLine(IplImage* src) 
{ 
    int i;    
	 
	//应先将src转化为灰度图像 
	IplImage* img=cvCreateImage(cvGetSize(src),8,1); 
    if(src->nChannels==3)  cvCvtColor(src,img,CV_RGB2GRAY); 
	else img=cvCloneImage(src); 
	 
	//create a new image with 8 bits,one channel 
	IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 ); 
    
    //create a new image with 8 bits,three channels 
	IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 ); 
     
	//用于存储识别出来的直线 
	CvMemStorage* storage = cvCreateMemStorage(0); 
    CvSeq* lines = 0; 
     
	cvCanny(img, dst, m_iThresh1, m_iThresh2, 3);//将图像二值化 
    cvCvtColor( dst, color_dst, CV_GRAY2BGR ); //将所得到的灰度图像转化为BGR格式,为了能在其上画出有颜色的直线 
 
    //检测线段,将结果存储到storage中 
	lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 100, 0, 0 ); 
 
    //将查找到的直线画出来——standard方法 
	/*for( i = 0; i < MIN(lines->total,100); i++ ) 
    { 
        float* line = (float*)cvGetSeqElem(lines,i); 
         
		float rho = line[0]; 
        float theta = line[1]; 
         
		CvPoint pt1, pt2; 
         
		double a = cos(theta), b = sin(theta); 
        double x0 = a*rho, y0 = b*rho; 
        pt1.x = cvRound(x0 + 1000*(-b)); 
        pt1.y = cvRound(y0 + 1000*(a)); 
        pt2.x = cvRound(x0 - 1000*(-b)); 
        pt2.y = cvRound(y0 - 1000*(a)); 
         
		cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 ); 
     } 
    */ 
	//采用概率方法——probabilistic方法 
	lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 10 ); 
    for( i = 0; i < lines->total; i++ ) 
    { 
        CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); 
        cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 ); 
    } 
	 
    cvNamedWindow( "LINE", 1 ); 
    cvShowImage( "LINE", color_dst ); 
 
    cvWaitKey(0); 
	cvReleaseImage(&img); 
	cvReleaseImage(&dst); 
	cvReleaseImage(&color_dst); 
	return lines; 
} 
/*----FindSquare------识别图像中的矩形--------------------- 
 
src:     待识别的图像 
返回:    四边形的端点序列 
 
---------------------------------------------------------*/ 
CvSeq* CObjectRecognition::FindSquare(IplImage* src) 
{ 
	CvSeq* contours; 
    int i, c, l, N = 11; 
 
	//将图像的尺寸变为偶数 
    CvSize sz = cvSize( src->width & -2, src->height & -2 ); 
 
    //拷贝源图像 
    IplImage* timg = cvCloneImage(src); 
	//创建灰度图像,单通道,大小为原图像大小(近似) 
	IplImage* gray = cvCreateImage(sz,IPL_DEPTH_8U,1);  
	//创建一个三通道彩色图像,大小为原图像的1/2*1/2,这主要是用于后面的图像下采样和上采样去噪; 
    IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2),IPL_DEPTH_8U,3); 
    IplImage* tgray; 
     
	//存储所识别出的图像中的矩形 
	CvMemStorage* storage = cvCreateMemStorage(0); 
	CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); 
     
    // select the maximum ROI in the image 
    // with the width and height divisible by 2 
	//选定图像的感兴趣区域 
    cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); 
     
	//图像的下采样和上采样 
    cvPyrDown( timg, pyr, 7 ); 
    cvPyrUp( pyr, timg, 7 ); 
    tgray = cvCreateImage( sz,IPL_DEPTH_8U, 1 ); 
	 
	//在每一个颜色通道中查找矩形 
    for( c = 0; c < 3; c++ ) 
    { 
        // extract the c-th color plane 
        cvSetImageCOI( timg, c+1 ); 
        cvCopy( timg, tgray, 0 ); 
         
        // try several threshold levels 
        for( l = 0; l < N; l++ ) 
        { 
            // hack: use Canny instead of zero threshold level. 
            // Canny helps to catch squares with gradient shading 	 
            if( l == 0 ) 
            { 
                // apply Canny. Take the upper threshold from slider 
                // and set the lower to 0 (which forces edges merging)  
                cvCanny(tgray,gray,200,250,5); 
                // dilate canny output to remove potential 
                // holes between edge segments  
                cvDilate( gray, gray, 0, 1 ); 
            } 
            else 
            { 
                // apply threshold if l!=0: 
                // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 
                cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); 
			} 
             
            // find contours and store them all as a list 
            cvFindContours( gray, storage, &contours, sizeof(CvContour), 
                CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); 
             
            // test each contour 
            while( contours ) 
            { 
                // approximate contour with accuracy proportional 
                // to the contour perimeter 
               	CvSeq* result = cvApproxPoly( contours, sizeof(CvContour), storage, 
                CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); 
                // square contours should have 4 vertices after approximation 
                // relatively large area (to filter out noisy contours) 
                // and be convex. 
                // Note: absolute value of an area is used because 
                // area may be positive or negative - in accordance with the 
                // contour orientation 
                if( result->total == 4 && 
                    fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 && 
                    cvCheckContourConvexity(result) ) 
                { 
                    double s = 0, t; 
                     
                    for( i = 0; i < 5; i++ ) 
                    { 
                        // find minimum angle between joint 
                        // edges (maximum of cosine) 
                        if( i >= 2 ) 
                        { 
                            t = fabs(angle( 
                            (CvPoint*)cvGetSeqElem( result, i ), 
                            (CvPoint*)cvGetSeqElem( result, i-2 ), 
                            (CvPoint*)cvGetSeqElem( result, i-1 ))); 
                            s = s > t ? s : t; 
                        } 
					} 
						// if cosines of all angles are small 
                        // (all angles are ~90 degree) then write quandrange 
                        // vertices to resultant sequence  
                       if( s < 0.3 ) 
                         for(i = 0; i < 4; i++) 
                            cvSeqPush( squares,(CvPoint*)cvGetSeqElem(result, i)); 
				} 
 
				// take the next contour 
                contours = contours->h_next; 
            } 
	    } 
	} 
 
	//release all the temporary images 
    cvReleaseImage( &gray ); 
    cvReleaseImage( &pyr ); 
    cvReleaseImage( &tgray ); 
    cvReleaseImage( &timg ); 
     
    //画出所有识别出来的四边形 
	IplImage* cpy = cvCloneImage(src); 
	DrawGraphics(squares,cpy,4); 
	cvWaitKey(0); 
	 
	cvReleaseImage(&cpy);  
	return squares; 
} 
/*----FindCircle-------识别图像中的圆---------------------- 
 
src:     待识别的图像 
返回:    圆(圆心、半径) 
 
---------------------------------------------------------*/ 
CvSeq* CObjectRecognition::FindCircle(IplImage* src) 
{ 
  IplImage* gray = cvCreateImage( cvGetSize(src), 8, 1 ); 
  IplImage* cpy = cvCloneImage(src); 
  CvMemStorage* storage = cvCreateMemStorage(0); 
 
	cvCvtColor(src, gray, CV_BGR2GRAY ); 
  cvSmooth( gray, gray, CV_GAUSSIAN, 9, 9 ); // smooth it, otherwise a lot of false circles may be detected 
     
	CvSeq* circles = cvHoughCircles( gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/4, 200, 100); 
 
	//draw circles 
    for(int i = 0;itotal; i++ ) 
    { 
       float* p=(float*)cvGetSeqElem(circles,i); 
       cvCircle(cpy, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(0,255,0), 3, 8, 0 ); 
    } 
     
	cvNamedWindow("CIRCLE",1); 
	cvShowImage("CIRCLE",cpy); 
  cvWaitKey(0); 
 
	cvReleaseImage(&cpy); 
	cvReleaseImage(&gray); 
	return circles; 
} 
/*----FindEllipse-------识别图像中的椭圆------------------- 
 
src:     待识别的图像 
返回:    椭圆 
 
---------------------------------------------------------*/ 
CvSeq* CObjectRecognition::FindEllipse(IplImage* src) 
{ 
   int N=11,i,j,k; 
   int EdgePointNum=0; 
   int iWidth,iHeight; 
   int iMaxPos; 
   int count;//指定Accumulator所在位置 
   int threshold;//阈值 
   double x0,y0,angle,a,b; 
   bool flag=false; 
    
   //存储所识别出的图像中的椭圆 
   //椭圆可以用5个参数来表示,这点可以参考圆 
   CvMemStorage* storage = cvCreateMemStorage(0); 
   CvSeq* ellipses=cvCreateSeq( 0, sizeof(CvSeq),sizeof(SEllipseParams), storage ); 
    
   //store the edge points 
   IplImage* img=cvCreateImage(cvGetSize(src),8,1); 
   IplImage* cpy=cvCloneImage(src);//最后我们将把所识别出来的椭圆画在cpy上 
    
   //IplImage* img1=cvCreateImage(cvGetSize(src),8,1); 
   if(src->nChannels==3) cvCvtColor(src,img,CV_RGB2GRAY); 
   	else img=cvCloneImage(src); 
    
   //for(int l=0;lwidth; 
   iHeight=img->height; 
    
   for(i=0;iimageData[i]!=0) EdgePointNum++; 
     
   CvPoint *EdgePoints=new CvPoint[EdgePointNum]; 
 
   EdgePointNum=0; 
   for(i=0;iimageData[i*iWidth+j]!=0) 
   	 	 {  
   	 	   EdgePoints[EdgePointNum].x=j; 
   	 	   EdgePoints[EdgePointNum].y=i; 
   	 	   EdgePointNum++;  
   	 	 } 
     }   
    
   int AccumulatorSize=(int)(sqrt( (double)iWidth*iWidth+iHeight*iHeight));  
 
   SAccumulatorElem *AccumulatorArray=new SAccumulatorElem[AccumulatorSize]; 
   //初始化totalpoints 
   for(i=0;i50  
     	 	   && dist(&EdgePoints[i],&cvPoint(0,0))!=0  
     	 	   && dist(&EdgePoints[j],&cvPoint(0,0))!=0) 
     	 { 
     	 	 //first calculate (x0,y0,a,angle) 
     	 	 int x1=EdgePoints[i].x; 
     	 	 int y1=EdgePoints[i].y; 
     	 	 int x2=EdgePoints[j].x; 
     	 	 int y2=EdgePoints[j].y; 
     	 	 //int count; 
     	 	  
     	 	 x0=(x1+x2)*0.5; 
     	 	 y0=(y1+y2)*0.5; 
     	 	 a=0.5*sqrt((double)(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); 
     	 	 angle=a*tan((double)(y2-y1)/(x2-x1)); 
			 
     	 	  
     	 	 CvPoint Center; 
     	 	  
     	 	 Center.x=(int)x0; 
     	 	 Center.y=(int)y0; 
     	 	 //the third point,calculate the fifth parameter 
     	 	 for(k=j+1;kdist(&EdgePoints[k],&EdgePoints[j])) 
     	 	 	 	  	f=dist(&EdgePoints[k],&EdgePoints[j]); 
     	 	 	 	   
     	 	 	 	  double cosine=(a*a+d*d-f*f)/(2*a*d); 
     	 	 	 	  b=sqrt(a*a*d*d*(1-cosine*cosine)/(a*a-d*d*cosine*cosine)); 
     	 	 	 	   
					  count=(int)b; 
					  if(b-count>0.5) count++; 
 
					  //store the parameters 
     	 	 	 	  AccumulatorArray[count].EllipseParams[0]=x0; 
     	 	 	 	  AccumulatorArray[count].EllipseParams[1]=y0; 
     	 	 	 	  AccumulatorArray[count].EllipseParams[2]=angle; 
     	 	 	 	  AccumulatorArray[count].EllipseParams[3]=a; 
     	 	 	 	  AccumulatorArray[count].EllipseParams[4]=b; 
 
                      threshold=(int)a+count; 
     	 	 	 	   
     	 	 	 	  //Increment the accumulator for this length of minor axis by 1. 
					  if(AccumulatorArray[count].totalpoints==0) 
     	 	 	 	  { 
     	 	 	 	  		AccumulatorArray[count].totalpoints=3; 
     	 	 	 	  		//分配内存 
     	 	 	 	  		AccumulatorArray[count].xpos=new int[EdgePointNum]; 
     	 	 	 	  		AccumulatorArray[count].ypos=new int[EdgePointNum]; 
     	 	 	 	  		AccumulatorArray[count].pos=new int[EdgePointNum]; 
     	 	 	 	       
     	 	 	 	      AccumulatorArray[count].xpos[0]=EdgePoints[i].x; 
     	 	 	 	      AccumulatorArray[count].ypos[0]=EdgePoints[i].y; 
     	 	 	 	      AccumulatorArray[count].pos[0]=i; 
     	 	 	 	       
     	 	 	 	      AccumulatorArray[count].xpos[1]=EdgePoints[i].x; 
     	 	 	 	      AccumulatorArray[count].ypos[1]=EdgePoints[i].y; 
     	 	 	 	      AccumulatorArray[count].pos[1]=j; 
     	 	 	 	       
     	 	 	 	      AccumulatorArray[count].xpos[2]=EdgePoints[i].x; 
     	 	 	 	      AccumulatorArray[count].ypos[2]=EdgePoints[i].y; 
     	 	 	 	      AccumulatorArray[count].pos[2]=k; 
     	 	 	 	  } 
     	 	 	 	  else 
     	 	 	 	  { 
     	 	 	 	  		int tem; //Accumulator中点个数 
     	 	 	 	  		tem=AccumulatorArray[count].totalpoints; 
     	 	 	 	  		AccumulatorArray[count].xpos[tem]=EdgePoints[k].x; 
     	 	 	 	  		AccumulatorArray[count].ypos[tem]=EdgePoints[k].y; 
     	 	 	 	  		AccumulatorArray[count].pos[tem]=k; 
     	 	 	 	  		AccumulatorArray[count].totalpoints++;	   
							if (AccumulatorArray[count].totalpoints>threshold)  
							{ 
								iMaxPos=count; 
								flag=true; 
								break; 
							} 
     	 	 	 	  } 
     	 	 	 } 
     	 	 } 
     	 	  
     	 	 /* 
			 int max=0; 
     	 	 //find the maximum accumulator 
     	 	 for(int l=0;lmax)  
     	 	 	 	{ 
     	 	 	 		max=AccumulatorArray[l].totalpoints; 
     	 	 	 		iMaxPos=l; 
     	 	 	 	} 
     	 	 } 
			 */ 
     	 	  
           if(flag) 
     	   {   
     	   	  //认定该检测的为椭圆,应该把该椭圆的参数储存起来,存储的是CvSeq(ellipses)   
			  SEllipseParams ellipseParams; 
	          ellipseParams.x0=x0; 
	          ellipseParams.y0=y0; 
	          ellipseParams.angle=angle; 
	          ellipseParams.a=a; 
	          ellipseParams.b=b; 
 
              cvSeqPush(ellipses,&ellipseParams); 
     	      
     	     //把椭圆中的点去掉 
     	     for(int l=0;ltotal; i++ ) 
    { 
       SEllipseParams* p=(SEllipseParams*)cvGetSeqElem(ellipses,i); 
	   cvEllipse(cpy,cvPoint(cvRound(p->x0),cvRound(p->y0)), cvSize(cvRound(p->a),cvRound(p->b)),p->angle,0,360,CV_RGB(0,255,0),-1,8,0); 
    } 
     
	cvNamedWindow("ELLIPSE",1); 
	cvShowImage("ELLIPSE",cpy); 
    cvWaitKey(0); 
 
	cvReleaseImage(&cpy); 
	cvReleaseImage(&img); 
 
  return ellipses; 
} 
/*---FindTriangle-------识别图像中的三角形----------------- 
 
src:     待识别的图像 
返回:    三角形 
 
---------------------------------------------------------*/ 
CvSeq* CObjectRecognition::FindTriangle(IplImage* src) 
{ 
	CvSeq* contours; 
    int i, c, l, N = 11; 
 
	//将图像的尺寸变为偶数 
    CvSize sz = cvSize( src->width & -2, src->height & -2 ); 
 
  //拷贝源图像 
    IplImage* timg = cvCloneImage(src); 
	//创建灰度图像,单通道,大小为原图像大小(近似) 
	IplImage* gray = cvCreateImage(sz,IPL_DEPTH_8U,1);  
	//创建一个三通道彩色图像,大小为原图像的1/2*1/2,这主要是用于后面的图像下采样和上采样去噪; 
    IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2),IPL_DEPTH_8U,3); 
    IplImage* tgray; 
     
	//存储所识别出的图像中的三角形 
	CvMemStorage* storage = cvCreateMemStorage(0); 
	CvSeq* triangles= cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); 
     
    // select the maximum ROI in the image 
    // with the width and height divisible by 2 
	//选定图像的感兴趣区域 
    cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); 
     
	//图像的下采样和上采样(去噪) 
    cvPyrDown( timg, pyr, 7 ); 
    cvPyrUp( pyr, timg, 7 ); 
    tgray = cvCreateImage( sz,IPL_DEPTH_8U, 1 ); 
	 
	//在每一个颜色通道中查找三角形 
    for( c = 0; c < 3; c++ ) 
    { 
        //extract the c-th color plane 
        cvSetImageCOI( timg, c+1 ); 
        cvCopy( timg, tgray, 0 ); 
         
        //try several threshold levels 
        for( l = 0; l < N; l++ ) 
        { 
            // hack: use Canny instead of zero threshold level. 
            // Canny helps to catch squares with gradient shading 	 
            if( l == 0 ) 
            { 
                // apply Canny. Take the upper threshold from slider 
                // and set the lower to 0 (which forces edges merging)  
                cvCanny(tgray,gray,200,250,5); 
                // dilate canny output to remove potential 
                // holes between edge segments  
                cvDilate( gray, gray, 0, 1 ); 
            } 
            else 
            { 
                // apply threshold if l!=0: 
                // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 
                cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); 
			} 
             
            // find contours and store them all as a list 
            cvFindContours( gray, storage, &contours, sizeof(CvContour), 
                CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); 
             
            // test each contour 
            while( contours ) 
            { 
                // approximate contour with accuracy proportional 
                // to the contour perimeter 
               	CvSeq* result = cvApproxPoly( contours, sizeof(CvContour), storage, 
                CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); 
                // triangle contours should have 3 vertices after approximation 
                // relatively large area (to filter out noisy contours) 
                // and be convex. 
                // Note: absolute value of an area is used because 
                // area may be positive or negative - in accordance with the 
                // contour orientation 
                if( result->total == 3 && 
                    fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 500 && 
                    cvCheckContourConvexity(result) ) 
                { 
                    double s = 0; 
					CvPoint* pt[3]; 
                     
                    //the following codes are the key points,which is different from what you see in findsquare 
					//as we know,the three edges of a triangle should satisfy the constraints a plus b larger than c(not include equal) 
 
					pt[0]=(CvPoint*)cvGetSeqElem(result,0); 
					pt[1]=(CvPoint*)cvGetSeqElem(result,1); 
					pt[2]=(CvPoint*)cvGetSeqElem(result,2); 
 
 
                    //计算两点之间的距离 
					double EdgeA=dist(pt[0],pt[1]); 
				    double EdgeB=dist(pt[0],pt[2]); 
					double EdgeC=dist(pt[1],pt[2]); 
 
                    
					// the sum of two edges > the third edge 
                    // then write triangle 
                    // vertices to resultant sequence  
                    if( EdgeA+EdgeB> EdgeC) 
                         for(i = 0; i<3; i++) 
                            cvSeqPush(triangles,(CvPoint*)cvGetSeqElem( result, i )); 
				} 
 
				// take the next contour 
                contours = contours->h_next; 
            } 
	    } 
	} 
 
	//release all the temporary images 
    cvReleaseImage( &gray ); 
    cvReleaseImage( &pyr ); 
    cvReleaseImage( &tgray ); 
    cvReleaseImage( &timg ); 
     
    //画出所有识别出来的四边形 
	IplImage* cpy = cvCloneImage(src); 
	DrawGraphics(triangles,cpy,3); 
 
	cvWaitKey(0); 
	 
	cvReleaseImage(&cpy); 
	return triangles; 
   
} 
/*----DrawGraphics------画出所识别出的图像中形状---------- 
 
graphics:    所识别出的图像中的形状 
img:         要画的图像 
num:         形状的边数 
返回:        无 
 
---------------------------------------------------------*/ 
void CObjectRecognition::DrawGraphics(CvSeq* graphics,IplImage* img,int num) 
{ 
	CvSeqReader reader; 
	CvPoint *pt=new CvPoint[num]; 
 
	cvStartReadSeq(graphics,&reader,0); 
 
	//read the sequence elements at a time(all vertices of a graphic) 
	for(int i=0;itotal;i+=num) 
	{ 
		CvPoint* area=pt; 
		int count=num; 
 
		for(int j=0;jx - pt0->x; 
    double dy1 = pt1->y - pt0->y; 
    double dx2 = pt2->x - pt0->x; 
    double dy2 = pt2->y - pt0->y; 
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); 
} 
 
double CObjectRecognition::dist(CvPoint* pt0,CvPoint* pt1) 
{ 
	double distance; 
	distance=sqrt((double)(pt0->x-pt1->x)*(pt0->x-pt1->x)+(pt0->y-pt1->y)*(pt0->y-pt1->y)); 
 
	return distance; 
}