Ask Your Question
0

How to create a class for trackbars in general?

asked 2019-06-30 03:17:25 -0600

Hordon gravatar image

I would like to create a general Trackbar class what I would like to use with different functions. The maximum number of trackbar I need is 3. It should be flexible: sometimes I would use 1 trackbar for 2 images (for xample blend to image in different ratios), sometimes I would like to use 3 trackbar for one image (eg: set RGB paramaters for an image). My idea was to crate a Trackbar class. It has a constructor which takes all the neccessary parameter to create + it takes a function pointer, a vector of Mat pointer (the input images), and a vector of integers (the values I should modify), and the number of trackbar I use.

Trackbar(int value, int maxValue, std::string trackbarName, std::string windowName, cv::Mat* (*func_ptr)(std::vector<cv::Mat*> images, std::vector<int> values), std::vector<cv::Mat*> imagesInput, std::vector<int> values, int trackbarSelect)

The constructor creates a trackbar with a callback (out of the predefined 3) based on which is the trackbarSelect.

if (trackbarSelect == 0) {
        cv::createTrackbar(_trackbarName, _windowName, &_startValue, _maxValue, trackbarCallback);
        trackbarCallback(_values.at(trackbarSelect), 0);
    } else if (trackbarSelect == 1) {
        cv::createTrackbar(_trackbarName, _windowName, &_startValue, _maxValue, trackbarCallback2);
        trackbarCallback2(_values.at(trackbarSelect), 0);
    }  else if (trackbarSelect == 2) {
        cv::createTrackbar(_trackbarName, _windowName, &_startValue, _maxValue, trackbarCallback2);
        trackbarCallback3(_values.at(trackbarSelect), 0); }

}

The callbacs calls the pointed function which is written in general form: it could handle multiple images if needed (since the first parameter is a vector) and could handle multiple values if needed because the second parameter is a vector too. It returns with a Mat pointer which will be displayed in the callback.

void Trackbar::trackbarCallback( int, void* )
{
    _values.at(trackbarSelect) = cv::getTrackbarPos(_trackbarName, _windowName);
    cv::Mat* result = _func_ptr(_imagesInput, _values);
    cv::imshow(_windowName, *result);
}

An example function I would like to handle with this:

cv::Mat* rgbFunction(std::vector<cv::Mat*> images, std::vector<int> values)
{
    *images[0] = cv::Scalar(values.at(0), values.at(1), values.at(2));
    return images.at(0);
}

void colorSetter(void)
{
    cv::Mat img(1000, 1000, CV_8UC3, cv::Scalar(0, 0, 0));
    std::vector<cv::Mat*> images;
    images.push_back(&img);
    std::vector<int> values = {0, 0, 0};

    std::string windowname = "RGB_Sliders";
    cv::namedWindow(windowname, cv::WINDOW_AUTOSIZE);

    Trackbar blueTrackbar(0, 100, "blue", windowname, &rgbFunction, images, values, 0);
    Trackbar greenTrackbar(0, 100, "green", windowname, &rgbFunction, images, values, 1);
    Trackbar redTrackbar(0, 100, "red", windowname, &rgbFunction, images, values, 2);

    cv::waitKey(0);
    cv::destroyWindow(windowname);
}

My problem is that I have a strong feeling that I overcomplicated things here and this could be done much easier if I have a better understanding + this isn't work perfectly well for some reason. I little help would be much appreciated - please be very clear since I just start to learn OpenCV a week ago! Thank you very much in advance!

edit retag flag offensive close merge delete

Comments

berak gravatar imageberak ( 2019-06-30 04:49:29 -0600 )edit

it also expects a global, static callback , not a class member function

berak gravatar imageberak ( 2019-06-30 05:18:35 -0600 )edit

@berak Thank you for your answer but I do not understand it completely yet. Could you please show me some minimal code of how to implement this general purpose trackbar class?

Hordon gravatar imageHordon ( 2019-07-01 03:06:22 -0600 )edit

general purpose

goto line 1

berak gravatar imageberak ( 2019-07-01 03:09:59 -0600 )edit

btw, NEVER save or pass pointers to cv::Mat, you'll wreck havoc with the refcounts. (it's a "smart pointer" already !)

berak gravatar imageberak ( 2019-07-01 03:31:39 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2019-07-01 03:30:07 -0600

berak gravatar image

updated 2019-07-01 03:42:26 -0600

the trackbar callback expects a global, static callback function (it has to save the function address). if you want to use this in a class context, you need some indirection ("dispatch" from a static handler to your desired class member function):

struct Foo {
    int value;    

    // static  function
    static void callback(int pos, void *userptr) {
        Foo *foo = (Foo*)usrptr; // cast user data back to "this"
        foo->real_callback(pos);
    }

    // class member function
    void real_callback(int p) {
         // do something.
         // you can use Foo's "this" ptr here.
         this->value = p;
    }

};


...
Foo foo;

// now pass Foo's *static* callback, and it's address:
cv::createTrackbar(win_name, bar_name, &foo.value, 100, Foo::callback, (void*)(&foo));
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2019-06-30 03:17:25 -0600

Seen: 1,460 times

Last updated: Jul 01 '19