How Interact with ContourFinder(Contour detected -OfxOpencv),blobs VS Some kind of objects,like a simple circle or a system particle for instance?

Hey,guys!
@fbrmz ,@pelintra ,@benMcChesney and all.

Hello from Brazil!
Since January of this year I’ve been working hard in an interactive floor project installation.
I’m bit confuse in my train of thought.

My big question is how to relate and write properly in the code the contours detected by the ContourFinder order to interact with some simple circle or even a complex particle ?
For example if I want to use the detected contour to repel a simple drawn circle?

I wish understand how to interact the ContourFinder captured from camera with some kind of object.
When I mean kind of object It’s just like a simple circle drawn or a rectangle.Or maybe something more complex like a system particles (repel,repulsion or whatever).
I wish have all control about it.
What Should I have in my mind,where do I start?

The another question is …Where in my code I can play wiht it?
For example …Should I change something on code like…
for (int i = 0; i < contourFinder.nBlobs; i++){
contourFinder.blobs[i].draw(360,540);

I have read book as Programming Interactivity and Mastering openFrameworks Creative Coding and ofbook but there is something very difficult that i don’t get it in my mind.I’ts been realy hard to try understand and put it in my brain maybe cause of trying translate English Language to portuguese from Brasil.

…I think when I have all this command control in my hand I’m able to proceed in my aim that is build an interactive floor aplication using contourfinder from kinect to repel some particles.

I don’t know if i’m especific clear and if someone just feel or felt like me.LOST!!
just nice be a part of this community OF.
Thanks for the help.

That’s what I 'm trying to do!

Use the Contour to repel something.

Example from youtube

Hi,
I made you a little example of repulsion. To make it quick, I used the mouse pointor as repulsion center. You can do the same thing with the blob centroid instead of the mouse coordinates.

ofVec2f p; // Coordinate of the object to move

void ofApp::update()
{
    ofVec2f c( ofGetMouseX(), ofGetMouseY() ); // Point of repulsion
    ofVec2f v = p - c; // Vector between c and p
    float d = v.length(); // Distance between c and p
    float f = 10000 / d / d; // Intensity of the repulsion (quick search on the web, found http://www.physicsclassroom.com/class/estatics/Lesson-3/Coulomb-s-Law)
    v = v.getNormalized() * f; // Force vector
    p += v; // Move the point with this vector

    // Just to bound the movement
    p.x = ofClamp( p.x, 50, ofGetWidth() - 50 );
    p.y = ofClamp( p.y, 50, ofGetHeight() - 50 );
}
void ofApp::draw()
{
    ofCircle( p.x, p.y, 30 );
}

src.zip (1.4 KB)

@fbrmz has already replied the same think to you. Perhaps you haven’t understood (don’t know, you did not answer), that’s why I wrote an example.

@lilive Thank you very much for the response !

I 'll try your example right now !!

Yes , I’ve been trying @fbrmz clue for two months !! I do not understand some concepts to be honest…thats my fault .

In my mind I’ve stopped my code project in --HOW I INTERACT WITH SOME OF THE OBJECT ( pic, circle , rec, particles ) … WHEN YOU HAVE A BLOB TO DO ?

In this case, and in my opinion, don’t hesitate: ask for clarification to the person who answered to you. Because it is sometimes not obvious to choose the right details level of an answer.
Same thing for my previous reply: if you doesn’t understand something, ask, I will clarify (if I can :slight_smile: ).

You right !!
It’s the best way to undarstand.
Cool!

By the way!Clarify me more one question,please! :smile:

Where on this place in the code,that you send to me,I will tell to the BLOB CENTROID being Written.
Where can I negotiate the exchange of blob centroid by mouse?Using the blob instead Mouse?

You know what a mean!?Like…
-Guy you must be wirite on this line of the code!

I suppose something like that.

ofVec2f c( ofGetMouseX(), ofGetMouseY() ); // Point of repulsion

I Just change ofGetMouse for something called Blob Centroid?

ofVec2f c( BLOBCENTROID(), BLOBCENTROID() ); // Point of repulsion

I assume I know basic concepts in OF and c++ ,cause I’ve been studying into a few period. Since january.but I have an incredible strength of will and don’t give up…OF is addictive.

Something like that:

for (int i = 0, int numBlobs = contourFinder.blobs.size(); i < numBlobs; ++i){
    ofxCvBlob & blob = contourFinder.blobs[i];
    ofVec2f c( blob.centroid.x, blob.centroid.y );
    ofVec2f v = p - c;
    float d = v.length();
    float f = 10000 / d / d;
    v = v.getNormalized() * f;
    p += v;
}

Oops just saw this. This might not be what you are looking for but in my ofxOpenVJ during a hackathon I created a scene that had box2d particles along with openCV outlines - you can dig around here :

benMcChesney,Thanks I’ll try.

@lilive,The last chance I promisse! :sweat:
I still getting confuse.

I joined opencvExample and your example of repulsion to give me an ideia how to change the movie mouse for just blobs contourFinder.

class ofApp : public ofBaseApp{

public:
	void setup();
	void update();
	void draw();
	
	void keyPressed(int key);
	void keyReleased(int key);
	void mouseMoved(int x, int y );
	void mouseDragged(int x, int y, int button);
	void mousePressed(int x, int y, int button);
	void mouseReleased(int x, int y, int button);
	void windowResized(int w, int h);
	void dragEvent(ofDragInfo dragInfo);
	void gotMessage(ofMessage msg);		

    #ifdef _USE_LIVE_VIDEO
	  ofVideoGrabber 		vidGrabber;
	#else
	  ofVideoPlayer 		vidPlayer;
	#endif

    ofxCvColorImage			colorImg;

    ofxCvGrayscaleImage 	grayImage;
	ofxCvGrayscaleImage 	grayBg;
	ofxCvGrayscaleImage 	grayDiff;

    ofxCvContourFinder 	contourFinder;

	int 				threshold;
	bool				bLearnBakground;

    ofVec2f p;

};


#include “ofApp.h”

//--------------------------------------------------------------
void ofApp::setup(){

#ifdef _USE_LIVE_VIDEO
    vidGrabber.setVerbose(true);
    vidGrabber.initGrabber(320,240);
#else
    vidPlayer.loadMovie("fingers.mov");
    vidPlayer.play();
#endif

colorImg.allocate(320,240);
grayImage.allocate(320,240);
grayBg.allocate(320,240);
grayDiff.allocate(320,240);

bLearnBakground = true;
threshold = 80;

**p.set( ofGetWidth() * 0.5f, ofGetHeight() * 0.5f );**

}

//--------------------------------------------------------------

void ofApp::update(){

ofBackground(100,100,100);

bool bNewFrame = false;

#ifdef _USE_LIVE_VIDEO
   vidGrabber.update();
   bNewFrame = vidGrabber.isFrameNew();
#else
    vidPlayer.update();
    bNewFrame = vidPlayer.isFrameNew();
#endif

if (bNewFrame){

	#ifdef _USE_LIVE_VIDEO
        colorImg.setFromPixels(vidGrabber.getPixels(), 320,240);
    #else
        colorImg.setFromPixels(vidPlayer.getPixels(), 320,240);
    #endif

    grayImage = colorImg;
	if (bLearnBakground == true){
		grayBg = grayImage;		// the = sign copys the pixels from grayImage into grayBg (operator overloading)
		bLearnBakground = false;
	}

	// take the abs value of the difference between background and incoming and then threshold:
	grayDiff.absDiff(grayBg, grayImage);
	grayDiff.threshold(threshold);

	// find contours which are between the size of 20 pixels and 1/3 the w*h pixels.
	// also, find holes is set to true so we will get interior contours as well....
	contourFinder.findContours(grayDiff, 20, (340*240)/3, 10, true);	// find holes
    
    
    **ofVec2f c( ofGetMouseX(), ofGetMouseY() ); // Point of repulsion**
    **ofVec2f v = p - c; // Vector between c and p**
    **float d = v.length(); // Distance between c and p**
    **float f = 10000 / d / d; // Intensity of the repulsion (quick search on the web, found http://www.physicsclassroom.com/class/estatics/Lesson-3/Coulomb-s-Law)**
    **v = v.getNormalized() * f; // Force vector**
    **p += v; // Move the point with this vector**
    
    **// Just to bound the movement**
    **p.x = ofClamp( p.x, 50, ofGetWidth() - 50 );**
    **p.y = ofClamp( p.y, 50, ofGetHeight() - 50 );**
}

}

//--------------------------------------------------------------
void ofApp::draw(){

// draw the incoming, the grayscale, the bg and the thresholded difference
ofSetHexColor(0xffffff);
colorImg.draw(20,20);
grayImage.draw(360,20);
grayBg.draw(20,280);
grayDiff.draw(360,280);

// then draw the contours:

ofFill();
ofSetHexColor(0x333333);
ofRect(360,540,320,240);
ofSetHexColor(0xffffff);

// we could draw the whole contour finder
//contourFinder.draw(360,540);

// or, instead we can draw each blob individually from the blobs vector,
// this is how to get access to them:
for (int i = 0; i < contourFinder.nBlobs; i++){
    contourFinder.blobs[i].draw(360,540);
	
	// draw over the centroid if the blob is a hole
	ofSetColor(255);
	if(contourFinder.blobs[i].hole){
		ofDrawBitmapString("hole",
			contourFinder.blobs[i].boundingRect.getCenter().x + 360,
			contourFinder.blobs[i].boundingRect.getCenter().y + 540);
	}
}

// finally, a report:
ofSetHexColor(0xffffff);
stringstream reportStr;
reportStr << "bg subtraction and blob detection" << endl
		  << "press ' ' to capture bg" << endl
		  << "threshold " << threshold << " (press: +/-)" << endl
		  << "num blobs found " << contourFinder.nBlobs << ", fps: " << ofGetFrameRate();
ofDrawBitmapString(reportStr.str(), 20, 600);


**ofFill();**
**ofCircle( p.x, p.y, 30 );**

}


How Can I tell my app use the blobs centroid just to repel the circle?

Have you tried to use my last code?

for (int i = 0, int numBlobs = contourFinder.blobs.size(); i < numBlobs; ++i){
    ofxCvBlob & blob = contourFinder.blobs[i];
    ofVec2f c( blob.centroid.x, blob.centroid.y );
    ofVec2f v = p - c;
    float d = v.length();
    float f = 10000 / d / d;
    v = v.getNormalized() * f;
    p += v;
}

Put it in update, like you did with my first example (the one with the mouse).

And don’t forget to draw something to view the result, at the end of draw(). An ofCircle for example, like in my first example. [edit] Ooops, I just see you already do it, sorry.
But you can use p.x and p.y to set the position of any object you want to draw, why not an ofImage.

I’ll try it.

Your correct loop must be …

for (int i = 0; ------ and not --------- for (int i = 0, ???

(; vs ,)

Right??

I made a mistake. It is:

for (int i = 0, numBlobs = contourFinder.blobs.size(); i < numBlobs; ++i){

If you don’t know this syntax, it is possible to inialize more than one variable in the first part of the for(). This is the same as

int numBlobs = contourFinder.blobs.size();
for (int i = 0; i < numBlobs; ++i){

except that in the first case numBlobs is local to the loop.

Still trying!

Some idea what is happenig?

Hi,

Yes, a quite precise idea: you have to take the correction I made in my previous post:

for (int i = 0, numBlobs = contourFinder.blobs.size(); i < numBlobs; ++i){

:wink:

main.cpp (347 Bytes)ofApp.h (564 Bytes)ofApp.cpp (2.1 KB)

Why the Circle particle is static?
How can I move it from blob centroid?

Send me your code I’ll watch.
(the one you’ve just posted is my mouse repulsion example, not your last try)

main.cpp (344 Bytes)ofApp.cpp (4.9 KB)ofApp.h (1.0 KB)

Sorry!!

The video grabber is initialized at 320x240 size.
So the blob centroids coordinates are between 0 and 320 for x, 0 and 240 for y.
The circle center is initialized at position x=1024/2, y=768/2
So the blob centroids are always too far from the circle to repel it.

Except this problem, the code works.

Are There a way to change it?

maybe lower the initialized circle center coordinates.
Or up video grabber size?

Yes, or if your goal is to move objects (the circle in this case) on all the surface of your window, you can convert the blob centroids coordinates.
ofMap is a function which can help you to do that.
For example, if A is a number between 0 and 320, do:

float B = ofMap( A, 0, 320, 0, ofGetWidth() )

You get B, a number between 0 and the width of your window.
For example, if A=160, and your window width is 1024, then B will be 512.

1 Like