Blob.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002                         Blob.cpp
00003                         
00004 - FUNCIONALITAT: Implementació de la classe CBlob
00005 - AUTOR: Inspecta S.L.
00006 MODIFICACIONS (Modificació, Autor, Data):
00007 
00008  
00009 FUNCTIONALITY: Implementation of the CBlob class and some helper classes to perform
00010                            some calculations on it
00011 AUTHOR: Inspecta S.L.
00012 MODIFICATIONS (Modification, Author, Date):
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                 // clear all current blob contours
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                 // copy all internal contours
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 /* = true */, bool yBorder /* = true */)
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 /* = true */, bool yBorder /* = true */)
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         // it is calculated?
00257         if( m_externPerimeter != -1 )
00258         {
00259                 return m_externPerimeter;
00260         }
00261 
00262         // get contour pixels
00263         externContour = m_externalContour.GetContourPoints();
00264 
00265         m_externPerimeter = 0;
00266 
00267         // there are contour pixels?
00268         if( externContour == NULL )
00269         {
00270                 return m_externPerimeter;
00271         }
00272 
00273         cvStartReadSeq( externContour, &reader);
00274 
00275         // create a sequence with the external points of the blob
00276         externalPoints = cvCreateSeq( externContour->flags, externContour->header_size, externContour->elem_size, 
00277                                                                   m_storage );
00278         cvStartAppendToSeq( externalPoints, &writer );
00279         previousPoint.x = -1;
00280 
00281         // which contour pixels touch border?
00282         for( j=0; j< externContour->total; j++)
00283         {
00284                 CV_READ_SEQ_ELEM( actualPoint, reader);
00285 
00286                 find = false;
00287 
00288                 // pixel is touching border?
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                                 // verify if some of 8-connected neighbours is black in mask
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                         // calculate separately each external contour segment 
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         // divide by two because external points have one side inside the blob and the other outside
00372         // Perimeter of external points counts both sides, so it must be divided
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         // it is calculated?
00412 /*      if( m_meanGray != -1 )
00413         {
00414                 return m_meanGray;
00415         }
00416 */      
00417         // Create a mask with same size as blob bounding box
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         // apply ROI and mask to input image to compute mean gray and standard deviation
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         // draw contours on mask
00438         cvDrawContours( mask, m_externalContour.GetContourPoints(), CV_RGB(255,255,255), CV_RGB(255,255,255),0, CV_FILLED, 8,
00439                                         offset );
00440 
00441         // draw internal contours
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         // it is calculated?
00465 /*      if( m_stdDevGray != -1 )
00466         {
00467                 return m_stdDevGray;
00468         }
00469 */
00470         // call mean calculation (where also standard deviation is calculated)
00471         Mean( image );
00472 
00473         return m_stdDevGray;
00474 }
00488 CvRect CBlob::GetBoundingBox()
00489 {
00490         // it is calculated?
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         // get contour pixels
00501         externContour = m_externalContour.GetContourPoints();
00502         
00503         // it is an empty blob?
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         //m_boundingBox.x = max( m_boundingBox.x , 0 );
00533         //m_boundingBox.y = max( m_boundingBox.y , 0 );
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         // it is calculated?
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         // central moments calculation
00564         u00 = Moment(0,0);
00565 
00566         // empty blob?
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         // elipse calculation
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         // elipse orientation
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 /*=0*/, int offsetY /*=0*/)                                           
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 }


hrl_cvblobslib
Author(s): kelsey
autogenerated on Wed Nov 27 2013 11:32:58