/************************************************************************ BlobGroup.cpp FUNCIONALITAT: Implementation de la classe BlobGroup AUTOR: Inspecta S.L. MODIFICACIONS (Modificacition, Autor, Data): **************************************************************************/ #include "BlobGroup.h" //! Show errors functions: only works for windows releases #ifdef _SHOW_ERRORS #include //suport per a CStrings #include //suport per a AfxMessageBox #endif /************************************************************************** Constructors / Destructors **************************************************************************/ /** - FUNCTION: BlobGroup - FUNCTIONALITY: Standard constructor - PARAMETERS: - RESULT: - creates an empty set of blobs - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ BlobGroup::BlobGroup() { m_blobs = BlobVector(); } /** - FUNCTION: BlobGroup - FUNCTIONALITY: Copy constructor - PARAMETERS: - source: object to copy - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ BlobGroup::BlobGroup(const BlobGroup& source) { // create the new from the past as a parameter //m_blobs = BlobVector(source.getNumBlobs()); m_blobs.reserve(source.getNumBlobs()); // copy the blobs from the origin to the current one BlobVector::const_iterator pBlobsSrc = source.m_blobs.begin(); //BlobVector::iterator pBlobsDst = m_blobs.begin(); while (pBlobsSrc != source.m_blobs.end()) { // can't call the operator = since BlobVector is a // Blob vector *. So create a new blob from the // original blob m_blobs.push_back(new Blob(**pBlobsSrc)); pBlobsSrc++; } } /** - FUNCTION: ~BlobGroup - FUNCTIONALITY: Destructor - PARAMETERS: - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ BlobGroup::~BlobGroup() { clearBlobs(); } /************************************************************************** Operadors / Operators **************************************************************************/ /** - FUNCTION: Assigment operator - FUNCTIONALITY: - PARAMETERS: - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ BlobGroup& BlobGroup::operator=(const BlobGroup& source) { // if they are already the same, nothing needs to be done if (this != &source) { // release the old set of blobs for (int i = 0; i < getNumBlobs(); ++i) { delete m_blobs[i]; } m_blobs.clear(); // create the new from the past as a parameter m_blobs = BlobVector(source.getNumBlobs()); // copy the blobs from the origin to the current one BlobVector::const_iterator pBlobsSrc = source.m_blobs.begin(); BlobVector::iterator pBlobsDst = m_blobs.begin(); while (pBlobsSrc != source.m_blobs.end()) { // can't call the operator = since BlobVector is a // Blob vector *. So create a new blob from the // original blob *pBlobsDst = new Blob(**pBlobsSrc); pBlobsSrc++; pBlobsDst++; } } return *this; } /** - FUNCTION: + operator - FUNCTIONALITY: Joins the blobs in source with the current ones - PARAMETERS: - source: object to copy the blobs - RESULT: - object with the actual blobs and the source blobs - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ BlobGroup BlobGroup::operator+(const BlobGroup& source) const { // create the result from the current blobs BlobGroup result(*this); // reserve memory for the new blobs result.m_blobs.resize(result.getNumBlobs() + source.getNumBlobs()); // declare the iterators to cross the origin and destination blobs BlobVector::const_iterator pBlobsSrc = source.m_blobs.begin(); BlobVector::iterator pBlobsDst = result.m_blobs.end(); // insert the blobs from the origin to the current one while (pBlobsSrc != source.m_blobs.end()) { pBlobsDst--; *pBlobsDst = new Blob(**pBlobsSrc); pBlobsSrc++; } return result; } /************************************************************************** Operacions / Operations **************************************************************************/ /** - FUNCTIONS: addBlob - FUNCIONALITAT: Afegeix un blob al conjunt - PARAMETERS: - blob: blob a afegir - RESULTAT: - modifica el conjunt de blobs actual - RESTRICCIONS: - AUTOR: Ricard Borràs - DATE OF CREATION: 2006/03/01 - MODIFICATION: Data. Autor. Description. */ void BlobGroup::addBlob(Blob* blob) { if (blob != NULL) { Blob* tp = new Blob(blob); m_blobs.push_back(tp); } } #ifdef MATRIXCV_ACTIU /** - FUNCTION: getResult - FUNCTIONALITY: Computes the function evaluator on all the blobs of the class and returns a vector with the result - PARAMETERS: - evaluator: function to apply to each blob (any object derived from the OperatorBlob class) - RESULT: - vector with all the results in the same order as the blobs - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ DoubleVector BlobGroup::getResult(BlobOperator* evaluator) const { if (getNumBlobs() <= 0) { return DoubleVector(); } // define the result DoubleVector result = DoubleVector(getNumBlobs()); // and iterators on the blobs and the result DoubleVector::iterator itResult = result.GetIterator(); BlobVector::const_iterator itBlobs = m_blobs.begin(); // evaluate the function on all blobs while (itBlobs != m_blobs.end()) { *itResult = (*evaluator)(**itBlobs); itBlobs++; itResult++; } return result; } #endif /** - FUNCTION: getResult - FUNCTIONALITY: Computes the function evaluator on all the blobs of the class and returns a vector with the result - PARAMETERS: - evaluator: function to apply to each blob (any object derived from the OperatorBlob class) - RESULT: - vector with all the results in the same order as the blobs - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ DoubleStlVector BlobGroup::getStlResult(BlobOperator* evaluator) const { if (getNumBlobs() <= 0) { return DoubleStlVector(); } // define the result DoubleStlVector result = DoubleStlVector(getNumBlobs()); // and iterators on the blobs and the result DoubleStlVector::iterator itResult = result.begin(); BlobVector::const_iterator itBlobs = m_blobs.begin(); // evaluate the function on all blobs while (itBlobs != m_blobs.end()) { *itResult = (*evaluator)(**itBlobs); itBlobs++; itResult++; } return result; } /** - FUNCTION: getNumber - FUNCTIONALITY: Computes the function evaluator on a blob of the class - PARAMETERS: - indexBlob: index of the blob to compute the function - evaluator: function to apply to each blob (any object derived from the OperatorBlob class) - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ double BlobGroup::getNumber(int indexBlob, BlobOperator* evaluator) const { if (indexBlob < 0 || indexBlob >= getNumBlobs()) { raiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); } return (*evaluator)(*m_blobs[indexBlob]); } /** - FUNCTION: filter (const version) - FUNCTIONALITY: Get some blobs from the class based on conditions on measures of the blobs. - PARAMETERS: - dst: where to store the selected blobs - filterAction: B_INCLUDE: include the blobs which pass the filter in the result B_EXCLUDE: exclude the blobs which pass the filter in the result - evaluator: Object to evaluate the blob - Condition: How to decide if the result returned by evaluator on each blob is included or not. It can be: B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - LowLimit: numerical value to evaluate the Condition on evaluator(blob) - HighLimit: numerical value to evaluate the Condition on evaluator(blob). Only useful for B_INSIDE and B_OUTSIDE - RESULT: - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) the Condition on the result returned by evaluator on each blob - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ /////////////////////////// FILTRAT DE BLOBS //////////////////////////////////// void BlobGroup::filter(BlobGroup& dst, int filterAction, BlobOperator* evaluator, int condition, double lowLimit, double highLimit /*=0*/) const { // do the job doFilter(dst, filterAction, evaluator, condition, lowLimit, highLimit); } /** - FUNCTION: filter - FUNCTIONALITY: Get some blobs from the class based on conditions on measures of the blobs. - PARAMETERS: - dst: where to store the selected blobs - filterAction: B_INCLUDE: include the blobs which pass the filter in the result B_EXCLUDE: exclude the blobs which pass the filter in the result - evaluator: Object to evaluate the blob - Condition: How to decide if the result returned by evaluator on each blob is included or not. It can be: B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - LowLimit: numerical value to evaluate the Condition on evaluator(blob) - HighLimit: numerical value to evaluate the Condition on evaluator(blob). Only useful for B_INSIDE and B_OUTSIDE - RESULT: - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) the Condition on the result returned by evaluator on each blob - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ void BlobGroup::filter(BlobGroup& dst, int filterAction, BlobOperator* evaluator, int condition, double lowLimit, double highLimit /*=0*/) { int numBlobs = getNumBlobs(); // do the job doFilter(dst, filterAction, evaluator, condition, lowLimit, highLimit); // inline operation: remove previous blobs if (&dst == this) { // delete the first blobs (which are the originals) // since we will have them replicated at the end if they pass the filter BlobVector::iterator itBlobs = m_blobs.begin(); for (int i = 0; i < numBlobs; i++) { delete *itBlobs; itBlobs++; } m_blobs.erase(m_blobs.begin(), itBlobs); } } void BlobGroup::filter(BlobGroup& dst, FilterAction filterAction, BlobOperator* evaluator, FilterCondition condition, double lowLimit, double highLimit /*= 0 */) { filter(dst, (int)filterAction, evaluator, (int)condition, lowLimit, highLimit); } //! Does the filter method job void BlobGroup::doFilter(BlobGroup& dst, int filterAction, BlobOperator* evaluator, int condition, double lowLimit, double highLimit/* = 0*/) const { int i, numBlobs; bool evaluationResult; DoubleStlVector evaluationBlobs; DoubleStlVector::iterator itEvaluationBlobs; if (getNumBlobs() <= 0) { return; } if (!evaluator) { return; } // evaluate the blobs with the relevant function evaluationBlobs = getStlResult(evaluator); itEvaluationBlobs = evaluationBlobs.begin(); numBlobs = getNumBlobs(); switch(condition) { case B_EQUAL: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult= *itEvaluationBlobs == lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_NOT_EQUAL: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = *itEvaluationBlobs != lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_GREATER: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = *itEvaluationBlobs > lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_LESS: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = *itEvaluationBlobs < lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_GREATER_OR_EQUAL: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = *itEvaluationBlobs>= lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_LESS_OR_EQUAL: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = *itEvaluationBlobs <= lowLimit; if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_INSIDE: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = (*itEvaluationBlobs >= lowLimit) && (*itEvaluationBlobs <= highLimit); if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; case B_OUTSIDE: for (i = 0; i < numBlobs; ++i, ++itEvaluationBlobs) { evaluationResult = (*itEvaluationBlobs < lowLimit) || (*itEvaluationBlobs > highLimit); if ((evaluationResult && filterAction == B_INCLUDE) || (!evaluationResult && filterAction == B_EXCLUDE)) { dst.m_blobs.push_back(new Blob(getBlob(i))); } } break; } } /** - FUNCTION: getBlob - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs) - PARAMETERS: - index: index in the blob array - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ Blob BlobGroup::getBlob(int index) const { if (index < 0 || index >= getNumBlobs()) { raiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); } return *m_blobs[index]; } Blob *BlobGroup::getBlob(int index) { if (index < 0 || index >= getNumBlobs()) { raiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); } return m_blobs[index]; } Blob BlobGroup::getBlobByID(LabelID id) const{ for (int i = 0; i < getNumBlobs(); ++i) { if (getBlob(i).getID() == id) { return m_blobs[i]; } } raiseError(EXCEPTION_EXECUTE_FAULT); return Blob(); } Blob *BlobGroup::getBlobByID(LabelID id) { for (int i = 0; i < getNumBlobs(); ++i) { if (getBlob(i)->getID() == id) { return m_blobs[i]; } } raiseError(EXCEPTION_EXECUTE_FAULT); return (new Blob()); } /** - FUNCTION: getNthBlob - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria - PARAMETERS: - criteria: criteria to order the blob array - nBlob: index of the returned blob in the ordered blob array - dst: where to store the result - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ void BlobGroup::getNthBlob(BlobOperator* criteria, int nBlob, Blob& dst) const { // verify that we are not accessing out the blobs vector if(nBlob < 0 || nBlob >= getNumBlobs()) { //raiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); dst = Blob(); return; } DoubleStlVector evaluationBlobs, evaluationBlobsOrdered; double value; // evaluate the blobs with the relevant function evaluationBlobs = getStlResult(criteria); evaluationBlobsOrdered = DoubleStlVector(getNumBlobs()); // get the nBlob first results (in descending order) std::partial_sort_copy(evaluationBlobs.begin(), evaluationBlobs.end(), evaluationBlobsOrdered.begin(), evaluationBlobsOrdered.end(), std::greater()); value = evaluationBlobsOrdered[nBlob]; // look for the first blob that has the value n-ssim DoubleStlVector::const_iterator itEvaluation = evaluationBlobs.begin(); bool foundBlob = false; int indexBlob = 0; while (itEvaluation != evaluationBlobs.end() && !foundBlob) { if (*itEvaluation == value) { foundBlob = true; dst = Blob(getBlob(indexBlob)); } itEvaluation++; indexBlob++; } } /** - FUNCTION: clearBlobs - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory - PARAMETERS: - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ void BlobGroup::clearBlobs() { BlobVector::iterator itBlobs = m_blobs.begin(); while (itBlobs != m_blobs.end()) { delete *itBlobs; itBlobs++; } m_blobs.clear(); } /** - FUNCTION: raiseError - FUNCTIONALITY: Error handling function - PARAMETERS: - errorCode: reason of the error - RESULT: - in _SHOW_ERRORS version, shows a message box with the error. In release is silent. In both cases throws an exception with the error. - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ void BlobGroup::raiseError(int errorCode) const { //! Do we need to show errors? #ifdef _SHOW_ERRORS CString msg, format = "Error en BlobGroup: %s"; switch (errorCode) { case EXCEPTION_BLOB_OUT_OF_BOUNDS: msg.Format(format, "Intentant accedir a un blob no existent"); break; default: msg.Format(format, "Codi d'error desconegut"); break; } AfxMessageBox(msg); #endif throw errorCode; } /************************************************************************** Auxiliars / Auxiliary functions **************************************************************************/ /** - FUNCTION: printBlobs - FUNCTIONALITY: Prints some blob features in an ASCII file - PARAMETERS: - fileName: full path + filename to generate - RESULT: - RESTRICTIONS: - AUTHOR: Ricard Borràs - CREATION DATE: 25-05-2005. - MODIFICATION: Date. Author. Description. */ void BlobGroup::printBlobs(char* fileName) const { DoubleStlVector area, /*perimeter,*/ exterior, compactness, length, externalPerimeter, perimeterConvex, perimeter; int i; FILE* fp; area = getStlResult(BlobGetArea()); perimeter = getStlResult(BlobGetPerimeter()); exterior = getStlResult(BlobGetExterior()); compactness = getStlResult(BlobGetCompactness()); length = getStlResult(BlobGetLength()); externalPerimeter = getStlResult(BlobGetExternalPerimeter()); perimeterConvex = getStlResult(BlobGetHullPerimeter()); fp = fopen(fileName, "w"); for (i = 0; i < getNumBlobs(); ++i) { fprintf(fp, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f external)\t pconvex=%8.2f\t ext=%.0f\t c=%3.2f\t l=%8.2f\n", i, area[i], perimeter[i], externalPerimeter[i], perimeterConvex[i], exterior[i], compactness[i], length[i]); } fclose(fp); } Blob* BlobGroup::getBlobNearestTo(const cv::Point& pt) { float minD = FLT_MAX, d = 0; int numBlobs = m_blobs.size(); int idxNearest = -1; for (int i = 0; i < numBlobs; ++i) { cv::Point diff = m_blobs[i]->getCenter() - pt; d = diff.x * diff.x + diff.y * diff.y; if (minD > d) { idxNearest = i; minD = d; } } if (idxNearest != -1) { return m_blobs[idxNearest]; } else { return NULL; } }