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 }