[SOLVED] Using ofParameter to modify ofRect within a class with Gui

Hello,

I am stuck in my project. A bit hard to explain but i will try to make it clear.

I am using a kinect to detect blobs.
I have two classes.

one that handles the kinect sensor :

class kinectTracker {
public:
    
    kinectTracker();
    ~kinectTracker();
                                                                                    
    void setup();
    void update();
    void draw();
    void draw(float _x, float _y, float _w, float _h);
    void drawDepth();
    void drawDepth(float _x, float _y, float _w, float _h);
    int getNbBlobs();

    ROI roi;
    
    //---------- Parameters ----------//
    
    ofParameterGroup parameters;
    ofParameter<float> nearThreshValue;
    ofParameter<float> farThreshValue;
    ofParameter<float> minBlobSize;
    ofParameter<bool> bDilate;
    ofParameter<bool> bErode;
    ofParameter<int> nbDilate;
    ofParameter<int> nbErode;
    ofParameter<ofVec3f> pos; // x, y and z position of blob
    
private:
    
    ofxKinect kinect;
            
    //---------- blob tracking with ofxKinect and ofxOpenCV ----------//
    
    ofxCvGrayscaleImage depthImage; // grayscale depth image
    ofxCvGrayscaleImage nearThresholdImage;
    ofxCvGrayscaleImage farThresholdImage;
    ofxCvContourFinder contourFinder; // blob detection
};

and one to handle the ROI :

    class ROI : public ofBaseDraws, public ofRectangle {
    
public:
    void draw(float _x,float _y) {
        draw(_x, _y, getWidth(), getHeight());
    }
    
    void draw(float _x,float _y,float w, float h)  {
        
        ofPushMatrix();
        
        ofTranslate(_x, _y);
        ofScale(w/CAM_WIDTH, h/CAM_HEIGHT);
        
        ofPushStyle();
        ofSetColor(255, 0, 0);
        ofNoFill();
        ofSetLineWidth(1);
        ofRect(*this);
        ofPopStyle();
        
        ofPopMatrix();
    }
    
    float getWidth()  {
        return CAM_WIDTH;
    }
    
    float getHeight()  {
        return CAM_HEIGHT;
    }
};

Class ROI handles and draw region of interest in order to select a detection area.
As you can see this ROI integrates an ofRect to set and draw this area.

In ofApp i use a kinectTracker object

 kinectTracker cvKinect;

I would like to be able to change the values of the ofRect from the ofApp with ofxGui using ofParameter if possible.

I was able to use the GUI to change kinect parameters using ofParameterGroup but i don’t know how to “publish” ROI parameters to access them from the ofApp GUI…

I had a previous version of this app using ofxUI instead of ofxGui and i was able to change ROI coordinates using

configUI1->addSlider("ROI - position X", 0.f, CAM_WIDTH, &cvKinect.roi.x);
configUI1->addSlider("ROI - position Y", 0.f, CAM_HEIGHT, &cvKinect.roi.y);
configUI1->addSlider("ROI - width", 0.f, CAM_WIDTH, &cvKinect.roi.width);
configUI1->addSlider("ROI - height", 0.f, CAM_HEIGHT, &cvKinect.roi.height);

Hope i made myself clear.

any contribution appreciated.

thanks a lot

i think the easiest until there’s some control that allows to use ofParmater<ofRectangle> would be to have ofParamters for x,y,w,h and add a listener function to all of them, when any of them changes update the roi by creating the rectangle from x,y,w,h

ok. Thanks for the info.
I will try like you suggest.

Thanks

Is there an event i could use like valueChanged from ofParameter ?

Hi, the example in examples\gui\guiExample\src shows how to add a listener for when the value changes in an ofParameter.

/A

Just saw it :wink:
thanks.

also guiFromParameters is even a better example on how to use ofParameter & ofxGui

For the record. In case it is usefull to anyone.

Header

class ROI : public ofBaseDraws, public ofRectangle {
public:
    ROI();
    ~ROI();
    void draw();
    
    ofParameterGroup parameters;
    ofParameter<float> posX;
    ofParameter<float> posY;
    ofParameter<float> width;
    ofParameter<float> height;
        
    void changeRoiX(float &posX);
    void changeRoiY(float &posY);
    void changeRoiWidth(float &width);
    void changeRoiHeight(float &height);
};

.cpp

#include "ROI.h"

ROI::ROI() {
    
    posX.addListener(this, &ROI::changeRoiX);
    posY.addListener(this, &ROI::changeRoiY);
    width.addListener(this, &ROI::changeRoiWidth);
    height.addListener(this, &ROI::changeRoiHeight);
    
    parameters.setName("ROI Settings");
    parameters.add(posX.set("position x", 0, 0, CAM_WIDTH));
    parameters.add(posY.set("position y", 0, 0, CAM_HEIGHT));
    parameters.add(width.set("width", 0, 0, CAM_WIDTH));
    parameters.add(height.set("height", 0, 0, CAM_HEIGHT));
    
}

ROI::~ROI() {
    posX.removeListener(this, &ROI::changeRoiX);
    posY.removeListener(this, &ROI::changeRoiY);
    width.removeListener(this, &ROI::changeRoiWidth);
    height.removeListener(this, &ROI::changeRoiHeight);
}

void ROI::draw() {
    ofPushMatrix();
    ofPushStyle();
    ofSetColor(255, 0, 0);
    ofNoFill();
    ofSetLineWidth(2);
    ofRect(*this);
    ofPopStyle();
    ofPopMatrix();
}
    
void ROI::changeRoiX(float &posX) {
    this->setX(posX);
}

void ROI::changeRoiY(float &posY) {
    this->setY(posY);
}

void ROI::changeRoiWidth(float &width) {
    this->setWidth(width);

}

void ROI::changeRoiHeight(float &height) {
    this->setHeight(height);
}

a simpler way to do it would be something like:

class ROI {
public:
    void draw(){
        ofDrawRectangle(getRectangle());
    }

    ofRectangle getRectangle(){
        return ofRectangle(x,y,width,height);
    }
    
    ofParameter<float> x{"x",0,0,MAX_W};
    ofParameter<float> y{"y",0,0,MAX_H};
    ofParameter<float> width{"width",0,0,MAX_W};
    ofParameter<float> height{"height",0,0,MAX_H};
    ofParameterGroup parameters{
         "roi parameters",
         x, y, width, height,
    };
};

that syntax to initialize the parameters in the header will only work in 0.9 but you can just initialize them in the constructor if you are using 0.8.4

That way you avoid having to use the events.

If you don’t want to call getRectangle() you can also overload the cast operator:

operator ofRectangle(){
    return ofRectangle(x,y,width,height);
}

and then you can use an instance of ROI as if it was an ofRectangle

1 Like

hum… interesting
it seems a bit more confusing to me as i am not a advanced developper, but it is really instructive

thanks for the tip