#include "ofxCvContourFinder.h"
static bool sort_carea_compare( const CvSeq* a, const CvSeq* b) {
float areaa = cvContourArea(a, CV_WHOLE_SEQ);
float areab = cvContourArea(b, CV_WHOLE_SEQ);
return (areaa > areab);
}
ofxCvContourFinder::ofxCvContourFinder() {
_width = 0;
_height = 0;
myMoments = (CvMoments*)malloc( sizeof(CvMoments) );
reset();
}
ofxCvContourFinder::~ofxCvContourFinder() {
free( myMoments );
}
void ofxCvContourFinder::reset() {
cvSeqBlobs.clear();
blobs.clear();
nBlobs = 0;
}
int ofxCvContourFinder::findContours( ofxCvGrayscaleImage& input,
int minArea,
int maxArea,
int nConsidered,
bool bFindHoles,
bool bUseApproximation) {
IplImage* ipltemp = input.getCvImage();
_width = ipltemp->width;
_height = ipltemp->height;
reset();
inputCopy.setUseTexture(false);
if( inputCopy.getWidth() == 0 ) {
inputCopy.allocate( _width, _height );
} else if( inputCopy.getWidth() != _width || inputCopy.getHeight() != _height ) {
inputCopy.clear();
inputCopy.allocate( _width, _height );
}
inputCopy.setROI( input.getROI() );
inputCopy = input;
CvSeq* contour_list = NULL;
contour_storage = cvCreateMemStorage( 1000 );
storage = cvCreateMemStorage( 1000 );
int retrieve_mode
= (bFindHoles) ? CV_RETR_LIST : CV_RETR_EXTERNAL;
cvFindContours( inputCopy.getCvImage(), contour_storage, &contour_list,
sizeof(CvContour), retrieve_mode, bUseApproximation ? CV_CHAIN_APPROX_SIMPLE : CV_CHAIN_APPROX_NONE );
CvSeq* contour_ptr = contour_list;
while( (contour_ptr != NULL) ) {
float area = cvContourArea(contour_ptr, CV_WHOLE_SEQ, bFindHoles);
if(bFindHoles && area < 0) {
area = fabs(area);
}
if((area > minArea) && (area < maxArea)) {
cvSeqBlobs.push_back(contour_ptr);
}
contour_ptr = contour_ptr->h_next;
}
if( cvSeqBlobs.size() > 1 ) {
sort( cvSeqBlobs.begin(), cvSeqBlobs.end(), sort_carea_compare );
}
for( int i = 0; i < MIN(nConsidered, (int)cvSeqBlobs.size()); i++ ) {
blobs.push_back( ofxCvBlob() );
float area = cvContourArea( cvSeqBlobs[i], CV_WHOLE_SEQ, bFindHoles );
CvRect rect = cvBoundingRect( cvSeqBlobs[i], 0 );
cvMoments( cvSeqBlobs[i], myMoments );
blobs[i].area = bFindHoles ? fabs(area) : area;
blobs[i].length = cvArcLength(cvSeqBlobs[i]);
blobs[i].boundingRect.x = rect.x;
blobs[i].boundingRect.y = rect.y;
blobs[i].boundingRect.width = rect.width;
blobs[i].boundingRect.height = rect.height;
blobs[i].centroid.x = (myMoments->m10 / myMoments->m00);
blobs[i].centroid.y = (myMoments->m01 / myMoments->m00);
if(bFindHoles) {
blobs[i].hole = -area < 0 ? true : false;
}
else {
blobs[i].hole = false;
}
CvPoint pt;
CvSeqReader reader;
cvStartReadSeq( cvSeqBlobs[i], &reader, 0 );
for( int j=0; j < cvSeqBlobs[i]->total; j++ ) {
CV_READ_SEQ_ELEM( pt, reader );
blobs[i].pts.push_back( ofPoint((float)pt.x, (float)pt.y) );
}
blobs[i].nPts = blobs[i].pts.size();
}
nBlobs = blobs.size();
if( contour_storage != NULL ) { cvReleaseMemStorage(&contour_storage); }
if( storage != NULL ) { cvReleaseMemStorage(&storage); }
return nBlobs;
}
void ofxCvContourFinder::draw( float x, float y, float w, float h ) const {
float scalex = 0.0f;
float scaley = 0.0f;
if( _width != 0 ) { scalex = w/_width; } else { scalex = 1.0f; }
if( _height != 0 ) { scaley = h/_height; } else { scaley = 1.0f; }
if(bAnchorIsPct){
x -= anchor.x * w;
y -= anchor.y * h;
}else{
x -= anchor.x;
y -= anchor.y;
}
ofPushStyle();
ofSetHexColor(0xDD00CC);
ofPushMatrix();
ofTranslate( x, y, 0.0 );
ofScale( scalex, scaley, 0.0 );
ofNoFill();
for( int i=0; i<(int)blobs.size(); i++ ) {
ofDrawRectangle( blobs[i].boundingRect.x, blobs[i].boundingRect.y,
blobs[i].boundingRect.width, blobs[i].boundingRect.height );
}
ofSetHexColor(0x00FFFF);
for( int i=0; i<(int)blobs.size(); i++ ) {
ofNoFill();
ofBeginShape();
for( int j=0; j<blobs[i].nPts; j++ ) {
ofVertex( blobs[i].pts[j].x, blobs[i].pts[j].y );
}
ofEndShape();
}
ofPopMatrix();
ofPopStyle();
}
void ofxCvContourFinder::draw(const ofPoint & point) const{
draw(point.x, point.y);
}
void ofxCvContourFinder::draw(const ofRectangle & rect) const{
draw(rect.x, rect.y, rect.width, rect.height);
}
void ofxCvContourFinder::setAnchorPercent( float xPct, float yPct ){
anchor.x = xPct;
anchor.y = yPct;
bAnchorIsPct = true;
}
void ofxCvContourFinder::setAnchorPoint( int x, int y ){
anchor.x = x;
anchor.y = y;
bAnchorIsPct = false;
}
void ofxCvContourFinder::resetAnchor(){
anchor.set(0,0);
bAnchorIsPct = false;
}
Comments