Ask Your Question
0

Issue Masking Input Image to findContours [closed]

asked 2015-07-25 09:15:49 -0600

MdK8 gravatar image

updated 2015-07-27 03:42:43 -0600

Hi,

I am currently implementing obstacle detection using the camera output of a robot's floor-directed video camera. Using canny edge detection as preprocessing I am able to efficiently find contours using findContours. Whenever I find sufficient amounts of contours I send out an obstacle warning. So far so good - code compiles and works using laptop camera. The last remaining issue is that the robot films its own body using the camera (i.e. its base and wheels) and I obviously do not consider them to be obstacles and would hence like to exclude them from contour finding. Seeing that neither canny nor findContours provide masking functionality, I decided to mask the input myself. So what I am currently doing is performing canny edge on the whole image and then overwriting the area to be ignored with zeroes (i.e. color black), before I pass the image to find contours. I do this using copyTo(). However findContours throws an "Unrecognized or unsupported array type in function cvGetMat" exception if my mask indicates to overwrite nothing, and copyTo() an "EXC_BAD_ACCESS" exception if my mask indicates to overwrite everything. I am unable to trace this error, as I assert type and size equality before using copyTo() and input and mask are static and therefore never empty. I would highly appreciate some feedback. I am guessing I am making a very fundamental mistake, as copyTo() should copy nothing given the code below (with the empty mask) and therefore the code should run just as before.

Any feedback is appreciated.

Warm regards,
Mark

int detectFloor(VideoCapture floorCam){

if( !floorCam.isOpened() ){
    cout << "Could not initialize capturing...\n";
    return 0;
}

Mat frame, image, gray, canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
RNG rng(12345);
Mat black(720,1280,CV_8U,0); // The black pixels I am copying later on
Mat mask(720,1280,CV_8U,0); // When to copy them (currently never) - I need to actually build the real mask

// Sensitivity of the contour detection
int thresh = 100;
// Sensitivity of obstacle detection i.e. number of contours needed to raise warning
int critical = 10;

for(;;){
    // Capture a 1280*720 frame
    floorCam >> frame;
    if( frame.empty() )
        break;
    frame.copyTo(image);

    // Convert image to gray for better accuracy during contour detection
    cvtColor(image, gray, COLOR_BGR2GRAY);
    // Blur image to remove disturbances
    blur( gray, gray, Size(3,3) );

    // Detect edges using canny to preprocess image for contour detection
    Canny( gray, canny_output, thresh, thresh*2, 3 );
    // Mask robot from canny_output by filling that area of the image with black
    // That way robot contours will be ignored during detection
    assert(black.size() == canny_output.size());
    assert(black.type() == canny_output.type());
    black.copyTo(canny_output, mask);
    // Find contours i.e. curves that join continuous points having same color or intensity
    findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
    // Contours indicate presence of alien entities
    // Therefore check if sufficient numbers of contours are present to raise alarm
    if (contours.size() > critical)
        cout << "Warning! Obstacle detected - " << contours.size() << " contours found." << endl;
}
return(0);
}

EDIT: Alternative approach using ... (more)

edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by MdK8
close date 2015-07-27 11:18:45.562798

Comments

1

I think your creation of black could be the problem. Try CV_8UC1 instead of CV_8U. Then it is a 1 channel image. This is a requirement of findContours() and could explain the "unsupported array type error".

Instead of check with assert(black.size() == canny_output.size()); and assert(black.type() == canny_output.type()); you can do black.create(canny_output.size(), canny_output.type(), 0);

Consider that copyTo() does not do a deep copy in cases the target image is not allocated, but only copies the header.

Another problem you should check is, if it is working when you copy the valid areas from canny_ouput to black and using black in the findContours() function. I'm not sure what happenes when you copy nothing from black to canny_output

matman gravatar imagematman ( 2015-07-25 14:20:10 -0600 )edit

Hi Matman, thank you for your reply! As far as I'm aware CV_8UC1 and CV_8U evaluate to the same type. In accordance with that knowledge changing the type did not help. black.create() also yielded the same errors. Anyway, I came up with a simpler code that now at least runs, but gives me a black image every iteration, regardless of the contents of mask. I now simply use setTo() to directly change the canny_output to avoid errors while copying. I'll attach the revised code to my initial post.

MdK8 gravatar imageMdK8 ( 2015-07-27 03:35:26 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2015-07-27 11:18:16 -0600

MdK8 gravatar image

Turns out that the constructor of Mat does not except numbers as arguments to the init_valueparameter, but requires use of Scalar()in order to work. As a consequence mask and black both had data nullpointers.

edit flag offensive delete link more

Comments

ahh, common pitfall, i did not see it either. at least, it was fixed in opencv3.0 !

berak gravatar imageberak ( 2015-07-27 11:23:59 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-07-25 09:15:49 -0600

Seen: 1,847 times

Last updated: Jul 27 '15