Search code examples
c++opencvobject-detection

OpenCV HSV filter with range slider not working


I am currently starting to work on a vision system to detect blueberries out of a .jpg

I want to try to make code that displays three windows, one with my normal image (unfiltered) image, one with a set of sliders that control the upper and lower HSV limits, and one that displays my filtered image.

Currently this is my code:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace std;

Mat image;
Mat imgHSV;
Mat OutputImage;

int iLowH;
int iHighH;
int iLowS;
int iHighS;
int iLowV;
int iHighV;

static void HSVthreshold(int, int, int, int, int, int, void*)
{
   inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), OutputImage);
}

int main(int argc, char** argv)
{
    //Read image
    image = imread("C:\\OpenCV-test-imgs\\blueberryTest2.jpg", 1);
    if (image.empty())
    {
        cerr << "image was not read !" << endl;
        return 1;
    }

    //convert RGB to HSV
    cvtColor(image, imgHSV, COLOR_BGR2HSV);

    //Create windows
    namedWindow("image", WINDOW_FREERATIO); //window for original image
    namedWindow("Control", WINDOW_AUTOSIZE); //window for HSV-control sliders
    namedWindow("Output", WINDOW_AUTOSIZE); //window for output mask

    //Create trackbars in "Control" window
    createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)
    createTrackbar("HighH", "Control", &iHighH, 179);

    createTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255)
    createTrackbar("HighS", "Control", &iHighS, 255);

    createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)
    createTrackbar("HighV", "Control", &iHighV, 255);

    int key = 0;
    while (key != 27) { // 27 is escape
        HSVthreshold(iLowH, iHighH, iLowS, iHighS, iLowV, iHighV, 0);
        imshow("Output", OutputImage);
        imshow("image", imgHSV);
        key = waitKey(1); // wait at most 1 ms for input, if nothing was pressed result is -1
    }
    return 0;
}

I have the three windows that I'm looking for, but the sliders don't seem to do anything. Does anyone know a way to fix this.

Sorry if i'm not understanding simple things in OpenCV, I'm quite new to this.

Edit: I edited the code slightly to remove some errors.

Edit2: Updated code, included error messages

Edit3: Updated code, is working now!, removed error messages


Solution

  • cv::waitKey provides a "moment" for opencv to process stuff you want to display. You are only calling it twice so opencv recalculates images only two times.

    In your code program hangs before creating "Control" window, but you should see "image" window. You press any button and program continues. It hangs again one more time just before return. Then you should see "Control" window as well but basically nothing is going on in a meantime.

    Add a loop to enable processing and remove each other call to cv::waitKey from the rest of your code. This way program will recalulate both windows every milisecond.

    // rest of your code
    
    int key = 0;
    while(key != 27) { // 27 is escape
        // wait at most 1 ms for input, if nothing was pressed result is -1
        key = cv::waitKey(1);
    }
    return 0;
    

    Please, check out cv::waitKey docs for more info.


    I did not notice that your trackbars are created without callback argument - see createTrackbar docs. Also you may be interested in trackbar example. Having said that there are two approaches you can take:

    1. Call your HSVthreshold function in the while loop
    2. Create callback function and assign it as callback when you callcreateTrackbar

    Since I see that HSVthreshold parameters are not needed anyway you can change this function signature to match one required by createTrackbar and assign it as callback - so 2nd approach. Code should look like that:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>
    
    using namespace cv;
    using namespace std;
    
    Mat OutputImage;
    Mat image;
    
    int iLowH;
    int iHighH;
    int iLowS;
    int iHighS;
    int iLowV;
    int iHighV;
    
    double alpha;
    double beta;
    
    // From the docs: 
    // "Callback function should be prototyped as void Foo(int,void*);
    // first parameter is the trackbar position and the second parameter is the user data"
    // Both of these are not relevant to you at this point 
    static void HSVthreshold(int, void*)
    {
        inRange(image, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), OutputImage);
    }
    
    int main(int argc, char** argv)
    {
        image = imread("C:\\OpenCV-test-imgs\\blueberryTest1.jpg", 1);
    
        // Create all windows
        namedWindow("image", WINDOW_FREERATIO);
        namedWindow("Control", WINDOW_AUTOSIZE); 
        namedWindow("Output", WINDOW_AUTOSIZE);
    
        // Create trackbars in "Control" window - add callback HSVthreshold
        createTrackbar("LowH", "Control", &iLowH, 179, HSVthreshold); //Hue (0 - 179)
        createTrackbar("HighH", "Control", &iHighH, 179, HSVthreshold);
    
        createTrackbar("LowS", "Control", &iLowS, 255, HSVthreshold); //Saturation (0 - 255)
        createTrackbar("HighS", "Control", &iHighS, 255, HSVthreshold);
    
        createTrackbar("LowV", "Control", &iLowV, 255, HSVthreshold); //Value (0 - 255)
        createTrackbar("HighV", "Control", &iHighV, 255, HSVthreshold);
    
        int key = 0;
        while (key != 27) { 
            // Refresh images
            imshow("Output", OutputImage);
            imshow("image", image);
            key = waitKey(1);         
        }
        return 0;
    }