12

As some kind of "holiday project" I'm playing around with OpenCV and want to detect and measure stuff.

Current workflow (early stage - detection):

  1. Convert to grayscale (cv::cvtColor)
  2. Apply Adaptive threshold (cv::adaptiveThreshold)
  3. Apply canny edge detection (cv::Canny)
  4. Finding contours (cv::findContours)

My outcome is kinda crappy and I'm not sure what's the right direction to go. I already got cvBlob working under my current setup (OSX 10.7.2, Xcode 4.2.1) is it a better way to go? If so, how can I implement it the right way?

Or do I need background subtraction first? I tried that but wasn't able to find contours afterwards

Here's my image: image to measure

And that's my output, when I draw my contours back into the first image: output

UPDATE

I got it working in my programm and my output looks a bit different …

- (IBAction)processImage:(id)sender
{
    cv::Mat forground = [[_inputView image] CVMat];
    cv::Mat result = [self isolateBackground:forground];
    [_outputView setImage:[NSImage imageWithCVMat:result]];
}

- (cv::Mat)isolateBackground:(cv::Mat &)_image
{
    int rh = 255, rl = 100, gh = 255, gl = 0, bh = 70, bl = 0;
    cv::cvtColor(_image, _image, CV_RGB2HSV_FULL);
    cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
    cv::Mat bgIsolation;
    cv::inRange(_image, cv::Scalar(bl, gl, rl), cv::Scalar(bh, gh, rh), bgIsolation);
    bitwise_not(bgIsolation, bgIsolation);
    erode(bgIsolation, bgIsolation, cv::Mat());
    dilate(bgIsolation, bgIsolation, element);
    return bgIsolation;
}
Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
dom
  • 11,894
  • 10
  • 51
  • 74

1 Answers1

11

This might be kind of a hack, but since it's a "holiday project", I'll post it anyway :)

Have you tried isolating the background and then inverting the mask (this would assume anything not background is an object, but it might work for what you want).

Below is the result I got using the OpenCV inRange function: enter image description here

You might want to smooth the image (pre-process) with GuassianBlur to get rid of some of the jagginess. I used a bigger dilation kernel than erosion kernel (5x5 vs. 3x3) to get rid of some noisy pixels. The smoothing might help this also tweaking the thresholds could make the erosion unnecessary. But, that should get you started.

Finally, here is my quick little code snippet I used to find this range:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    Mat src = imread("test.jpg");


    int rh = 255, rl = 100, gh = 255, gl = 0, bh = 70, bl = 0;

    string windowName = "background";
    namedWindow(windowName);

    createTrackbar("rh", windowName, &rh, 255);
    createTrackbar("rl", windowName, &rl, 255);
    createTrackbar("gh", windowName, &gh, 255);
    createTrackbar("gl", windowName, &gl, 255);
    createTrackbar("bh", windowName, &bh, 255);
    createTrackbar("bl", windowName, &bl, 255);

    // for dilation
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));

    Mat bgIsolation;
    int key = 0;
    do
    {
        inRange(src, Scalar(bl, gl, rl), Scalar(bh, gh, rh), bgIsolation);

        bitwise_not(bgIsolation, bgIsolation);

        erode(bgIsolation, bgIsolation, Mat());
        dilate(bgIsolation, bgIsolation, element);

        imshow(windowName, bgIsolation);
        key = waitKey(33);
    } while((char)key != 27);

    waitKey();

    return 0;
}

Enjoy the holiday project! Looks fun :)

mevatron
  • 13,911
  • 4
  • 55
  • 72
  • @moosgummi The reason you are getting a different output is because you are transforming to the HSV color space. My thresholds were for the RGB space. You can use HSV, but you'll need to find the appropriate ranges for that space. You could add that color conversion to my sample application, and try it out. I imagine you'll only need to worry about the Hue and Saturation channels as the Value channel doesn't contain any color info (i.e., the Value range would be left untouched [0, 255]). Hope that helps! – mevatron Dec 22 '11 at 14:50
  • Ah ok, so it should work better in RGB? bl, gl and rl are blue, green and red values. Am I right? – dom Dec 22 '11 at 15:18
  • For mac users, change `waitKey(33)` to `waitKey(500)` and `(char)key != 27` to `key != -1`. waitKey return values are different on different platforms but a timeout is always -1. This change will exit on any key press (not just escape). – Rick Smith May 28 '14 at 18:33
  • Also for anyone else who doesn't have the values show on the trackpad, I'll give you something to cut and paste: cout << "rh: " << rh << " rl: " << rl << " gh: " << gh << " gl: " << gl << " bh: " << bh << " bl: " << bl << endl; – Rick Smith May 28 '14 at 18:34