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;
}