nim_duilib/examples/contour/blob/BlobGroup.cpp
2025-03-16 16:42:44 +08:00

664 lines
21 KiB
C++

/************************************************************************
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 <afx.h> //suport per a CStrings
#include <afxwin.h> //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<double>());
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;
}
}