00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "hrl_cvblobslib/Blob.h"
00018
00019
00020 CBlob::CBlob()
00021 {
00022 m_area = m_perimeter = -1;
00023 m_externPerimeter = m_meanGray = m_stdDevGray = -1;
00024 m_boundingBox.width = -1;
00025 m_ellipse.size.width = -1;
00026 m_storage = NULL;
00027 m_id = -1;
00028 }
00029 CBlob::CBlob( t_labelType id, CvPoint startPoint, CvSize originalImageSize )
00030 {
00031 m_id = id;
00032 m_area = m_perimeter = -1;
00033 m_externPerimeter = m_meanGray = m_stdDevGray = -1;
00034 m_boundingBox.width = -1;
00035 m_ellipse.size.width = -1;
00036 m_storage = cvCreateMemStorage();
00037 m_externalContour = CBlobContour(startPoint, m_storage);
00038 m_originalImageSize = originalImageSize;
00039 }
00041 CBlob::CBlob( const CBlob &src )
00042 {
00043 m_storage = NULL;
00044 *this = src;
00045 }
00046
00047 CBlob::CBlob( const CBlob *src )
00048 {
00049 if (src != NULL )
00050 {
00051 m_storage = NULL;
00052 *this = *src;
00053 }
00054 }
00055
00056 CBlob& CBlob::operator=(const CBlob &src )
00057 {
00058 if( this != &src )
00059 {
00060 m_id = src.m_id;
00061 m_area = src.m_area;
00062 m_perimeter = src.m_perimeter;
00063 m_externPerimeter = src.m_externPerimeter;
00064 m_meanGray = src.m_meanGray;
00065 m_stdDevGray = src.m_stdDevGray;
00066 m_boundingBox = src.m_boundingBox;
00067 m_ellipse = src.m_ellipse;
00068 m_originalImageSize = src.m_originalImageSize;
00069
00070
00071 ClearContours();
00072
00073 if( m_storage )
00074 cvReleaseMemStorage( &m_storage );
00075
00076 m_storage = cvCreateMemStorage();
00077
00078 m_externalContour = CBlobContour(src.m_externalContour.GetStartPoint(), m_storage );
00079 if( src.m_externalContour.m_contour )
00080 m_externalContour.m_contour = cvCloneSeq( src.m_externalContour.m_contour, m_storage);
00081 m_internalContours.clear();
00082
00083
00084 if( src.m_internalContours.size() )
00085 {
00086 m_internalContours = t_contourList( src.m_internalContours.size() );
00087 t_contourList::const_iterator itSrc;
00088 t_contourList::iterator it;
00089
00090 itSrc = src.m_internalContours.begin();
00091 it = m_internalContours.begin();
00092
00093 while (itSrc != src.m_internalContours.end())
00094 {
00095 *it = CBlobContour((*itSrc).GetStartPoint(), m_storage);
00096 if( (*itSrc).m_contour )
00097 (*it).m_contour = cvCloneSeq( (*itSrc).m_contour, m_storage);
00098
00099 it++;
00100 itSrc++;
00101 }
00102 }
00103 }
00104
00105 return *this;
00106 }
00107
00108 CBlob::~CBlob()
00109 {
00110 ClearContours();
00111
00112 if( m_storage )
00113 cvReleaseMemStorage( &m_storage );
00114 }
00115
00116 void CBlob::ClearContours()
00117 {
00118 t_contourList::iterator it;
00119
00120 it = m_internalContours.begin();
00121
00122 while (it != m_internalContours.end())
00123 {
00124 (*it).ResetChainCode();
00125 it++;
00126 }
00127 m_internalContours.clear();
00128
00129 m_externalContour.ResetChainCode();
00130
00131 }
00132 void CBlob::AddInternalContour( const CBlobContour &newContour )
00133 {
00134 m_internalContours.push_back(newContour);
00135 }
00136
00139 bool CBlob::IsEmpty()
00140 {
00141 return GetExternalContour()->m_contour == NULL;
00142 }
00143
00157 double CBlob::Area()
00158 {
00159 double area;
00160 t_contourList::iterator itContour;
00161
00162 area = m_externalContour.GetArea();
00163
00164 itContour = m_internalContours.begin();
00165
00166 while (itContour != m_internalContours.end() )
00167 {
00168 area -= (*itContour).GetArea();
00169 itContour++;
00170 }
00171 return area;
00172 }
00173
00187 double CBlob::Perimeter()
00188 {
00189 double perimeter;
00190 t_contourList::iterator itContour;
00191
00192 perimeter = m_externalContour.GetPerimeter();
00193
00194 itContour = m_internalContours.begin();
00195
00196 while (itContour != m_internalContours.end() )
00197 {
00198 perimeter += (*itContour).GetPerimeter();
00199 itContour++;
00200 }
00201 return perimeter;
00202
00203 }
00204
00219 int CBlob::Exterior(IplImage *mask, bool xBorder , bool yBorder )
00220 {
00221 if (ExternPerimeter(mask, xBorder, yBorder ) > 0 )
00222 {
00223 return 1;
00224 }
00225
00226 return 0;
00227 }
00246 double CBlob::ExternPerimeter( IplImage *maskImage, bool xBorder , bool yBorder )
00247 {
00248 t_PointList externContour, externalPoints;
00249 CvSeqReader reader;
00250 CvSeqWriter writer;
00251 CvPoint actualPoint, previousPoint;
00252 bool find = false;
00253 int i,j;
00254 int delta = 0;
00255
00256
00257 if( m_externPerimeter != -1 )
00258 {
00259 return m_externPerimeter;
00260 }
00261
00262
00263 externContour = m_externalContour.GetContourPoints();
00264
00265 m_externPerimeter = 0;
00266
00267
00268 if( externContour == NULL )
00269 {
00270 return m_externPerimeter;
00271 }
00272
00273 cvStartReadSeq( externContour, &reader);
00274
00275
00276 externalPoints = cvCreateSeq( externContour->flags, externContour->header_size, externContour->elem_size,
00277 m_storage );
00278 cvStartAppendToSeq( externalPoints, &writer );
00279 previousPoint.x = -1;
00280
00281
00282 for( j=0; j< externContour->total; j++)
00283 {
00284 CV_READ_SEQ_ELEM( actualPoint, reader);
00285
00286 find = false;
00287
00288
00289 if ( xBorder & ((actualPoint.x == 0) || (actualPoint.x == m_originalImageSize.width - 1 )) ||
00290 yBorder & ((actualPoint.y == 0) || (actualPoint.y == m_originalImageSize.height - 1 )))
00291 {
00292 find = true;
00293 }
00294 else
00295 {
00296 if( maskImage != NULL )
00297 {
00298
00299 char *pMask;
00300
00301 pMask = (maskImage->imageData + actualPoint.x - 1 + (actualPoint.y - 1) * maskImage->widthStep);
00302
00303 for ( i = 0; i < 3; i++, pMask++ )
00304 {
00305 if(*pMask == 0 && !find )
00306 {
00307 find = true;
00308 break;
00309 }
00310 }
00311
00312 if(!find)
00313 {
00314 pMask = (maskImage->imageData + actualPoint.x - 1 + (actualPoint.y ) * maskImage->widthStep);
00315
00316 for ( i = 0; i < 3; i++, pMask++ )
00317 {
00318 if(*pMask == 0 && !find )
00319 {
00320 find = true;
00321 break;
00322 }
00323 }
00324 }
00325
00326 if(!find)
00327 {
00328 pMask = (maskImage->imageData + actualPoint.x - 1 + (actualPoint.y + 1) * maskImage->widthStep);
00329
00330 for ( i = 0; i < 3; i++, pMask++ )
00331 {
00332 if(*pMask == 0 && !find )
00333 {
00334 find = true;
00335 break;
00336 }
00337 }
00338 }
00339 }
00340 }
00341
00342 if( find )
00343 {
00344 if( previousPoint.x > 0 )
00345 delta = abs(previousPoint.x - actualPoint.x) + abs(previousPoint.y - actualPoint.y);
00346
00347
00348 if( delta > 2 )
00349 {
00350 cvEndWriteSeq( &writer );
00351 m_externPerimeter += cvArcLength( externalPoints, CV_WHOLE_SEQ, 0 );
00352
00353 cvClearSeq( externalPoints );
00354 cvStartAppendToSeq( externalPoints, &writer );
00355 delta = 0;
00356 previousPoint.x = -1;
00357 }
00358
00359 CV_WRITE_SEQ_ELEM( actualPoint, writer );
00360 previousPoint = actualPoint;
00361 }
00362
00363 }
00364
00365 cvEndWriteSeq( &writer );
00366
00367 m_externPerimeter += cvArcLength( externalPoints, CV_WHOLE_SEQ, 0 );
00368
00369 cvClearSeq( externalPoints );
00370
00371
00372
00373 m_externPerimeter /= 2.0;
00374
00375 return m_externPerimeter;
00376 }
00377
00379 double CBlob::Moment(int p, int q)
00380 {
00381 double moment;
00382 t_contourList::iterator itContour;
00383
00384 moment = m_externalContour.GetMoment(p,q);
00385
00386 itContour = m_internalContours.begin();
00387
00388 while (itContour != m_internalContours.end() )
00389 {
00390 moment -= (*itContour).GetMoment(p,q);
00391 itContour++;
00392 }
00393 return moment;
00394 }
00395
00409 double CBlob::Mean( IplImage *image )
00410 {
00411
00412
00413
00414
00415
00416
00417
00418 IplImage *mask;
00419 CvScalar mean, std;
00420 CvPoint offset;
00421
00422 GetBoundingBox();
00423
00424 if (m_boundingBox.height == 0 ||m_boundingBox.width == 0 || !CV_IS_IMAGE( image ))
00425 {
00426 m_meanGray = 0;
00427 return m_meanGray;
00428 }
00429
00430
00431 mask = cvCreateImage( cvSize(m_boundingBox.width, m_boundingBox.height), IPL_DEPTH_8U, 1);
00432 cvSetZero(mask);
00433
00434 offset.x = -m_boundingBox.x;
00435 offset.y = -m_boundingBox.y;
00436
00437
00438 cvDrawContours( mask, m_externalContour.GetContourPoints(), CV_RGB(255,255,255), CV_RGB(255,255,255),0, CV_FILLED, 8,
00439 offset );
00440
00441
00442 t_contourList::iterator it = m_internalContours.begin();
00443 while(it != m_internalContours.end() )
00444 {
00445 cvDrawContours( mask, (*it).GetContourPoints(), CV_RGB(0,0,0), CV_RGB(0,0,0),0, CV_FILLED, 8,
00446 offset );
00447 it++;
00448 }
00449
00450 cvSetImageROI( image, m_boundingBox );
00451 cvAvgSdv( image, &mean, &std, mask );
00452
00453 m_meanGray = mean.val[0];
00454 m_stdDevGray = std.val[0];
00455
00456 cvReleaseImage( &mask );
00457 cvResetImageROI( image );
00458
00459 return m_meanGray;
00460 }
00461
00462 double CBlob::StdDev( IplImage *image )
00463 {
00464
00465
00466
00467
00468
00469
00470
00471 Mean( image );
00472
00473 return m_stdDevGray;
00474 }
00488 CvRect CBlob::GetBoundingBox()
00489 {
00490
00491 if( m_boundingBox.width != -1 )
00492 {
00493 return m_boundingBox;
00494 }
00495
00496 t_PointList externContour;
00497 CvSeqReader reader;
00498 CvPoint actualPoint;
00499
00500
00501 externContour = m_externalContour.GetContourPoints();
00502
00503
00504 if( !externContour )
00505 {
00506 m_boundingBox.x = 0;
00507 m_boundingBox.y = 0;
00508 m_boundingBox.width = 0;
00509 m_boundingBox.height = 0;
00510
00511 return m_boundingBox;
00512 }
00513
00514 cvStartReadSeq( externContour, &reader);
00515
00516 m_boundingBox.x = m_originalImageSize.width;
00517 m_boundingBox.y = m_originalImageSize.height;
00518 m_boundingBox.width = 0;
00519 m_boundingBox.height = 0;
00520
00521 for( int i=0; i< externContour->total; i++)
00522 {
00523 CV_READ_SEQ_ELEM( actualPoint, reader);
00524
00525 m_boundingBox.x = MIN( actualPoint.x, m_boundingBox.x );
00526 m_boundingBox.y = MIN( actualPoint.y, m_boundingBox.y );
00527
00528 m_boundingBox.width = MAX( actualPoint.x, m_boundingBox.width );
00529 m_boundingBox.height = MAX( actualPoint.y, m_boundingBox.height );
00530 }
00531
00532
00533
00534
00535 m_boundingBox.width -= m_boundingBox.x;
00536 m_boundingBox.height -= m_boundingBox.y;
00537
00538 return m_boundingBox;
00539 }
00540
00555 CvBox2D CBlob::GetEllipse()
00556 {
00557
00558 if( m_ellipse.size.width != -1 )
00559 return m_ellipse;
00560
00561 double u00,u11,u01,u10,u20,u02, delta, num, den, temp;
00562
00563
00564 u00 = Moment(0,0);
00565
00566
00567 if ( u00 <= 0 )
00568 {
00569 m_ellipse.size.width = 0;
00570 m_ellipse.size.height = 0;
00571 m_ellipse.center.x = 0;
00572 m_ellipse.center.y = 0;
00573 m_ellipse.angle = 0;
00574 return m_ellipse;
00575 }
00576 u10 = Moment(1,0) / u00;
00577 u01 = Moment(0,1) / u00;
00578
00579 u11 = -(Moment(1,1) - Moment(1,0) * Moment(0,1) / u00 ) / u00;
00580 u20 = (Moment(2,0) - Moment(1,0) * Moment(1,0) / u00 ) / u00;
00581 u02 = (Moment(0,2) - Moment(0,1) * Moment(0,1) / u00 ) / u00;
00582
00583
00584
00585 delta = sqrt( 4*u11*u11 + (u20-u02)*(u20-u02) );
00586 m_ellipse.center.x = u10;
00587 m_ellipse.center.y = u01;
00588
00589 temp = u20 + u02 + delta;
00590 if( temp > 0 )
00591 {
00592 m_ellipse.size.width = sqrt( 2*(u20 + u02 + delta ));
00593 }
00594 else
00595 {
00596 m_ellipse.size.width = 0;
00597 return m_ellipse;
00598 }
00599
00600 temp = u20 + u02 - delta;
00601 if( temp > 0 )
00602 {
00603 m_ellipse.size.height = sqrt( 2*(u20 + u02 - delta ) );
00604 }
00605 else
00606 {
00607 m_ellipse.size.height = 0;
00608 return m_ellipse;
00609 }
00610
00611
00612 if (u20 > u02)
00613 {
00614 num = u02 - u20 + sqrt((u02 - u20)*(u02 - u20) + 4*u11*u11);
00615 den = 2*u11;
00616 }
00617 else
00618 {
00619 num = 2*u11;
00620 den = u20 - u02 + sqrt((u20 - u02)*(u20 - u02) + 4*u11*u11);
00621 }
00622 if( num != 0 && den != 00 )
00623 {
00624 m_ellipse.angle = 180.0 + (180.0 / CV_PI) * atan( num / den );
00625 }
00626 else
00627 {
00628 m_ellipse.angle = 0;
00629 }
00630
00631 return m_ellipse;
00632
00633 }
00634
00649 void CBlob::FillBlob( IplImage *imatge, CvScalar color, int offsetX , int offsetY )
00650 {
00651 cvDrawContours( imatge, m_externalContour.GetContourPoints(), color, color,0, CV_FILLED, 8 );
00652 }
00653
00654
00667 t_PointList CBlob::GetConvexHull()
00668 {
00669 CvSeq *convexHull = NULL;
00670
00671 if( m_externalContour.GetContourPoints() )
00672 convexHull = cvConvexHull2( m_externalContour.GetContourPoints(), m_storage,
00673 CV_COUNTER_CLOCKWISE, 1 );
00674
00675 return convexHull;
00676 }
00677
00690 void CBlob::JoinBlob( CBlob *blob )
00691 {
00692 CvSeqWriter writer;
00693 CvSeqReader reader;
00694 t_chainCode chainCode;
00695
00696 cvStartAppendToSeq( m_externalContour.GetChainCode(), &writer );
00697 cvStartReadSeq( blob->GetExternalContour()->GetChainCode(), &reader );
00698
00699 for (int i = 0; i < blob->GetExternalContour()->GetChainCode()->total; i++ )
00700 {
00701 CV_READ_SEQ_ELEM( chainCode, reader );
00702 CV_WRITE_SEQ_ELEM( chainCode, writer );
00703 }
00704 cvEndWriteSeq( &writer );
00705
00706 }