D:/users/ricard/src/utilitats/cpp/cvblobslib/BlobExtraction.cpp

Go to the documentation of this file.
00001 //***********************************************************//
00002 //* Blob analysis package  8 August 2003                    *//
00003 //* Version 1.0                                             *//
00004 //* Input: IplImage* binary image                           *//
00005 //* Output: attributes of each connected region             *//
00006 //* Author: Dave Grossman                                   *//
00007 //* Modifications: Francesc Pinyol and Ricard Borras            *//
00008 //* Email: dgrossman@cdr.stanford.edu                       *//
00009 //* Email: fpinyol@cvc.uab.es rborras@cvc.uab.es            *//
00010 //* Acknowledgement: the algorithm has been around > 20 yrs *//
00011 //***********************************************************//
00012 
00014 #define B_CONNECTIVITAT_8
00015 
00018 #define IMATGE_CICLICA_VERTICAL         1
00021 #define IMATGE_CICLICA_HORITZONTAL      0
00022 
00023 #define PERIMETRE_DIAGONAL (1.41421356237310 - 2)
00024 #define SQRT2   1.41421356237310
00025 // color dels píxels de la màscara per ser exteriors
00026 #define PIXEL_EXTERIOR 0
00027 
00028 
00029 #include "blobresult.h"
00030 #include "blobextraction.h"
00031 
00053 bool BlobAnalysis(      IplImage* inputImage,
00054                                         uchar threshold,
00055                                     IplImage* maskImage,
00056                                     bool borderColor,
00057                                     bool findmoments,
00058                                         blob_vector &RegionData )       
00059 {
00060         // dimensions of input image taking in account the ROI
00061         int Cols, Rows, startCol, startRow;
00062 
00063         if( inputImage->roi )
00064         {
00065                 CvRect imageRoi = cvGetImageROI( inputImage );
00066                 startCol = imageRoi.x;
00067                 startRow = imageRoi.y;
00068                 Cols = imageRoi.width;
00069                 Rows = imageRoi.height;
00070         }
00071         else
00072         {
00073                 startCol = 0;
00074                 startRow = 0; 
00075                 Cols = inputImage->width;
00076                 Rows = inputImage->height;
00077         }
00078 
00079         int Trans = Cols;                               // MAX trans in any row
00080         char* pMask;
00081         char* pImage;
00082 
00083         // Convert image array into transition array. In each row
00084         // the transition array tells which columns have a color change
00085         int iCol,iRow,iTran, Tran;                              // Data for a given run
00086         bool ThisCell, LastCell;                // Contents (colors (0 or 1)) within this row
00087         int TransitionOffset = 0;               // Performance booster to avoid multiplication
00088         
00089         // row 0 and row Rows+1 represent the border
00090         int i;
00091         int *Transition;                                // Transition Matrix
00092 
00093         int nombre_pixels_mascara = 0;
00095         IplImage *imatgePerimetreExtern;
00096 
00097         // input images must have only 1-channel and be an image
00098         if( !CV_IS_IMAGE( inputImage ) || (inputImage->nChannels != 1) )
00099         {
00100                 return false;
00101         }
00102         if( maskImage != NULL )
00103         {
00104                 // input image and mask are a valid image?
00105                 if( !CV_IS_IMAGE( inputImage ) || !CV_IS_IMAGE( maskImage )) 
00106                         return false;
00107 
00108                 // comprova que la màscara tingui les mateixes dimensions que la imatge
00109                 if( !CV_ARE_SIZES_EQ(inputImage, maskImage ) )
00110                 {
00111                         return false;
00112                 }
00113 
00114                 // comprova que la màscara sigui una imatge d'un sol canal (grayscale)
00115                 if( maskImage->nChannels != 1 )
00116                 {
00117                         return false;
00118                 }
00119                 
00120         }
00121 
00122         // Initialize Transition array
00123         Transition=new int[(Rows + 2)*(Cols + 2)];
00124         memset(Transition,0,(Rows + 2) * (Cols + 2)*sizeof(int));
00125         Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2;
00126         
00127         // Start at the beginning of the image (startCol, startRow)
00128         pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep;
00129 
00130 /*
00131         Paral·lelització del càlcul de la matriu de transicions
00132         Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads ) 
00133 */
00134         if(maskImage == NULL)
00135         {
00136                 imatgePerimetreExtern = NULL;
00137 
00138                 //Fill Transition array
00139                 for(iRow = 1; iRow < Rows + 1; iRow++)          // Choose a row of Bordered image
00140                 {
00141                         TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable
00142                         iTran = 0;                                      // Index into Transition array
00143                         Tran = 0;                                       // No transitions at row start
00144                         LastCell = borderColor;
00145 
00146                         for(iCol = 0; iCol < Cols + 2; iCol++)  // Scan that row of Bordered image
00147                         {
00148                                 if(iCol == 0 || iCol == Cols+1) 
00149                                         ThisCell = borderColor;
00150                                 else
00151                                         ThisCell = ((unsigned char) *(pImage)) > threshold;
00152 
00153                                 if(ThisCell != LastCell)
00154                                 {
00155                                         Transition[TransitionOffset + iTran] = Tran;    // Save completed Tran
00156                                         iTran++;                                                // Prepare new index
00157                                         LastCell = ThisCell;                    // With this color
00158                                 }
00159 
00160                                 Tran++; // Tran continues
00161                                 pImage++;
00162                         }
00163                         
00164                         Transition[TransitionOffset + iTran] = Tran;    // Save completed run
00165                         if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
00166                         {
00167                                 Transition[TransitionOffset + iTran + 1] = -1;
00168                         }
00169                         //jump to next row (beginning from (startCol, startRow))
00170                         pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
00171                 }
00172         }
00173         else
00174         {
00175                 //maskImage not NULL: Cal recòrrer la màscara també per calcular la matriu de transicions
00176 
00177                 char perimeter;
00178                 char *pPerimetre;
00179                 
00180                 // creem la imatge que contindrà el perimetre extern de cada pixel
00181                 imatgePerimetreExtern = cvCreateImage( cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1);
00182                 cvSetZero( imatgePerimetreExtern );
00183 
00184                 pMask = maskImage->imageData - 1;
00185                 
00186                 //Fill Transition array
00187                 for(iRow = 1; iRow < Rows + 1; iRow++)          // Choose a row of Bordered image
00188                 {
00189                         TransitionOffset = iRow*(Cols + 2);
00190                         iTran = 0;                                      // Index into Transition array
00191                         Tran = 0;                                       // No transitions at row start
00192                         LastCell = borderColor;
00193 
00194                         pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep;
00195                         //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep;
00196 
00197                         for(iCol = 0; iCol < Cols + 2; iCol++)  // Scan that row of Bordered image
00198                         {
00199                                 if(iCol == 0 || iCol == Cols+1 || ((unsigned char) *pMask) == PIXEL_EXTERIOR) 
00200                                         ThisCell = borderColor;
00201                                 else
00202                                         ThisCell = ((unsigned char) *(pImage)) > threshold;
00203 
00204                                 if(ThisCell != LastCell)
00205                                 {
00206                                         Transition[TransitionOffset + iTran] = Tran;    // Save completed Tran
00207                                         iTran++;                                                // Prepare new index
00208                                         LastCell = ThisCell;                    // With this color
00209                                 }
00210 
00211                                 /*////////////////////////////////////////////////////////////////////////
00212                                 Calcul de la imatge amb els pixels externs
00214                                 // pels pixels externs no cal calcular res pq no hi accedir-hem
00215                                 if( (iCol > 0) && (iCol < Cols) )
00216                                 {
00217                                         if( *pMask == PIXEL_EXTERIOR )
00218                                         {
00219                                                 *pPerimetre = 0;
00220                                         }
00221                                         else
00222                                         {
00223                                                 perimeter = 0;
00224                                                 
00225                                                 // pixels al nord de l'actual
00226                                                 if(iRow>1)
00227                                                 {
00228                                                         if( *(pMask - maskImage->widthStep ) == PIXEL_EXTERIOR) perimeter++;
00229                                                 }
00230 
00231                                                 // pixels a l'est i oest de l'actual
00232                                                 if( iRow < imatgePerimetreExtern->height )
00233                                                 {
00234                                                         if( (iCol>0) && (*(pMask-1) == PIXEL_EXTERIOR) ) perimeter++;
00235 
00236                                                         if( ( iCol < imatgePerimetreExtern->width - 1) && (*(pMask+1) == PIXEL_EXTERIOR) ) perimeter++;
00237                                                 }
00238 
00239                                                 // pixels al sud de l'actual
00240                                                 if( iRow < imatgePerimetreExtern->height - 1)
00241                                                 {
00242                                                         if( (*(pMask+maskImage->widthStep) == PIXEL_EXTERIOR) ) perimeter++;
00243                                                 }
00244                                 
00245                                                 *pPerimetre = perimeter;
00246                                         }
00247                                 }
00248 
00249                                 Tran++; // Tran continues
00250                                 pImage++;
00251                                 pMask++;
00252                                 pPerimetre++;
00253                         }
00254                         Transition[TransitionOffset + iTran] = Tran;    // Save completed run
00255 
00256                         if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
00257                         {
00258                                 Transition[TransitionOffset + iTran + 1] = -1;
00259                         }
00260 
00261                         
00262                         //jump to next row (beginning from (startCol, startRow))
00263                         pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
00264                         //the mask should be the same size as image Roi, so don't take into account the offset
00265                         pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep;
00266                 }
00267         }
00268 
00269         // Process transition code depending on Last row and This row
00270         //
00271         // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++---
00272         // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++--
00273         //
00274         // There are various possibilities:
00275         //
00276         // Case     1       2       3       4       5       6       7       8
00277         // Last |xxx    |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx  |ooxxxxx|    xxx|
00278         // This |    yyy|    yyy|  yyyy |  yyyyy|yyyyyyy|yyyyyyy|yyyy   |yyyy   |
00279         // Here o is optional
00280         // 
00281         // Here are the primitive tests to distinguish these 6 cases:
00282         //   A) Last end < This start - 1 OR NOT                Note: -1
00283         //   B) This end < Last start OR NOT
00284         //   C) Last start < This start OR NOT
00285         //   D) This end < Last end OR NOT
00286         //   E) This end = Last end OR NOT
00287         //
00288         // Here is how to use these tests to determine the case:
00289         //   Case 1 = A [=> NOT B AND C AND NOT D AND NOT E]
00290         //   Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B]
00291         //   Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B]
00292         //   Case 4 = C AND NOT D AND E [AND NOT A AND NOT B]
00293         //   Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B]
00294         //   Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B]
00295         //   Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B]
00296         //   Case 8 = B [=> NOT A AND NOT C AND D AND NOT E]
00297         //
00298         // In cases 2,3,4,5,6,7 the following additional test is needed:
00299         //   Match) This color = Last color OR NOT
00300         //
00301         // In cases 5,6,7 the following additional test is needed:
00302         //   Known) This region was already matched OR NOT
00303         //
00304         // Here are the main tests and actions:
00305         //   Case 1: LastIndex++;
00306         //   Case 2: if(Match) {y = x;}
00307         //           LastIndex++;
00308         //   Case 3: if(Match) {y = x;}
00309         //           else {y = new}
00310         //           ThisIndex++;
00311         //   Case 4: if(Match) {y = x;}
00312         //           else {y = new}
00313         //           LastIndex++;
00314         //           ThisIndex++;
00315         //   Case 5: if(Match AND NOT Known) {y = x}
00316         //           else if(Match AND Known) {Subsume(x,y)}
00317         //           LastIndex++;ThisIndex++
00318         //   Case 6: if(Match AND NOT Known) {y = x}
00319         //           else if(Match AND Known) {Subsume(x,y)}
00320         //           LastIndex++;
00321         //   Case 7: if(Match AND NOT Known) {y = x}
00322         //           else if(Match AND Known) {Subsume(x,y)}
00323         //           ThisIndex++;
00324         //   Case 8: ThisIndex++;
00325 
00326         int *SubsumedRegion = NULL;                     
00327         
00328         double ThisParent;      // These data can change when the line is current
00329         double ThisArea;
00330         double ThisPerimeter;
00331         double ThisSumX;
00332         double ThisSumY;
00333         double ThisSumXX;
00334         double ThisSumYY;
00335         double ThisSumXY;
00336         double ThisMinX;
00337         double ThisMaxX;
00338         double ThisMinY;
00339         double ThisMaxY;
00340         double LastPerimeter;   // This is the only data for retroactive change
00341         double ThisExternPerimeter;
00342         
00343         int HighRegionNum = 0;
00344         int RegionNum = 0;
00345         int ErrorFlag = 0;
00346         
00347         int LastRow, ThisRow;                   // Row number
00348         int LastStart, ThisStart;               // Starting column of run
00349         int LastEnd, ThisEnd;                   // Ending column of run
00350         int LastColor, ThisColor;               // Color of run
00351         
00352         int LastIndex, ThisIndex;               // Which run are we up to
00353         int LastIndexCount, ThisIndexCount;     // Out of these runs
00354         int LastRegionNum, ThisRegionNum;       // Which assignment
00355         int *LastRegion;                                // Row assignment of region number
00356         int *ThisRegion;                // Row assignment of region number
00357         
00358         int LastOffset = -(Trans + 2);  // For performance to avoid multiplication
00359         int ThisOffset = 0;                             // For performance to avoid multiplication
00360         int ComputeData;
00361 
00362         CvPoint actualedge;
00363         uchar imagevalue;
00364         bool CandidatExterior = false;
00365 
00366         // apuntadors als blobs de la regió actual i last
00367         CBlob *regionDataThisRegion, *regionDataLastRegion;
00368         
00369         LastRegion=new int[Cols+2];
00370         ThisRegion=new int[Cols+2];
00371 
00372         for(i = 0; i < Cols + 2; i++)   // Initialize result arrays
00373         {
00374                 LastRegion[i] = -1;
00375                 ThisRegion[i] = -1;
00376         }
00377 
00378         //create the external blob
00379         RegionData.push_back( new CBlob() );
00380         SubsumedRegion = NewSubsume(SubsumedRegion,0);
00381         RegionData[0]->parent = -1;
00382         RegionData[0]->area = (double) Transition[0];
00383         RegionData[0]->perimeter = (double) (2 + 2 * Transition[0]);
00384 
00385         ThisIndexCount = 1;
00386         ThisRegion[0] = 0;      // Border region
00387 
00388         // beginning of the image 
00389         // en cada linia, pimage apunta al primer pixel de la fila
00390         pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep;
00391         //the mask should be the same size as image Roi, so don't take into account the offset
00392         if(maskImage!=NULL) pMask = maskImage->imageData - 1;
00393 
00394         char *pImageAux, *pMaskAux;
00395         
00396         // Loop over all rows
00397         for(ThisRow = 1; ThisRow < Rows + 2; ThisRow++)
00398         {
00399                 //cout << "========= THIS ROW = " << ThisRow << endl;   // for debugging
00400                 ThisOffset += Trans + 2;
00401                 ThisIndex = 0;
00402                 LastOffset += Trans + 2;;
00403                 LastRow = ThisRow - 1;
00404                 LastIndexCount = ThisIndexCount;
00405                 LastIndex = 0;
00406 
00407                 int EndLast = 0;
00408                 int EndThis = 0;
00409 
00410                 for(int j = 0; j < Trans + 2; j++)
00411                 {
00412                         int Index = ThisOffset + j;
00413                         int TranVal = Transition[Index];
00414                         if(TranVal > 0) ThisIndexCount = j + 1; // stop at highest 
00415 
00416                         if(ThisRegion[j] == -1)  { EndLast = 1; }
00417                         if(TranVal < 0) { EndThis = 1; }
00418 
00419                         if(EndLast > 0 && EndThis > 0) { break; }
00420 
00421                         LastRegion[j] = ThisRegion[j];
00422                         ThisRegion[j] = -1;             // Flag indicates region is not initialized
00423                 }
00424 
00425                 int MaxIndexCount = LastIndexCount;
00426                 if(ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount;
00427 
00428                 // Main loop over runs within Last and This rows
00429                 while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount)
00430                 {
00431                         ComputeData = 0;
00432                 
00433                         if(LastIndex == 0) LastStart = 0;
00434                         else LastStart = Transition[LastOffset + LastIndex - 1];
00435                         LastEnd = Transition[LastOffset + LastIndex] - 1;
00436                         LastColor = LastIndex - 2 * (LastIndex / 2);
00437                         LastRegionNum = LastRegion[LastIndex];
00438 
00439                         regionDataLastRegion = RegionData[LastRegionNum];
00440 
00441                         
00442                         if(ThisIndex == 0) ThisStart = 0;
00443                         else ThisStart = Transition[ThisOffset + ThisIndex - 1];
00444                         ThisEnd = Transition[ThisOffset + ThisIndex] - 1;
00445                         ThisColor = ThisIndex - 2 * (ThisIndex / 2);
00446                         ThisRegionNum = ThisRegion[ThisIndex];
00447 
00448                         if( ThisRegionNum >= 0 )
00449                                 regionDataThisRegion = RegionData[ThisRegionNum];
00450                         else
00451                                 regionDataThisRegion = NULL;
00452 
00453 
00454                         // blobs externs
00455                         CandidatExterior = false;
00456                         if( 
00457 #if !IMATGE_CICLICA_VERTICAL
00458                                 ThisRow == 1 || ThisRow == Rows ||
00459 #endif
00460 #if !IMATGE_CICLICA_HORITZONTAL
00461                                 ThisStart <= 1 || ThisEnd >= Cols || 
00462 #endif                          
00463                                 GetExternPerimeter( ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern )
00464                                 )
00465                         {
00466                                 CandidatExterior = true;
00467                         }
00468                         
00469                         int TestA = (LastEnd < ThisStart - 1);  // initially false
00470                         int TestB = (ThisEnd < LastStart);              // initially false
00471                         int TestC = (LastStart < ThisStart);    // initially false
00472                         int TestD = (ThisEnd < LastEnd);
00473                         int TestE = (ThisEnd == LastEnd);
00474 
00475                         int TestMatch = (ThisColor == LastColor);               // initially true
00476                         int TestKnown = (ThisRegion[ThisIndex] >= 0);   // initially false
00477 
00478                         int Case = 0;
00479                         if(TestA) Case = 1;
00480                         else if(TestB) Case = 8;
00481                         else if(TestC)
00482                         {
00483                                 if(TestD) Case = 3;
00484                                 else if(!TestE) Case = 2;
00485                                 else Case = 4;
00486                         }
00487                         else
00488                         {
00489                                 if(TestE) Case = 5;
00490                                 else if(TestD) Case = 7;
00491                                 else Case = 6;
00492                         }
00493 
00494                         // Initialize common variables
00495                         ThisArea = (float) 0.0;
00496 
00497                         if(findmoments)
00498                         {
00499                                 ThisSumX = ThisSumY = (float) 0.0;
00500                                 ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0;
00501                         }
00502                         ThisMinX = ThisMinY = (float) 1000000.0;
00503                         ThisMaxX = ThisMaxY = (float) -1.0;
00504 
00505                         LastPerimeter = ThisPerimeter = (float) 0.0;
00506                         ThisParent = (float) -1;
00507                         ThisExternPerimeter = 0.0;
00508 
00509                         // Determine necessary action and take it
00510                         switch (Case)
00511                         { 
00512                                 case 1: //|xxx    |
00513                                                 //|    yyy|
00514                                         
00515                                         ThisRegion[ThisIndex] = ThisRegionNum;
00516                                         LastRegion[LastIndex] = LastRegionNum;
00517                                         LastIndex++;
00518                                         
00519                                         //afegim la cantonada a LastRegion
00520                                         actualedge.x = ThisEnd;
00521                                         actualedge.y = ThisRow - 1;
00522                                         cvSeqPush(regionDataLastRegion->edges,&actualedge);
00523 
00524                                         //afegim la cantonada a ThisRegion
00525                                         actualedge.x = ThisStart - 1;
00526                                         actualedge.y = ThisRow - 1;
00527                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
00528                                         
00529                                         break;
00530                                         
00531                                         
00532                                 case 2: //|xxxxoo |
00533                                                 //|    yyy|
00534 
00535                                         if(TestMatch)   // Same color
00536                                         {
00537                                                 ThisRegionNum = LastRegionNum;
00538                                                 regionDataThisRegion = regionDataLastRegion;
00539 
00540                                                 ThisArea = ThisEnd - ThisStart + 1;
00541                                                 LastPerimeter = LastEnd - ThisStart + 1;        // to subtract
00542                                                 ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter +
00543                                                                                 PERIMETRE_DIAGONAL*2;
00544 
00545                                                 if( CandidatExterior )
00546                                                 {
00547                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00548                                                                                                                                           inputImage->width, inputImage->height, 
00549                                                                                                                                           imatgePerimetreExtern );
00550                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL*2;
00551                                                 }
00552                                                 ComputeData = 1;
00553                                         }
00554 
00555                                         //afegim la cantonada a ThisRegion
00556                                         if(ThisRegionNum!=-1)
00557                                         {
00558                                                 // afegim dos vertexs si són diferents, només
00559                                                 if(ThisStart - 1 != ThisEnd)
00560                                                 {
00561                                                         actualedge.x = ThisStart - 1;
00562                                                         actualedge.y = ThisRow - 1;
00563                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
00564                                                 }
00565                                                 actualedge.x = ThisEnd;
00566                                                 actualedge.y = ThisRow - 1;
00567                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00568                                         }
00569                                         //afegim la cantonada a ThisRegion
00570                                         if(LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
00571                                         {
00572                                                 // afegim dos vertexs si són diferents, només
00573                                                 if(ThisStart - 1 != ThisEnd)
00574                                                 {
00575                                                         actualedge.x = ThisStart - 1;
00576                                                         actualedge.y = ThisRow - 1;
00577                                                         cvSeqPush(regionDataLastRegion->edges,&actualedge);
00578                                                 }
00579                                         }
00580 
00581                                         ThisRegion[ThisIndex] = ThisRegionNum;
00582                                         LastRegion[LastIndex] = LastRegionNum;
00583                                         LastIndex++;
00584                                         break;
00585                                         
00586                                         
00587                                 case 3: //|xxxxxxx|
00588                                                 //|  yyyy |
00589 
00590                                         if(TestMatch)   // Same color
00591                                         {
00592                                                 ThisRegionNum = LastRegionNum;
00593                                                 regionDataThisRegion = regionDataLastRegion;
00594 
00595                                                 ThisArea = ThisEnd - ThisStart + 1;
00596                                                 LastPerimeter = ThisArea;       // to subtract
00597                                                 ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL*2;
00598                                                 if( CandidatExterior )
00599                                                 {
00600                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00601                                                                                                                                           inputImage->width, inputImage->height, 
00602                                                                                                                                           imatgePerimetreExtern );
00603 
00604                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
00605                                                 }
00606                                         }
00607                                         else            // Different color => New region
00608                                         {
00609                                                 ThisParent = LastRegionNum;
00610                                                 ThisRegionNum = ++HighRegionNum;
00611                                                 ThisArea = ThisEnd - ThisStart + 1;
00612                                                 ThisPerimeter = 2 + 2 * ThisArea;
00613                                                 RegionData.push_back( new CBlob() );
00614                                                 regionDataThisRegion = RegionData.back();
00615 
00616                                                 SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
00617                                                 if( CandidatExterior )
00618                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00619                                                                                                                                           inputImage->width, inputImage->height, 
00620                                                                                                                                           imatgePerimetreExtern );
00621 
00622                                         }
00623 
00624                                         if(ThisRegionNum!=-1)
00625                                         {
00626                                                 //afegim la cantonada a la regio
00627                                                 actualedge.x = ThisStart - 1;
00628                                                 actualedge.y = ThisRow - 1;
00629                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00630                                                 //afegim la cantonada a la regio
00631                                                 actualedge.x = ThisEnd;
00632                                                 actualedge.y = ThisRow - 1;
00633                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00634                                         }
00635                                         // si hem creat un nou blob, afegim tb a l'anterior
00636                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
00637                                         {
00638                                                 //afegim la cantonada a la regio
00639                                                 actualedge.x = ThisStart - 1;
00640                                                 actualedge.y = ThisRow - 1;
00641                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
00642                                                 //afegim la cantonada a la regio
00643                                                 actualedge.x = ThisEnd;
00644                                                 actualedge.y = ThisRow - 1;
00645                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
00646                                         }
00647                                         
00648                                         ThisRegion[ThisIndex] = ThisRegionNum;
00649                                         LastRegion[LastIndex] = LastRegionNum;
00650                                         ComputeData = 1;
00651                                         ThisIndex++;
00652                                         break;
00653                                         
00654                                         
00655                                 case 4: //|xxxxxxx|
00656                                                 //|  yyyyy|
00657                                         
00658                                         if(TestMatch)   // Same color
00659                                         {
00660                                                 ThisRegionNum = LastRegionNum;
00661                                                 regionDataThisRegion = regionDataLastRegion;
00662                                                 ThisArea = ThisEnd - ThisStart + 1;
00663                                                 LastPerimeter = ThisArea;       // to subtract
00664                                                 ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL;
00665                                                 if( CandidatExterior )
00666                                                 {
00667                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00668                                                                                                                                           inputImage->width, inputImage->height, 
00669                                                                                                                                           imatgePerimetreExtern );
00670 
00671                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL;
00672                                                 }
00673                                         }
00674                                         else            // Different color => New region
00675                                         {
00676                                                 ThisParent = LastRegionNum;
00677                                                 ThisRegionNum = ++HighRegionNum;
00678                                                 ThisArea = ThisEnd - ThisStart + 1;
00679                                                 ThisPerimeter = 2 + 2 * ThisArea;
00680                                                 RegionData.push_back( new CBlob() );
00681                                                 regionDataThisRegion = RegionData.back();
00682                                                 SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
00683                                                 if( CandidatExterior )
00684                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00685                                                                                                                                           inputImage->width, inputImage->height, 
00686                                                                                                                                           imatgePerimetreExtern );
00687 
00688                                         }
00689                                         
00690                                         if(ThisRegionNum!=-1)
00691                                         {
00692                                                 //afegim la cantonada a la regio
00693                                                 actualedge.x = ThisStart - 1;
00694                                                 actualedge.y = ThisRow - 1;
00695                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00696                                                 actualedge.x = ThisEnd;
00697                                                 actualedge.y = ThisRow - 1;
00698                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00699                                         }
00700                                         // si hem creat un nou blob, afegim tb a l'anterior
00701                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
00702                                         {
00703                                                 actualedge.x = ThisStart - 1;
00704                                                 actualedge.y = ThisRow - 1;
00705                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
00706                                                 actualedge.x = ThisEnd;
00707                                                 actualedge.y = ThisRow - 1;
00708                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
00709                                         }
00710                                         
00711                                         ThisRegion[ThisIndex] = ThisRegionNum;
00712                                         LastRegion[LastIndex] = LastRegionNum;
00713                                         ComputeData = 1;
00714                                         
00715 #ifdef B_CONNECTIVITAT_8
00716                                         if( TestMatch )
00717                                         {
00718                                                 LastIndex++;
00719                                                 ThisIndex++;
00720                                         }
00721                                         else
00722                                         {
00723                                                 LastIndex++;    
00724                                         }
00725 #else
00726                                         LastIndex++;
00727                                         ThisIndex++;
00728 #endif                                  
00729                                         break;
00730                                         
00731                                         
00732                                 case 5: //|ooxxxxx|
00733                                                 //|yyyyyyy|
00734 
00735                                         if(!TestMatch && !TestKnown)    // Different color and unknown => new region
00736                                         {
00737                                                 ThisParent = LastRegionNum;
00738                                                 ThisRegionNum = ++HighRegionNum;
00739                                                 ThisArea = ThisEnd - ThisStart + 1;
00740                                                 ThisPerimeter = 2 + 2 * ThisArea;
00741                                                 RegionData.push_back( new CBlob() );
00742                                                 regionDataThisRegion = RegionData.back();
00743                                                 SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
00744                                                 if( CandidatExterior )
00745                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00746                                                                                                                                           inputImage->width, inputImage->height, 
00747                                                                                                                                           imatgePerimetreExtern );
00748 
00749                                         }
00750                                         else if(TestMatch && !TestKnown)        // Same color and unknown
00751                                         {
00752                                                 ThisRegionNum = LastRegionNum;
00753                                                 regionDataThisRegion = regionDataLastRegion;
00754                                                 ThisArea = ThisEnd - ThisStart + 1;
00755                                                 LastPerimeter = LastEnd - LastStart + 1;        // to subtract
00756                                                 ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter 
00757                                                                                 + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
00758                                                 if( CandidatExterior )
00759                                                 {
00760                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00761                                                                                                                                           inputImage->width, inputImage->height, 
00762                                                                                                                                           imatgePerimetreExtern );
00763 
00764 
00765                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart);
00766                                                 }
00767                                                 ComputeData = 1;
00768                                         }
00769                                         else if(TestMatch && TestKnown) // Same color and known
00770                                         {
00771                                                 LastPerimeter = LastEnd - LastStart + 1;        // to subtract
00772                                                 //ThisPerimeter = - LastPerimeter;
00773                                                 ThisPerimeter = - 2 * LastPerimeter 
00774                                                                                 + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
00775                                                 
00776                                                 if(ThisRegionNum > LastRegionNum)
00777                                                 {
00778                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
00779                                                                         findmoments, ThisRegionNum, LastRegionNum );
00780                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00781                                                         {
00782                                                                 if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
00783                                                                 if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
00784                                                         }                                       
00785                                                         ThisRegionNum = LastRegionNum;
00786                                                 }
00787                                                 else if(ThisRegionNum < LastRegionNum)
00788                                                 {
00789                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
00790                                                                         findmoments, LastRegionNum, ThisRegionNum );
00791 
00792                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00793                                                         {
00794                                                                 if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
00795                                                                 if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
00796                                                         }                                       
00797                                                         LastRegionNum = ThisRegionNum;
00798                                                 }
00799                                         }
00800 
00801                                         
00802                                         if(ThisRegionNum!=-1)
00803                                         {
00804                                                 actualedge.x = ThisEnd;
00805                                                 actualedge.y = ThisRow - 1;
00806                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00807 
00808                                                 if( ThisStart - 1 != LastEnd )
00809                                                 {
00810                                                         //afegim la cantonada a la regio
00811                                                         actualedge.x = ThisStart - 1;
00812                                                         actualedge.y = ThisRow - 1;
00813                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
00814                                                 }
00815                                         }
00816                                         // si hem creat un nou blob, afegim tb a l'anterior
00817                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
00818                                         {
00819                                                 actualedge.x = ThisEnd;
00820                                                 actualedge.y = ThisRow - 1;
00821                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
00822                                         }
00823 
00824                                         ThisRegion[ThisIndex] = ThisRegionNum;
00825                                         LastRegion[LastIndex] = LastRegionNum;
00826                                         
00827 #ifdef B_CONNECTIVITAT_8
00828                                         if( TestMatch )
00829                                         {
00830                                                 LastIndex++;
00831                                                 ThisIndex++;
00832                                         }
00833                                         else
00834                                         {
00835                                                 LastIndex++;    
00836                                         }
00837 #else
00838                                         LastIndex++;
00839                                         ThisIndex++;
00840 #endif  
00841                                         break;
00842                                         
00843                                         
00844                                 case 6: //|ooxxx  |
00845                                                 //|yyyyyyy|
00846 
00847                                         if(TestMatch && !TestKnown)
00848                                         {
00849                                                 ThisRegionNum = LastRegionNum;
00850                                                 regionDataThisRegion = regionDataLastRegion;
00851                                                 ThisArea = ThisEnd - ThisStart + 1;
00852                                                 LastPerimeter = LastEnd - LastStart + 1;        // to subtract
00853                                                 ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
00854                                                                                 + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00855                                                 if( CandidatExterior )
00856                                                 {
00857                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00858                                                                                                                                           inputImage->width, inputImage->height, 
00859                                                                                                                                           imatgePerimetreExtern );
00860 
00861 
00862                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00863                                                 }
00864                                                 ComputeData = 1;
00865                                         }
00866                                         else if(TestMatch && TestKnown)
00867                                         {
00868                                                 LastPerimeter = LastEnd - LastStart + 1;        // to subtract
00869                                                 //ThisPerimeter = - LastPerimeter;
00870                                                 ThisPerimeter = - 2 * LastPerimeter
00871                                                                                 + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00872                                                 
00873                                                 if(ThisRegionNum > LastRegionNum)
00874                                                 {
00875                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
00876                                                                         findmoments, ThisRegionNum, LastRegionNum );
00877                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00878                                                         {
00879                                                                 if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
00880                                                                 if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
00881                                                         }                                       
00882                                                         ThisRegionNum = LastRegionNum;
00883                                                 }
00884                                                 else if(ThisRegionNum < LastRegionNum)
00885                                                 {
00886                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
00887                                                                         findmoments, LastRegionNum, ThisRegionNum );
00888                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00889                                                         {
00890                                                                 if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
00891                                                                 if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
00892                                                         }                                       
00893                                                         LastRegionNum = ThisRegionNum;
00894                                                 }
00895                                         }
00896 
00897                                         
00898                                         if(ThisRegionNum!=-1)
00899                                         {
00900                                                 //afegim la cantonada a la regio
00901                                                 actualedge.x = ThisEnd;
00902                                                 actualedge.y = ThisRow - 1;
00903                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
00904                                                 if( ThisStart - 1 != LastEnd )
00905                                                 {
00906                                                         actualedge.x = ThisStart - 1;
00907                                                         actualedge.y = ThisRow - 1;
00908                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
00909                                                 }
00910                                         }
00911                                         // si hem creat un nou blob, afegim tb a l'anterior
00912                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
00913                                         {
00914                                                 //afegim la cantonada a la regio
00915                                                 if( ThisStart - 1 != LastEnd )
00916                                                 {
00917                                                         actualedge.x = ThisStart - 1;
00918                                                         actualedge.y = ThisRow - 1;
00919                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
00920                                                 }
00921                                         }                                       
00922 
00923                                         ThisRegion[ThisIndex] = ThisRegionNum;
00924                                         LastRegion[LastIndex] = LastRegionNum;
00925                                         LastIndex++;
00926                                         break;
00927                                         
00928                                         
00929                                 case 7: //|ooxxxxx|
00930                                                 //|yyyy   |
00931 
00932                                         if(!TestMatch && !TestKnown)    // Different color and unknown => new region
00933                                         {
00934                                                 ThisParent = LastRegionNum;
00935                                                 ThisRegionNum = ++HighRegionNum;
00936                                                 ThisArea = ThisEnd - ThisStart + 1;
00937                                                 ThisPerimeter = 2 + 2 * ThisArea;
00938                                                 RegionData.push_back( new CBlob() );
00939                                                 regionDataThisRegion = RegionData.back();
00940                                                 SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
00941                                                 if( CandidatExterior )
00942                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00943                                                                                                                                           inputImage->width, inputImage->height, 
00944                                                                                                                                           imatgePerimetreExtern );
00945 
00946                                         }
00947                                         else if(TestMatch && !TestKnown)
00948                                         {
00949                                                 ThisRegionNum = LastRegionNum;
00950                                                 regionDataThisRegion = regionDataLastRegion;
00951                                                 ThisArea = ThisEnd - ThisStart + 1;
00952                                                 ThisPerimeter = 2 + ThisArea;
00953                                                 LastPerimeter = ThisEnd - LastStart + 1;
00954                                                 ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
00955                                                                                 + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00956                                                 if( CandidatExterior )
00957                                                 {
00958                                                         ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
00959                                                                                                                                           inputImage->width, inputImage->height, 
00960                                                                                                                                           imatgePerimetreExtern );
00961 
00962                                                         ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00963                                                 }
00964                                                 ComputeData = 1;
00965                                         }
00966                                         else if(TestMatch && TestKnown)
00967                                         {
00968                                                 LastPerimeter = ThisEnd - LastStart + 1;        // to subtract
00969                                                 //ThisPerimeter = - LastPerimeter;
00970                                                 ThisPerimeter = - 2 * LastPerimeter
00971                                                                                 + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
00972                                                 
00973                                                 if(ThisRegionNum > LastRegionNum)
00974                                                 {
00975                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
00976                                                                         findmoments, ThisRegionNum, LastRegionNum );
00977                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00978                                                         {
00979                                                                 if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
00980                                                                 if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
00981                                                         }                                       
00982                                                         ThisRegionNum = LastRegionNum;
00983                                                 }
00984                                                 else if(ThisRegionNum < LastRegionNum)
00985                                                 {
00986                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
00987                                                                         findmoments, LastRegionNum, ThisRegionNum );
00988                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
00989                                                         {
00990                                                                 if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
00991                                                                 if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
00992                                                         }                                       
00993                                                         LastRegionNum = ThisRegionNum;
00994                                                 }
00995                                         }
00996 
00997                                         if(ThisRegionNum!=-1)
00998                                         {
00999                                                 //afegim la cantonada a la regio
01000                                                 actualedge.x = ThisEnd;
01001                                                 actualedge.y = ThisRow - 1;
01002                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
01003                                                 if( ThisStart - 1 != LastEnd )
01004                                                 {
01005                                                         actualedge.x = ThisStart - 1;
01006                                                         actualedge.y = ThisRow - 1;
01007                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
01008                                                 }
01009                                         }
01010                                         // si hem creat un nou blob, afegim tb a l'anterior
01011                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
01012                                         {
01013                                                 //afegim la cantonada a la regio
01014                                                 actualedge.x = ThisEnd;
01015                                                 actualedge.y = ThisRow - 1;
01016                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
01017                                                 if( ThisStart - 1 != LastEnd )
01018                                                 {
01019                                                         actualedge.x = ThisStart - 1;
01020                                                         actualedge.y = ThisRow - 1;
01021                                                         cvSeqPush(regionDataThisRegion->edges,&actualedge);
01022                                                 }
01023                                         }
01024 
01025                                         ThisRegion[ThisIndex] = ThisRegionNum;
01026                                         LastRegion[LastIndex] = LastRegionNum;
01027                                         ThisIndex++;
01028                                         break;
01029                                         
01030                                 case 8: //|    xxx|
01031                                                 //|yyyy   |
01032                                         
01033 #ifdef B_CONNECTIVITAT_8                                        
01034                                         // fusionem blobs
01035                                         if( TestMatch )
01036                                         {
01037                                                 if(ThisRegionNum > LastRegionNum)
01038                                                 {
01039                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
01040                                                                         findmoments, ThisRegionNum, LastRegionNum );
01041                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
01042                                                         {
01043                                                                 if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
01044                                                                 if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
01045                                                         }                                       
01046                                                         ThisRegionNum = LastRegionNum;
01047                                                 }
01048                                                 else if(ThisRegionNum < LastRegionNum)
01049                                                 {
01050                                                         Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
01051                                                                         findmoments, LastRegionNum, ThisRegionNum );
01052                                                         for(int iOld = 0; iOld < MaxIndexCount; iOld++)
01053                                                         {
01054                                                                 if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
01055                                                                 if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
01056                                                         }                                       
01057                                                         LastRegionNum = ThisRegionNum;
01058                                                 }
01059 
01060                                                 regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL*2;
01061                                         }
01062 #endif
01063 
01064                                         if(ThisRegionNum!=-1)
01065                                         {
01066                                                 //afegim la cantonada a la regio
01067                                                 actualedge.x = ThisStart - 1;
01068                                                 actualedge.y = ThisRow - 1;
01069                                                 cvSeqPush(regionDataThisRegion->edges,&actualedge);
01070                                         }
01071 #ifdef B_CONNECTIVITAT_8                                        
01072                                         // si hem creat un nou blob, afegim tb a l'anterior
01073                                         if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
01074                                         {
01075 #endif                                  
01076                                                 //afegim la cantonada a la regio
01077                                                 actualedge.x = ThisStart - 1;
01078                                                 actualedge.y = ThisRow - 1;
01079                                                 cvSeqPush(regionDataLastRegion->edges,&actualedge);
01080 #ifdef B_CONNECTIVITAT_8
01081                                         }
01082 #endif
01083 
01084                                         ThisRegion[ThisIndex] = ThisRegionNum;
01085                                         LastRegion[LastIndex] = LastRegionNum;
01086                                         ThisIndex++;
01087 #ifdef B_CONNECTIVITAT_8                                        
01088                                         LastIndex--;
01089 #endif
01090                                         break;
01091                                         
01092                                 default:
01093                                         ErrorFlag = -1;
01094                         }       // end switch case
01095 
01096                         // calculate the blob moments and mean gray level of the current blob (ThisRegionNum)
01097                         if(ComputeData > 0)
01098                         {
01099                                 // compute blob moments if necessary
01100                                 if(findmoments)
01101                                 {
01102                                         float ImageRow = (float) (ThisRow - 1);
01103 
01104                                         for(int k = ThisStart; k <= ThisEnd; k++)
01105                                         {
01106                                                 ThisSumX += (float) (k - 1);
01107                                                 ThisSumXX += (float) (k - 1) * (k - 1);
01108                                         }
01109                                         
01110                                         ThisSumXY = ThisSumX * ImageRow;
01111                                         ThisSumY = ThisArea * ImageRow;
01112                                         ThisSumYY = ThisSumY * ImageRow;
01113                                         
01114                                 }
01115 
01116                                 // compute the mean gray level and its std deviation 
01117                                 if(ThisRow <= Rows )
01118                                 {
01119                                         pImageAux = pImage + ThisStart;
01120                                         if(maskImage!=NULL) pMaskAux = pMask + ThisStart;
01121                                         for(int k = ThisStart; k <= ThisEnd; k++)
01122                                         {
01123                                                 if((k>0) && (k <= Cols))
01124                                                 {
01125                                                         if( maskImage!= NULL)
01126                                                         {
01127                                                                 // només es té en compte el valor del píxel de la
01128                                                                 // imatge que queda dins de la màscara
01129                                                                 // (de pas, comptem el nombre de píxels de la màscara)
01130                                                                 if( ((unsigned char) *pMaskAux) != PIXEL_EXTERIOR )
01131                                                                 {
01132                                                                         imagevalue = (unsigned char) (*pImageAux);
01133                                                                         regionDataThisRegion->mean+=imagevalue;
01134                                                                         regionDataThisRegion->stddev+=imagevalue*imagevalue;
01135                                                                 }
01136                                                                 else
01137                                                                 {
01138                                                                         nombre_pixels_mascara++;
01139                                                                 }
01140                                                         }
01141                                                         else
01142                                                         {
01143                                                                 imagevalue = (unsigned char) (*pImageAux);
01144                                                                 regionDataThisRegion->mean+=imagevalue;
01145                                                                 regionDataThisRegion->stddev+=imagevalue*imagevalue;
01146 
01147                                                         }
01148                                                 }
01149                                                 pImageAux++;
01150                                                 if(maskImage!=NULL) pMaskAux++;
01151                                         }
01152                                 }
01153 
01154                                 // compute the min and max values of X and Y
01155                                 if(ThisStart - 1 < (int) ThisMinX) ThisMinX = (float) (ThisStart - 1);
01156                                 if(ThisMinX < (float) 0.0) ThisMinX = (float) 0.0;
01157                                 if(ThisEnd > (int) ThisMaxX) ThisMaxX = (float) ThisEnd;
01158 
01159                                 if(ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1;
01160                                 if(ThisMinY < (float) 0.0) ThisMinY = (float) 0.0;
01161                                 if(ThisRow > ThisMaxY) ThisMaxY = ThisRow;
01162                         }
01163 
01164                         // put the current results into RegionData
01165                         if(ThisRegionNum >= 0)
01166                         {
01167                                 if(ThisParent >= 0) { regionDataThisRegion->parent = (int) ThisParent; }
01168                                 regionDataThisRegion->etiqueta = ThisRegionNum;
01169                                 regionDataThisRegion->area += ThisArea;
01170                                 regionDataThisRegion->perimeter += ThisPerimeter;
01171                                 regionDataThisRegion->externPerimeter += ThisExternPerimeter;
01172                                 
01173                                 if(ComputeData > 0)
01174                                 {
01175                                         if(findmoments)
01176                                         {
01177                                                 regionDataThisRegion->sumx += ThisSumX;
01178                                                 regionDataThisRegion->sumy += ThisSumY;
01179                                                 regionDataThisRegion->sumxx += ThisSumXX;
01180                                                 regionDataThisRegion->sumyy += ThisSumYY;
01181                                                 regionDataThisRegion->sumxy += ThisSumXY;
01182                                         }
01183                                         regionDataThisRegion->perimeter -= LastPerimeter;
01184                                         regionDataThisRegion->minx=MIN(regionDataThisRegion->minx,ThisMinX);
01185                                         regionDataThisRegion->maxx=MAX(regionDataThisRegion->maxx,ThisMaxX);
01186                                         regionDataThisRegion->miny=MIN(regionDataThisRegion->miny,ThisMinY);
01187                                         regionDataThisRegion->maxy=MAX(regionDataThisRegion->maxy,ThisMaxY);
01188                                 }
01189                                 // blobs externs
01190                                 if( CandidatExterior )
01191                                 {
01192                                         regionDataThisRegion->exterior = true;
01193                                 }
01194                         
01195                         }
01196                 }       // end Main loop
01197 
01198                 if(ErrorFlag != 0) return false;
01199                 // ens situem al primer pixel de la seguent fila
01200                 pImage = inputImage->imageData - 1 + startCol + (ThisRow+startRow) * inputImage->widthStep;
01201 
01202                 if(maskImage!=NULL)
01203                         pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep;
01204         }       // end Loop over all rows
01205 
01206         // eliminem l'àrea del marc
01207         // i també els píxels de la màscara
01208         // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del
01209         // blob 0 només serà cert si la màscara té contacte amb el marc.
01210         // Si no, s'haurà de trobar quin és el blob que conté més píxels del
01211         // compte.
01212         RegionData[0]->area -= ( Rows + 1 + Cols + 1 )*2 + nombre_pixels_mascara;
01213 
01214         // eliminem el perímetre de més:
01215         // - sense marc: 2m+2n (perímetre extern)
01216         // - amb marc:   2(m+2)+2(n+2) = 2m+2n + 8
01217         // (segurament no és del tot acurat)
01218         // (i amb les màscares encara menys...)
01219         RegionData[0]->perimeter -= 8.0;
01220 
01221         // Condense the list
01222         blob_vector::iterator itNew, itOld, iti;
01223         CBlob *blobActual;
01224 
01225         itNew = RegionData.begin();
01226         itOld = RegionData.begin();
01227         int iNew = 0;
01228         for(int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++)
01229         {
01230                 if(SubsumedRegion[iOld] < 1)    // This number not subsumed
01231                 {
01232                         // Move data from old region number to new region number
01233                         //*RegionData[iNew] = *RegionData[iOld];
01234                         **itNew = **itOld;
01235                         
01236                         // Update and parent pointer if necessary
01237                         iti = RegionData.begin();
01238                         for(int i = 0; i <= HighRegionNum; i++)
01239                         {
01240                                 //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; }
01241                                 if((*iti)->parent == iOld) { (*iti)->parent = iNew; }
01242 
01243                                 iti++;
01244                         }
01245                         iNew++;
01246                         itNew++;
01247                 }       
01248         }
01249 
01250 
01251         HighRegionNum = iNew - 1;                               // Update where the data ends
01252         RegionData[HighRegionNum]->parent = -1; // and set end of array flag
01253 
01254 
01255         if(findmoments)
01256         {
01257                 iti = RegionData.begin();
01258                 // Normalize summation fields into moments 
01259                 for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
01260                 {
01261                         blobActual = *iti;
01262 
01263                         // Get averages
01264                         blobActual->sumx /= blobActual->area;
01265                         blobActual->sumy /= blobActual->area;
01266                         blobActual->sumxx /= blobActual->area;
01267                         blobActual->sumyy /= blobActual->area;
01268                         blobActual->sumxy /= blobActual->area;
01269 
01270                         // Create moments
01271                         blobActual->sumxx -= blobActual->sumx * blobActual->sumx;
01272                         blobActual->sumyy -= blobActual->sumy * blobActual->sumy;
01273                         blobActual->sumxy -= blobActual->sumx * blobActual->sumy;
01274                         if(blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14)
01275                         {
01276                                 blobActual->sumxy = (float) 0.0; // Eliminate roundoff error
01277                         }
01278                         
01279                 }
01280         }
01281 
01282         //Get the real mean and std deviation
01283         iti = RegionData.begin();
01284         for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
01285         {
01286                 blobActual = *iti;
01287                 if(blobActual->area > 1)
01288                 {
01289                         blobActual->stddev =
01290                                                                 sqrt(
01291                                                                 (
01292                                                                 blobActual->stddev * blobActual->area -
01293                                                                 blobActual->mean * blobActual->mean 
01294                                                                 )/
01295                                                                 (blobActual->area*(blobActual->area-1))
01296                                                                 );
01297                 }
01298                 else
01299                         blobActual->stddev=0;
01300                 
01301                 if(blobActual->area > 0)
01302                         blobActual->mean/=blobActual->area;
01303                 else
01304                         blobActual->mean = 0;
01305         
01306         }
01307         // eliminem els blobs subsumats
01308         blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1;
01309         while( itBlobs != RegionData.end() )
01310         {
01311                 delete *itBlobs;
01312                 //RegionData.erase( itBlobs );
01313                 itBlobs++;
01314         }
01315         RegionData.erase( RegionData.begin() + HighRegionNum + 1, RegionData.end() );
01316 
01317         //free(RegionData);
01318         free(SubsumedRegion);
01319         delete Transition;
01320         delete ThisRegion;
01321         delete LastRegion;
01322 
01323         if( imatgePerimetreExtern ) cvReleaseImage(&imatgePerimetreExtern);
01324 
01325         return true;
01326 }
01327 
01328 
01329 int *NewSubsume(int *subsumed, int index_subsume)
01330 {
01331         if( index_subsume == 0 )
01332         {
01333                 subsumed = (int*)malloc(sizeof(int));
01334         }
01335         else
01336         {
01337                 subsumed = (int*)realloc(subsumed,(index_subsume+1)*sizeof(int));
01338         }
01339         subsumed[index_subsume]=0;
01340         return subsumed;
01341 }
01342 
01347 void Subsume(blob_vector &RegionData,
01348                         int HighRegionNum,
01349                         int* SubsumedRegion,
01350                         CBlob* blobHi,
01351                         CBlob* blobLo,
01352                         bool findmoments,
01353                         int HiNum,
01354                         int LoNum)
01355 {
01356         // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging
01357 
01358         int i;
01359         
01360         blobLo->minx=MIN(blobHi->minx,blobLo->minx);
01361         blobLo->miny=MIN(blobHi->miny,blobLo->miny);
01362         blobLo->maxx=MAX(blobHi->maxx,blobLo->maxx);
01363         blobLo->maxy=MAX(blobHi->maxy,blobLo->maxy);
01364         blobLo->area+=blobHi->area;     
01365         blobLo->perimeter+=blobHi->perimeter;
01366         blobLo->externPerimeter += blobHi->externPerimeter;
01367         blobLo->exterior = blobLo->exterior || blobHi->exterior;
01368         blobLo->mean += blobHi->mean;
01369         blobLo->stddev += blobHi->stddev;       
01370         
01371         if( findmoments )
01372         {
01373                 blobLo->sumx+=blobHi->sumx;     
01374                 blobLo->sumy+=blobHi->sumy;     
01375                 blobLo->sumxx+=blobHi->sumxx;   
01376                 blobLo->sumyy+=blobHi->sumyy;   
01377                 blobLo->sumxy+=blobHi->sumxy;
01378         }
01379         // Make sure no region still has subsumed region as parent
01380         blob_vector::iterator it = (RegionData.begin() + HiNum + 1);
01381 
01382         for(i = HiNum + 1; i <= HighRegionNum; i++, it++)
01383         {
01384                 if((*it)->parent == (float) HiNum) { (*it)->parent = LoNum; }
01385         }
01386 
01387         // Mark dead region number for future compression
01388         SubsumedRegion[HiNum] = 1;
01389         // marquem el blob com a lliure
01390         blobHi->etiqueta=-1;
01391 
01392         // Atenció!!!! abans d'eliminar els edges 
01393         // s'han de traspassar del blob HiNum al blob LoNum
01394         blobHi->CopyEdges( *blobLo );
01395         blobHi->ClearEdges();
01396 }
01397 
01414 double GetExternPerimeter( int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern )
01415 {
01416         double perimeter = 0.0f;
01417         char *pPerimetre;
01418 
01419 
01420         // comprovem les dimensions de la imatge
01421         perimeter += ( start <= 0 ) + ( end >= width - 1 );
01422         if(row <= 1 ) perimeter+= start - end;
01423         if(row >= height - 1 ) perimeter+= start - end;
01424 
01425 
01426         // comprovem els pixels que toquen a la màscara (si s'escau)
01427         if( imatgePerimetreExtern != NULL )
01428         {
01429                 if( row <= 0 || row >= height ) return perimeter;
01430 
01431                 if( start < 0 ) start = 1;
01432                 if( end >= width ) end = width - 2;
01433                 
01434                 pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start;
01435                 for (int x = start - 1; x <= end; x++ )
01436                 {
01437                         perimeter += *pPerimetre;
01438                         pPerimetre++;
01439                 }
01440         }
01441         
01442         return perimeter;
01443 }

Generated on Mon Nov 13 13:32:49 2006 for cvBlobsLib by  doxygen 1.5.1-p1