Search code examples
c++opencvimage-processingcontour

Excluding or skipping contrours in the corners of image


I have a camera under a glass with IR light to detect objects. I can find the contours and draw them using the following code (I just found some examples online and modified it to my need so I am not a master at all!).

using namespace cv;

cvtColor(mat, mat, COLOR_BGR2GRAY);
blur(mat, mat, Size(3,3));

erode(mat, mat, NULL, Point(-1,-1), 2);
dilate(mat, mat, NULL, Point(-1,-1), 2);
Canny(mat, mat, 100, 200);

auto contours = std::vector<std::vector<Point>>();
auto hierarchy = std::vector<Vec4i>();
findContours(mat, contours, hierarchy, CV_RETR_TREE,
             CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

Mat drawing = Mat::zeros(mat.size(), CV_8UC3);
for( int i = 0; i< contours.size(); i++ ) {
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255),
                           rng.uniform(0,255));
    drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}

putText(mat,
        (QString("Blobs: %1").arg(contours.size())).toStdString(),
        Point(25,175), cv::FONT_HERSHEY_PLAIN, 10, CV_RGB(0, 0, 255), 2);

This code results in a nice finding of the contours that I am quite happy with. Except the fact that my IR light somehow makes artifacts at the corners and bottom of the image.

enter image description here

You can see that I have used gimp to highlight the areas that I want to ignore while searching for contours. Under the gray shade you see the white pixels that my original code detects as contours. These areas are problematic and I want to exclude them from the either contour search or contour drawing (whichever is easier!)

I was thinking of cropping the image to get the ROI but the cropping is a rectangle while I (for example) could have things to be detected i.e. exactly at leftmost area.

I think there should be some data in the contour that tells me where are the pixels but I could not figure it out yet...


Solution

  • The easiest way would be to simply crop the image. Areas of the image are known as ROIs in OpenCV, which stands for Region of Interest.

    So, you could simply say

    cv::Mat image_roi = image(cv::Rect(x, y, w, h));
    

    This basically makes a rectangular crop, with the top left corner at x,y, width w and height h.

    Now, you might not want to reduce the size of the image. The next easiest way is to remove the artifacts is to set the borders to 0. Using ROIs, of course:

    image(cv::Rect(x, y, w, h)).setTo(cv::Scalar(0, 0, 0));
    

    This sets a rectangular region to black. You then have to define the 4 rectangular regions on the borders of your image that you want dark.

    Note that all of the above is based on manual tuning and some experimentation, and it would work provided that your system is static.