ribbon model

Hi All,

This is my first piece with OpenFrameworks, it´s a work in progress but for now enjoy it. One video and source code at ->


One more time :thanks for the library, Zach !

compiler: DEV c++
OF Version: 0.02
keys: space to capture background


hey nice!

I’ve tried to run the code and it says something about ofCvContourFinder not having maxX and maxY. Did you hack anything on the opencv addon? (i think i have the latest version…)

anyway, thanks for sharing!

Hi, I forgot this.

To solve the problem you must add these lines to the ofCvContourFinder.h

float maxX;
float maxY;

And this is my ofCvContourFinder function in ofCvContourFinder.cpp :

void ofCvContourFinder::findContours ( ofCvGrayscaleImage input,
int minArea,
int maxArea,
int nConsidered,
bool bFindHoles){


// opencv will clober the image it detects contours on, so we want to copy it
// into a copy before we detect contours. That copy is allocated if necessary
// (necessary = (a) not allocated or (b) wrong size)
// so be careful if you pass in different sized images to “findContours”
// there is a performance penalty, but we think there is not a memory leak to worry about
// better to create mutiple contour finders for different sizes, ie,
// if you are finding contours in a 640x480 image but also a 320x240 image
// better to make two ofCvContourFinder objects then to use one, because
// you will get penalized less.

if (inputCopy.width == 0){
inputCopy.allocate(input.width, input.height);
inputCopy = input;
} else {
if (inputCopy.width == input.width && inputCopy.height == input.height){
inputCopy = input;
} else {
// we are allocated, but to the wrong size –
// been checked for memory leaks, but a warning:
// be careful if you call this function with alot of different
// sized “input” images!, it does allocation every time
// a new size is passed in…
inputCopy.allocate(input.width, input.height);
inputCopy = input;

CvSeq* contour_list = NULL;
contour_storage = cvCreateMemStorage(1000);
storage = cvCreateMemStorage(1000);

CvContourRetrievalMode retrieve_mode = (bFindHoles) ? CV_RETR_LIST : CV_RETR_EXTERNAL;
cvFindContours (inputCopy.getCvImage(), contour_storage, &contour_list, sizeof(CvContour), retrieve_mode, CV_CHAIN_APPROX_SIMPLE);
CvSeq* contour_ptr = contour_list;

nCvSeqsFound = 0;
// put the contours from the linked list, into an array for sorting
while ((contour_ptr != NULL)){

float area = fabs(cvContourArea(contour_ptr, CV_WHOLE_SEQ));

if ((area > minArea) && (area < maxArea)) {
cvSeqBlobs[nCvSeqsFound] = contour_ptr; // copy the pointer

contour_ptr = contour_ptr->h_next;
//------------------------------------- sort the pointers based on size…
if (nCvSeqsFound > 0){
qsort( cvSeqBlobs, nCvSeqsFound, sizeof(CvSeq*), qsort_carea_compare);

// now, we have nCvSeqsFound contours, sorted by size in the array cvSeqBlobs
// let’s get the data out and into our structures that we like…

nBlobs = MIN(nConsidered, nCvSeqsFound); // take the minumum!

//vamos a averiguar cuál es el punto más alto de los contornos detectados
maxX = 0.0f;
maxY = 240.0f;

for (int i = 0; i < nBlobs; i++){

float area = cvContourArea(cvSeqBlobs[i], CV_WHOLE_SEQ);
CvRect rect = cvBoundingRect(cvSeqBlobs[i], 0);
cvMoments(cvSeqBlobs[i], myMoments);

blobs[i].area = fabs(area);
blobs[i].hole = area < 0 ? true : false;
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 = (int) (myMoments->m10 / myMoments->m00);
blobs[i].centroid.y = (int) (myMoments->m01 / myMoments->m00);

// get the points for the blob:
blobs[i].nPts = MIN(MAX_CONTOUR_LENGTH, cvSeqBlobs[i]->total);

CvPoint pt;
CvSeqReader reader;
cvStartReadSeq (cvSeqBlobs[i], &reader, 0);

for (int j=0; j < blobs[i].nPts; j++){
CV_READ_SEQ_ELEM(pt, reader);
blobs[i].pts[j].x = (float)pt.x;
blobs[i].pts[j].y = (float)pt.y;
//si la coordenada y es menor (punto mas alto)…
if ((float)pt.y < maxY){
maxY = (float)pt.y;
maxX = (float)pt.x;
// Free the storage memory.
// Warning: do this inside this function otherwise you get a strange memory leak
if (contour_storage != NULL) { cvReleaseMemStorage(&contour_storage);}
if (storage != NULL) { cvReleaseMemStorage(&storage);}


try it. Un saludo!