Пример #1
0
bool BoundAtomicConstraint::Subsume(BoundConstraint* that) const
{
    if (that->IsBinaryConstraint())
    {
        BoundBinaryConstraint* thatBinaryConstraint = static_cast<BoundBinaryConstraint*>(that);
        BoundConstraint* thatLeft = thatBinaryConstraint->Left();
        BoundConstraint* thatRight = thatBinaryConstraint->Right();
        bool subsumeLeft = Subsume(thatLeft);
        bool subsumeRight = Subsume(thatRight);
        if (that->IsConjunctiveConstraint())
        {
            return subsumeLeft && subsumeRight;
        }
        else if (that->IsDisjunctiveConstraint())
        {
            return subsumeLeft || subsumeRight;
        }
        else // assert(false)
        {
            return false;
        }
    }
    else if (that->IsAtomicConstraint())
    {
        BoundAtomicConstraint* thatAtomic = static_cast<BoundAtomicConstraint*>(that);
        if (satisfied && !thatAtomic->Satisfied())
        {
            return true;
        }
        else if (!satisfied && thatAtomic->Satisfied())
        {
            return false;
        }
        else
        {
            if (concept && !thatAtomic->concept)
            {
                return true;
            }
            else if (!concept && thatAtomic->concept)
            {
                return false;
            }
            else if (!concept && !thatAtomic->concept)
            {
                return true;
            }
            else 
            {
                if (concept == thatAtomic->concept)
                {
                    return true;
                }
                Cm::Sym::ConceptSymbol* refinedConcept = concept->RefinedConcept();
                while (refinedConcept)
                {
                    if (refinedConcept == thatAtomic->concept)
                    {
                        return true;
                    }
                    else
                    {
                        refinedConcept = refinedConcept->RefinedConcept();
                    }
                }
                return false;
            }
        }
    }
    else
    {
        return false;
    }
}
Пример #2
0
/**
- FUNCI? BlobAnalysis
- FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal
- PARÀMETRES:
	- inputImage: Imatge d'entrada. Ha de ser d'un sol canal
	- threshold: Nivell de gris per considerar un pixel blanc o negre
	- maskImage: Imatge de màscara fora de la cual no es calculen els blobs. A més,
				 els blobs que toquen els pixels de la màscara a 0, són considerats
				 externs
	- borderColor: Color del marc de la imatge (0=black or 1=white)
	- findmoments: calcula els moments dels blobs o no
	- RegionData: on es desar?el resultat
- RESULTAT:
	- retorna true si tot ha anat b? false si no. Deixa el resultat a blobs.
- RESTRICCIONS:
	- La imatge d'entrada ha de ser d'un sol canal
- AUTOR: [email protected]
- DATA DE CREACI? 25-05-2005.
- MODIFICACI? Data. Autor. Descripci?
	- [email protected], [email protected]: adaptaci?a les OpenCV
*/
bool BlobAnalysis(	IplImage* inputImage,
					int threshold,
				    IplImage* maskImage,
				    bool borderColor,
				    bool findmoments,
					vector<CBlob*> &RegionData )	
{
	
	// dimensions of input image taking in account the ROI
	int Cols, Rows, startCol, startRow;

	if( inputImage->roi )
	{
		CvRect imageRoi = cvGetImageROI( inputImage );
		startCol = imageRoi.x;
		startRow = imageRoi.y;
		Cols = imageRoi.width;
		Rows = imageRoi.height;
	}
	else
	{
		startCol = 0;
		startRow = 0; 
		Cols = inputImage->width;
		Rows = inputImage->height;
	}

	int Trans = Cols;				// MAX trans in any row
	char* pMask;
	char* pImage;

	// Convert image array into transition array. In each row
	// the transition array tells which columns have a color change
	int iCol,iRow,iTran, Tran;				// Data for a given run
	bool ThisCell, LastCell;		// Contents (colors (0 or 1)) within this row
	int TransitionOffset = 0;		// Performance booster to avoid multiplication
	
	// row 0 and row Rows+1 represent the border
	int i;
	int *Transition;				// Transition Matrix

	int nombre_pixels_mascara = 0;
	//! Imatge amb el perimetre extern de cada pixel
	IplImage *imatgePerimetreExtern;

	// input images must have only 1-channel and be an image
	if( !CV_IS_IMAGE( inputImage ) || (inputImage->nChannels != 1) )
	{
		return false;
	}
	if( maskImage != NULL )
	{
		// input image and mask are a valid image?
		if( !CV_IS_IMAGE( inputImage ) || !CV_IS_IMAGE( maskImage )) 
			return false;

		// comprova que la màscara tingui les mateixes dimensions que la imatge
		if( inputImage->width != maskImage->width || inputImage->height !=
maskImage->height ) 

		// comprova que la màscara sigui una imatge d'un sol canal (grayscale)
		if( maskImage->nChannels != 1 )
		{
			return false;
		}
		
	}

	// Initialize Transition array
	Transition=new int[(Rows + 2)*(Cols + 2)];
	memset(Transition,0,(Rows + 2) * (Cols + 2)*sizeof(int));
	Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2;
	
	// Start at the beginning of the image (startCol, startRow)
	pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep;

/*
	Paral·lelitzaci?del càlcul de la matriu de transicions
	Fem que cada iteraci?del for el faci un thread o l'altre ( tenim 2 possibles threads )	
*/
	if(maskImage == NULL)
	{
		imatgePerimetreExtern = NULL;

		//Fill Transition array
		for(iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
		{
			TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable
			iTran = 0;					// Index into Transition array
			Tran = 0;					// No transitions at row start
			LastCell = borderColor;

			for(iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
			{
				if(iCol == 0 || iCol == Cols+1) 
					ThisCell = borderColor;
				else
					ThisCell = ((unsigned char) *(pImage)) > threshold;

				if(ThisCell != LastCell)
				{
					Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
					iTran++;						// Prepare new index
					LastCell = ThisCell;			// With this color
				}

				Tran++;	// Tran continues
				pImage++;
			}
			
			Transition[TransitionOffset + iTran] = Tran;	// Save completed run
			if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
			{
				Transition[TransitionOffset + iTran + 1] = -1;
			}
			//jump to next row (beginning from (startCol, startRow))
			pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
		}
	}
	else
	{
		//maskImage not NULL: Cal recòrrer la màscara tamb?per calcular la matriu de transicions

		char perimeter;
		char *pPerimetre;
		
		// creem la imatge que contindr?el perimetre extern de cada pixel
		imatgePerimetreExtern = cvCreateImage( cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1);
		cvSetZero( imatgePerimetreExtern );

		pMask = maskImage->imageData - 1;
		
		//Fill Transition array
		for(iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
		{
			TransitionOffset = iRow*(Cols + 2);
			iTran = 0;					// Index into Transition array
			Tran = 0;					// No transitions at row start
			LastCell = borderColor;

			pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep;
			//pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep;

			for(iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
			{
				if(iCol == 0 || iCol == Cols+1 || ((unsigned char) *pMask) == PIXEL_EXTERIOR) 
					ThisCell = borderColor;
				else
					ThisCell = ((unsigned char) *(pImage)) > threshold;

				if(ThisCell != LastCell)
				{
					Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
					iTran++;						// Prepare new index
					LastCell = ThisCell;			// With this color
				}

				/*////////////////////////////////////////////////////////////////////////
				Calcul de la imatge amb els pixels externs
				////////////////////////////////////////////////////////////////////////*/
				// pels pixels externs no cal calcular res pq no hi accedir-hem
				if( (iCol > 0) && (iCol < Cols) )
				{
					if( *pMask == PIXEL_EXTERIOR )
					{
						*pPerimetre = 0;
					}
					else
					{
						perimeter = 0;
						
						// pixels al nord de l'actual
						if(iRow>1)
						{
							if( *(pMask - maskImage->widthStep ) == PIXEL_EXTERIOR) perimeter++;
						}

						// pixels a l'est i oest de l'actual
						if( iRow < imatgePerimetreExtern->height )
						{
							if( (iCol>0) && (*(pMask-1) == PIXEL_EXTERIOR) ) perimeter++;

							if( ( iCol < imatgePerimetreExtern->width - 1) && (*(pMask+1) == PIXEL_EXTERIOR) ) perimeter++;
						}

						// pixels al sud de l'actual
						if( iRow < imatgePerimetreExtern->height - 1)
						{
							if( (*(pMask+maskImage->widthStep) == PIXEL_EXTERIOR) ) perimeter++;
						}
				
						*pPerimetre = perimeter;
					}
				}

				Tran++;	// Tran continues
				pImage++;
				pMask++;
				pPerimetre++;
			}
			Transition[TransitionOffset + iTran] = Tran;	// Save completed run

			if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
			{
				Transition[TransitionOffset + iTran + 1] = -1;
			}

			
			//jump to next row (beginning from (startCol, startRow))
			pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
			//the mask should be the same size as image Roi, so don't take into account the offset
			pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep;
		}
	}

	// Process transition code depending on Last row and This row
	//
	// Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++---
	// This -----+++-----++++----+++++++++----+++++++---++------------------++++++++--
	//
	// There are various possibilities:
	//
	// Case     1       2       3       4       5       6       7       8
	// Last |xxx    |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx  |ooxxxxx|    xxx|
	// This |    yyy|    yyy|  yyyy |  yyyyy|yyyyyyy|yyyyyyy|yyyy   |yyyy   |
	// Here o is optional
	// 
	// Here are the primitive tests to distinguish these 6 cases:
	//   A) Last end < This start - 1 OR NOT		Note: -1
	//   B) This end < Last start OR NOT
	//   C) Last start < This start OR NOT
	//   D) This end < Last end OR NOT
	//   E) This end = Last end OR NOT
	//
	// Here is how to use these tests to determine the case:
	//   Case 1 = A [=> NOT B AND C AND NOT D AND NOT E]
	//   Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B]
	//   Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B]
	//   Case 4 = C AND NOT D AND E [AND NOT A AND NOT B]
	//   Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B]
	//   Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B]
	//   Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B]
	//   Case 8 = B [=> NOT A AND NOT C AND D AND NOT E]
	//
	// In cases 2,3,4,5,6,7 the following additional test is needed:
	//   Match) This color = Last color OR NOT
	//
	// In cases 5,6,7 the following additional test is needed:
	//   Known) This region was already matched OR NOT
	//
	// Here are the main tests and actions:
	//   Case 1: LastIndex++;
	//   Case 2: if(Match) {y = x;}
	//           LastIndex++;
	//   Case 3: if(Match) {y = x;}
	//           else {y = new}
	//           ThisIndex++;
	//   Case 4: if(Match) {y = x;}
	//           else {y = new}
	//           LastIndex++;
	//           ThisIndex++;
	//   Case 5: if(Match AND NOT Known) {y = x}
	//           else if(Match AND Known) {Subsume(x,y)}
	//           LastIndex++;ThisIndex++
	//   Case 6: if(Match AND NOT Known) {y = x}
	//           else if(Match AND Known) {Subsume(x,y)}
	//           LastIndex++;
	//   Case 7: if(Match AND NOT Known) {y = x}
	//           else if(Match AND Known) {Subsume(x,y)}
	//           ThisIndex++;
	//   Case 8: ThisIndex++;

	int *SubsumedRegion = NULL;			
	
	double ThisParent;	// These data can change when the line is current
	double ThisArea;
	double ThisPerimeter;
	double Thisu10;
	double Thisu01;
	double Thisu20;
	double Thisu02;
	double Thisu11;
	double ThisMinX;
	double ThisMaxX;
	double ThisMinY;
	double ThisMaxY;
	double LastPerimeter;	// This is the only data for retroactive change
	double ThisExternPerimeter;
	
	int HighRegionNum = 0;
	int RegionNum = 0;
	int ErrorFlag = 0;
	
	int LastRow, ThisRow;			// Row number
	int LastStart, ThisStart;		// Starting column of run
	int LastEnd, ThisEnd;			// Ending column of run
	int LastColor, ThisColor;		// Color of run
	
	int LastIndex, ThisIndex;		// Which run are we up to
	int LastIndexCount, ThisIndexCount;	// Out of these runs
	int LastRegionNum, ThisRegionNum;	// Which assignment
	int *LastRegion;				// Row assignment of region number
	int *ThisRegion;		// Row assignment of region number
	
	int LastOffset = -(Trans + 2);	// For performance to avoid multiplication
	int ThisOffset = 0;				// For performance to avoid multiplication
	int ComputeData;

	CvPoint actualedge;
	uchar imagevalue;
	bool CandidatExterior = false;

	// apuntadors als blobs de la regi?actual i last
	CBlob *regionDataThisRegion, *regionDataLastRegion;
	
	LastRegion=new int[Cols+2];
	ThisRegion=new int[Cols+2];

	for(i = 0; i < Cols + 2; i++)	// Initialize result arrays
	{
		LastRegion[i] = -1;
		ThisRegion[i] = -1;
	}

	//create the external blob
	RegionData.push_back( new CBlob() );
	SubsumedRegion = NewSubsume(SubsumedRegion,0);
	RegionData[0]->Parent = -1;
	RegionData[0]->Area = (double) Transition[0];
	RegionData[0]->Perimeter = (double) (2 + 2 * Transition[0]);

	ThisIndexCount = 1;
	ThisRegion[0] = 0;	// Border region

	// beginning of the image 
	// en cada linia, pimage apunta al primer pixel de la fila
	pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep;
	//the mask should be the same size as image Roi, so don't take into account the offset
	if(maskImage!=NULL) pMask = maskImage->imageData - 1;

	char *pImageAux, *pMaskAux;
	
	// Loop over all rows
	for(ThisRow = 1; ThisRow < Rows + 2; ThisRow++)
	{
		//cout << "========= THIS ROW = " << ThisRow << endl;	// for debugging
		ThisOffset += Trans + 2;
		ThisIndex = 0;
		LastOffset += Trans + 2;;
		LastRow = ThisRow - 1;
		LastIndexCount = ThisIndexCount;
		LastIndex = 0;

		int EndLast = 0;
		int EndThis = 0;

		for(int j = 0; j < Trans + 2; j++)
		{
			int Index = ThisOffset + j;
			int TranVal = Transition[Index];
			if(TranVal > 0) ThisIndexCount = j + 1;	// stop at highest 

			if(ThisRegion[j] == -1)  { EndLast = 1; }
			if(TranVal < 0) { EndThis = 1; }

			if(EndLast > 0 && EndThis > 0) { break; }

			LastRegion[j] = ThisRegion[j];
			ThisRegion[j] = -1;		// Flag indicates region is not initialized
		}

		int MaxIndexCount = LastIndexCount;
		if(ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount;

		// Main loop over runs within Last and This rows
		while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount)
		{
			ComputeData = 0;
		
			if(LastIndex == 0) LastStart = 0;
			else LastStart = Transition[LastOffset + LastIndex - 1];
			LastEnd = Transition[LastOffset + LastIndex] - 1;
			LastColor = LastIndex - 2 * (LastIndex / 2);
			LastRegionNum = LastRegion[LastIndex];

			regionDataLastRegion = RegionData[LastRegionNum];

			
			if(ThisIndex == 0) ThisStart = 0;
			else ThisStart = Transition[ThisOffset + ThisIndex - 1];
			ThisEnd = Transition[ThisOffset + ThisIndex] - 1;
			ThisColor = ThisIndex - 2 * (ThisIndex / 2);
			ThisRegionNum = ThisRegion[ThisIndex];

			if( ThisRegionNum >= 0 )
				regionDataThisRegion = RegionData[ThisRegionNum];
			else
				regionDataThisRegion = NULL;


			// blobs externs
			CandidatExterior = false;
			if( 
#if !IMATGE_CICLICA_VERTICAL
				ThisRow == 1 || ThisRow == Rows ||
#endif
#if !IMATGE_CICLICA_HORITZONTAL
				ThisStart <= 1 || ThisEnd >= Cols || 
#endif				
				GetExternPerimeter( ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern )
				)
			{
				CandidatExterior = true;
			}
			
			int TestA = (LastEnd < ThisStart - 1);	// initially false
			int TestB = (ThisEnd < LastStart);		// initially false
			int TestC = (LastStart < ThisStart);	// initially false
			int TestD = (ThisEnd < LastEnd);
			int TestE = (ThisEnd == LastEnd);

			int TestMatch = (ThisColor == LastColor);		// initially true
			int TestKnown = (ThisRegion[ThisIndex] >= 0);	// initially false

			int Case = 0;
			if(TestA) Case = 1;
			else if(TestB) Case = 8;
			else if(TestC)
			{
				if(TestD) Case = 3;
				else if(!TestE) Case = 2;
				else Case = 4;
			}
			else
			{
				if(TestE) Case = 5;
				else if(TestD) Case = 7;
				else Case = 6;
			}

			// Initialize common variables
			ThisArea = (float) 0.0;

			if(findmoments)
			{
				Thisu10 = Thisu01 = (float) 0.0;
				Thisu20 = Thisu02 = Thisu11 = (float) 0.0;
			}
			ThisMinX = ThisMinY = (float) 1000000.0;
			ThisMaxX = ThisMaxY = (float) -1.0;

			LastPerimeter = ThisPerimeter = (float) 0.0;
			ThisParent = (float) -1;
			ThisExternPerimeter = 0.0;

			// Determine necessary action and take it
			switch (Case)
			{ 
				case 1: //|xxx    |
						//|    yyy|
					
					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					LastIndex++;
					
					//afegim la cantonada a LastRegion
					actualedge.x = ThisEnd;
					actualedge.y = ThisRow - 1;
					cvSeqPush(regionDataLastRegion->Edges,&actualedge);

					//afegim la cantonada a ThisRegion
					actualedge.x = ThisStart - 1;
					actualedge.y = ThisRow - 1;
					cvSeqPush(regionDataThisRegion->Edges,&actualedge);
					
					break;
					
					
				case 2: //|xxxxoo |
						//|    yyy|

					if(TestMatch)	// Same color
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;

						ThisArea = ThisEnd - ThisStart + 1;
						LastPerimeter = LastEnd - ThisStart + 1;	// to subtract
						ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter +
										PERIMETRE_DIAGONAL*2;

						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );
							ThisExternPerimeter += PERIMETRE_DIAGONAL*2;
						}
						ComputeData = 1;
					}

					//afegim la cantonada a ThisRegion
					if(ThisRegionNum!=-1)
					{
						// afegim dos vertexs si són diferents, només
						if(ThisStart - 1 != ThisEnd)
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
					}
					//afegim la cantonada a ThisRegion
					if(LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						// afegim dos vertexs si són diferents, només
						if(ThisStart - 1 != ThisEnd)
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataLastRegion->Edges,&actualedge);
						}
					}

					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					LastIndex++;
					break;
					
					
				case 3: //|xxxxxxx|
						//|  yyyy |

					if(TestMatch)	// Same color
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;

						ThisArea = ThisEnd - ThisStart + 1;
						LastPerimeter = ThisArea;	// to subtract
						ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL*2;
						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

							ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
						}
					}
					else		// Different color => New region
					{
						ThisParent = LastRegionNum;
						ThisRegionNum = ++HighRegionNum;
						ThisArea = ThisEnd - ThisStart + 1;
						ThisPerimeter = 2 + 2 * ThisArea;
						RegionData.push_back( new CBlob() );
						regionDataThisRegion = RegionData.back();

						SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
						if( CandidatExterior )
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

					}

					if(ThisRegionNum!=-1)
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						//afegim la cantonada a la regio
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
					}
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
						//afegim la cantonada a la regio
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
					}
					
					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					ComputeData = 1;
					ThisIndex++;
					break;
					
					
				case 4:	//|xxxxxxx|
						//|  yyyyy|
					
					if(TestMatch)	// Same color
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;
						ThisArea = ThisEnd - ThisStart + 1;
						LastPerimeter = ThisArea;	// to subtract
						ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL;
						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

							ThisExternPerimeter += PERIMETRE_DIAGONAL;
						}
					}
					else		// Different color => New region
					{
						ThisParent = LastRegionNum;
						ThisRegionNum = ++HighRegionNum;
						ThisArea = ThisEnd - ThisStart + 1;
						ThisPerimeter = 2 + 2 * ThisArea;
						RegionData.push_back( new CBlob() );
						regionDataThisRegion = RegionData.back();
						SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
						if( CandidatExterior )
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

					}
					
					if(ThisRegionNum!=-1)
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
					}
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
					}
					
					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					ComputeData = 1;
					
#ifdef B_CONNECTIVITAT_8
					if( TestMatch )
					{
						LastIndex++;
						ThisIndex++;
					}
					else
					{
						LastIndex++;	
					}
#else
					LastIndex++;
					ThisIndex++;
#endif					
					break;
					
					
				case 5:	//|ooxxxxx|
						//|yyyyyyy|

					if(!TestMatch && !TestKnown)	// Different color and unknown => new region
					{
						ThisParent = LastRegionNum;
						ThisRegionNum = ++HighRegionNum;
						ThisArea = ThisEnd - ThisStart + 1;
						ThisPerimeter = 2 + 2 * ThisArea;
						RegionData.push_back( new CBlob() );
						regionDataThisRegion = RegionData.back();
						SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
						if( CandidatExterior )
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

					}
					else if(TestMatch && !TestKnown)	// Same color and unknown
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;
						ThisArea = ThisEnd - ThisStart + 1;
						LastPerimeter = LastEnd - LastStart + 1;	// to subtract
						ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter 
										+ PERIMETRE_DIAGONAL * (LastStart != ThisStart);
						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );


							ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart);
						}
						ComputeData = 1;
					}
					else if(TestMatch && TestKnown)	// Same color and known
					{
						LastPerimeter = LastEnd - LastStart + 1;	// to subtract
						//ThisPerimeter = - LastPerimeter;
						ThisPerimeter = - 2 * LastPerimeter 
										+ PERIMETRE_DIAGONAL * (LastStart != ThisStart);
						
						if(ThisRegionNum > LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
									findmoments, ThisRegionNum, LastRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
								if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
							}					
							ThisRegionNum = LastRegionNum;
						}
						else if(ThisRegionNum < LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
									findmoments, LastRegionNum, ThisRegionNum );

							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
								if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
							}					
							LastRegionNum = ThisRegionNum;
						}
					}

					
					if(ThisRegionNum!=-1)
					{
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);

						if( ThisStart - 1 != LastEnd )
						{
							//afegim la cantonada a la regio
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
					}
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
					}

					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					
#ifdef B_CONNECTIVITAT_8
					if( TestMatch )
					{
						LastIndex++;
						ThisIndex++;
					}
					else
					{
						LastIndex++;	
					}
#else
					LastIndex++;
					ThisIndex++;
#endif	
					break;
					
					
				case 6:	//|ooxxx  |
						//|yyyyyyy|

					if(TestMatch && !TestKnown)
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;
						ThisArea = ThisEnd - ThisStart + 1;
						LastPerimeter = LastEnd - LastStart + 1;	// to subtract
						ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
										+ PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );


							ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						}
						ComputeData = 1;
					}
					else if(TestMatch && TestKnown)
					{
						LastPerimeter = LastEnd - LastStart + 1;	// to subtract
						//ThisPerimeter = - LastPerimeter;
						ThisPerimeter = - 2 * LastPerimeter
										+ PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						
						if(ThisRegionNum > LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
									findmoments, ThisRegionNum, LastRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
								if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
							}					
							ThisRegionNum = LastRegionNum;
						}
						else if(ThisRegionNum < LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
									findmoments, LastRegionNum, ThisRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
								if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
							}					
							LastRegionNum = ThisRegionNum;
						}
					}

					
					if(ThisRegionNum!=-1)
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						if( ThisStart - 1 != LastEnd )
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
					}
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						//afegim la cantonada a la regio
						if( ThisStart - 1 != LastEnd )
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
					}					

					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					LastIndex++;
					break;
					
					
				case 7:	//|ooxxxxx|
						//|yyyy   |

					if(!TestMatch && !TestKnown)	// Different color and unknown => new region
					{
						ThisParent = LastRegionNum;
						ThisRegionNum = ++HighRegionNum;
						ThisArea = ThisEnd - ThisStart + 1;
						ThisPerimeter = 2 + 2 * ThisArea;
						RegionData.push_back( new CBlob() );
						regionDataThisRegion = RegionData.back();
						SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
						if( CandidatExterior )
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

					}
					else if(TestMatch && !TestKnown)
					{
						ThisRegionNum = LastRegionNum;
						regionDataThisRegion = regionDataLastRegion;
						ThisArea = ThisEnd - ThisStart + 1;
						ThisPerimeter = 2 + ThisArea;
						LastPerimeter = ThisEnd - LastStart + 1;
						ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
										+ PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						if( CandidatExterior )
						{
							ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
																	  inputImage->width, inputImage->height, 
																	  imatgePerimetreExtern );

							ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						}
						ComputeData = 1;
					}
					else if(TestMatch && TestKnown)
					{
						LastPerimeter = ThisEnd - LastStart + 1;	// to subtract
						//ThisPerimeter = - LastPerimeter;
						ThisPerimeter = - 2 * LastPerimeter
										+ PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
						
						if(ThisRegionNum > LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
									findmoments, ThisRegionNum, LastRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
								if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
							}					
							ThisRegionNum = LastRegionNum;
						}
						else if(ThisRegionNum < LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
									findmoments, LastRegionNum, ThisRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
								if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
							}					
							LastRegionNum = ThisRegionNum;
						}
					}

					if(ThisRegionNum!=-1)
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						if( ThisStart - 1 != LastEnd )
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
					}
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisEnd;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
						if( ThisStart - 1 != LastEnd )
						{
							actualedge.x = ThisStart - 1;
							actualedge.y = ThisRow - 1;
							cvSeqPush(regionDataThisRegion->Edges,&actualedge);
						}
					}

					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					ThisIndex++;
					break;
					
				case 8:	//|    xxx|
						//|yyyy   |
					
#ifdef B_CONNECTIVITAT_8					
					// fusionem blobs
					if( TestMatch )
					{
						if(ThisRegionNum > LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
									findmoments, ThisRegionNum, LastRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
								if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
							}					
							ThisRegionNum = LastRegionNum;
						}
						else if(ThisRegionNum < LastRegionNum)
						{
							Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
									findmoments, LastRegionNum, ThisRegionNum );
							for(int iOld = 0; iOld < MaxIndexCount; iOld++)
							{
								if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
								if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
							}					
							LastRegionNum = ThisRegionNum;
						}

						regionDataThisRegion->Perimeter = regionDataThisRegion->Perimeter + PERIMETRE_DIAGONAL*2;
					}
#endif

					if(ThisRegionNum!=-1)
					{
						//afegim la cantonada a la regio
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataThisRegion->Edges,&actualedge);
					}
#ifdef B_CONNECTIVITAT_8					
					// si hem creat un nou blob, afegim tb a l'anterior
					if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
					{
#endif					
						//afegim la cantonada a la regio
						actualedge.x = ThisStart - 1;
						actualedge.y = ThisRow - 1;
						cvSeqPush(regionDataLastRegion->Edges,&actualedge);
#ifdef B_CONNECTIVITAT_8
					}
#endif

					ThisRegion[ThisIndex] = ThisRegionNum;
					LastRegion[LastIndex] = LastRegionNum;
					ThisIndex++;
#ifdef B_CONNECTIVITAT_8					
					LastIndex--;
#endif
					break;
					
				default:
					ErrorFlag = -1;
			}	// end switch case

			// calculate the blob moments and mean gray level of the current blob (ThisRegionNum)
			if(ComputeData > 0)
			{
				// compute blob moments if necessary
				if(findmoments)
				{
					float ImageRow = (float) (ThisRow - 1);

					for(int k = ThisStart; k <= ThisEnd; k++)
					{
						Thisu10 += (float) (k - 1);
						Thisu20 += (float) (k - 1) * (k - 1);
					}
					
					Thisu11 = Thisu10 * ImageRow;
					Thisu01 = ThisArea * ImageRow;
					Thisu02 = Thisu01 * ImageRow;
					
				}

				// compute the mean gray level and its std deviation 
				if(ThisRow <= Rows )
				{
					pImageAux = pImage + ThisStart;
					if(maskImage!=NULL) pMaskAux = pMask + ThisStart;
					for(int k = ThisStart; k <= ThisEnd; k++)
					{
						if((k>0) && (k <= Cols))
						{
							if( maskImage!= NULL)
							{
								// només es t?en compte el valor del píxel de la
								// imatge que queda dins de la màscara
								// (de pas, comptem el nombre de píxels de la màscara)
								if( ((unsigned char) *pMaskAux) != PIXEL_EXTERIOR )
								{
									imagevalue = (unsigned char) (*pImageAux);
									regionDataThisRegion->Mean+=imagevalue;
									regionDataThisRegion->StdDev+=imagevalue*imagevalue;
								}
								else
								{
									nombre_pixels_mascara++;
								}
							}
							else
							{
								imagevalue = (unsigned char) (*pImageAux);
								regionDataThisRegion->Mean+=imagevalue;
								regionDataThisRegion->StdDev+=imagevalue*imagevalue;

							}
						}
						pImageAux++;
						if(maskImage!=NULL) pMaskAux++;
					}
				}

				// compute the min and max values of X and Y
				if(ThisStart - 1 < (int) ThisMinX) ThisMinX = (float) (ThisStart - 1);
				if(ThisMinX < (float) 0.0) ThisMinX = (float) 0.0;
				if(ThisEnd > (int) ThisMaxX) ThisMaxX = (float) ThisEnd;

				if(ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1;
				if(ThisMinY < (float) 0.0) ThisMinY = (float) 0.0;
				if(ThisRow > ThisMaxY) ThisMaxY = ThisRow;
			}

			// put the current results into RegionData
			if(ThisRegionNum >= 0)
			{
				if(ThisParent >= 0) { regionDataThisRegion->Parent = (int) ThisParent; }
				regionDataThisRegion->Label = ThisRegionNum;
				regionDataThisRegion->Area += ThisArea;
				regionDataThisRegion->Perimeter += ThisPerimeter;
				regionDataThisRegion->ExternPerimeter += ThisExternPerimeter;
				
				if(ComputeData > 0)
				{
					if(findmoments)
					{
						regionDataThisRegion->u10 += Thisu10;
						regionDataThisRegion->u01 += Thisu01;
						regionDataThisRegion->u20 += Thisu20;
						regionDataThisRegion->u02 += Thisu02;
						regionDataThisRegion->u11 += Thisu11;
					}
					regionDataThisRegion->Perimeter -= LastPerimeter;
					regionDataThisRegion->Minx=MIN(regionDataThisRegion->Minx,ThisMinX);
					regionDataThisRegion->Maxx=MAX(regionDataThisRegion->Maxx,ThisMaxX);
					regionDataThisRegion->Miny=MIN(regionDataThisRegion->Miny,ThisMinY);
					regionDataThisRegion->Maxy=MAX(regionDataThisRegion->Maxy,ThisMaxY);
				}
				// blobs externs
				if( CandidatExterior )
				{
					regionDataThisRegion->Exterior = true;
				}
			
			}
		}	// end Main loop

		if(ErrorFlag != 0) return false;
		// ens situem al primer pixel de la seguent fila
		pImage = inputImage->imageData - 1 + startCol + (ThisRow+startRow) * inputImage->widthStep;

		if(maskImage!=NULL)
			pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep;
	}	// end Loop over all rows

	// eliminem l'àrea del marc
	// i tamb?els píxels de la màscara
	// ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del
	// blob 0 només ser?cert si la màscara t?contacte amb el marc.
	// Si no, s'haur?de trobar quin és el blob que cont?més píxels del
	// compte.
	RegionData[0]->Area -= ( Rows + 1 + Cols + 1 )*2 + nombre_pixels_mascara;

	// eliminem el perímetre de més:
	// - sense marc: 2m+2n (perímetre extern)
	// - amb marc:   2(m+2)+2(n+2) = 2m+2n + 8
	// (segurament no és del tot acurat)
	// (i amb les màscares encara menys...)
	RegionData[0]->Perimeter -= 8.0;

	vector<CBlob*>::iterator iti;
	CBlob *blobActual;

	if(findmoments)
	{
		iti = RegionData.begin();
		// Normalize summation fields into moments 
		for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
		{
			blobActual = *iti;

			if(!SubsumedRegion[ThisRegionNum])	// is a valid blob?
			{
				// Get averages
				blobActual->u10 /= blobActual->Area;
				blobActual->u01 /= blobActual->Area;
				blobActual->u20 /= blobActual->Area;
				blobActual->u02 /= blobActual->Area;
				blobActual->u11 /= blobActual->Area;

				// Create moments
				blobActual->u20 -= blobActual->u10 * blobActual->u10;
				blobActual->u02 -= blobActual->u01 * blobActual->u01;
				blobActual->u11 -= blobActual->u10 * blobActual->u01;
				if(blobActual->u11 > -1.0E-14 && blobActual->u11 < 1.0E-14)
				{
					blobActual->u11 = (float) 0.0; // Eliminate roundoff error
				}
			}			
		}
	}

	//Get the real mean and std deviation
	iti = RegionData.begin();
	for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
	{
		blobActual = *iti;
		if(!SubsumedRegion[ThisRegionNum])	// is a valid blob?
		{
			if(blobActual->Area > 1)
			{
				blobActual->StdDev =
									sqrt(
									(
									blobActual->StdDev * blobActual->Area -
									blobActual->Mean * blobActual->Mean 
									)/
									(blobActual->Area*(blobActual->Area-1))
									);
			}
			else
				blobActual->StdDev=0;
			
			if(blobActual->Area > 0)
				blobActual->Mean/=blobActual->Area;
			else
				blobActual->Mean = 0;
		}
	
	}

	// eliminem els blobs subsumats
	//blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1;
	vector<CBlob*>::iterator itBlobs = RegionData.begin();

	ThisRegionNum = 0;
	while( itBlobs != RegionData.end() )
	{
		if(SubsumedRegion[ThisRegionNum])	// is not a valid blob?
		{
			delete *itBlobs;
			itBlobs = RegionData.erase( itBlobs );
		}
		else		
			itBlobs++;

		ThisRegionNum++;
	}

	free(SubsumedRegion);
	delete Transition;
	delete ThisRegion;
	delete LastRegion;

	if( imatgePerimetreExtern ) cvReleaseImage(&imatgePerimetreExtern);

	return true;
}