First time here? Check out the FAQ!

Ask Your Question
4

How to resize a contour?

asked Oct 16 '14

thdrksdfthmn gravatar image

updated Nov 28 '0

I have an application that detects an object by finding its contour. Because the image where I search for the object may be at a very big scale is affecting my detection because the contour can be too long and I skip the contours longer than a threshold. For fixing this, I have thought of resizing the image larger than a maximum size to that maw size. Doing so, I am detecting the object in the smaller image, and when drawing the contour on the initial image, I am getting a "wrong detection". Is there a possibility to resize the contour?

Preview: (hide)

Comments

Hmm afaik contours are actually for visualisation purposes and for creating masks. Resizing them will not be that easy. How about the following approach

  1. Use the contour to make a binary mask.
  2. Apply a resize operation on that binary mask, which is possible since it is a data matrix.
  3. Now use findContours again on that binary image to change it back to an active contour.

Would this suit your needs?

StevenPuttemans gravatar imageStevenPuttemans (Oct 17 '14)edit
1

If I just do the (x, y) -> (resizer * x, resizer * y) is not correct? Actually I am trying to test this. (x and y are both positive)

thdrksdfthmn gravatar imagethdrksdfthmn (Oct 17 '14)edit
1

That was my first tought. But I am not sure if this will actually work for each point. You should test and report back :)

StevenPuttemans gravatar imageStevenPuttemans (Oct 17 '14)edit

Great! Yeah my approach suffers from artefacts ... hadn't thought on that...

StevenPuttemans gravatar imageStevenPuttemans (Oct 17 '14)edit

2 answers

Sort by » oldest newest most voted
3

answered Oct 17 '14

thdrksdfthmn gravatar image

updated Oct 5 '15

Nice, it is working, and it is working very nice. More, your idea of resizing the mask is introducing errors, because the cv::fillPoly is introducing errors (small "stairs") and resizing it is just making the errors to appear in the new contour, and they are even bigger.

Sample code :

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

int main( int argc, char** argv )
{
    vector<vector<Point> > contours;
    Mat img = Mat::zeros( 500, 500, CV_8UC1 );

    circle( img, Point(250,250), 100, Scalar(255) );

    findContours( img, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

    fillConvexPoly( img, Mat( contours[0] ) / 2, Scalar(255)); // draws contour resized 1x/2

    polylines( img, Mat( contours[0] ) * 2, true, Scalar(255)); // draws contour resized 2x

    imshow("result",img);
    waitKey();

    return 0;
}

result image:

image description

Preview: (hide)
5

answered Apr 13 '18

updated Aug 31 '18

You can use the following method to resize the contour by keeping the contour center like the morphology operation.

    void contourOffset(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, const cv::Point& offset) {
    dst.clear();
    dst.resize(src.size());
    for (int j = 0; j < src.size(); j++)
        dst[j] = src[j] + offset;

}
void scaleContour(const std::vector<cv::Point>& src, std::vector<cv::Point>& dst, float scale)
{
    cv::Rect rct = cv::boundingRect(src);

    std::vector<cv::Point> dc_contour;
    cv::Point rct_offset(-rct.tl().x, -rct.tl().y);
    contourOffset(src, dc_contour, rct_offset);

    std::vector<cv::Point> dc_contour_scale(dc_contour.size());

    for (int i = 0; i < dc_contour.size(); i++)
        dc_contour_scale[i] = dc_contour[i] * scale;

    cv::Rect rct_scale = cv::boundingRect(dc_contour_scale);

    cv::Point offset((rct.width - rct_scale.width) / 2, (rct.height - rct_scale.height) / 2);
    offset -= rct_offset;
    dst.clear();
    dst.resize(dc_contour_scale.size());
    for (int i = 0; i < dc_contour_scale.size(); i++)
        dst[i] = dc_contour_scale[i] + offset;
    }

void scaleContours(const std::vector<std::vector<cv::Point>>& src, std::vector<std::vector<cv::Point>>& dst, float scale)
{
    dst.clear();
    dst.resize(src.size());
    for (int i = 0; i < src.size(); i++)
        scaleContour(src[i], dst[i], scale);
}
        void main(){
            std::vector<std::vector<cv::Point>> src,dst;
            scaleContours(src,dst,0.95);
         }

In the sample below, the green contour is main contour and the red contour is scaled contour with a coefficient of 0.95. image description

Preview: (hide)

Comments

1

nice to have you back here ;)

berak gravatar imageberak (Apr 13 '18)edit

Is there an equivalent python code for this? If not would be very grateful if you could please explain the process on the code above.

fzuffer gravatar imagefzuffer (Jun 9 '18)edit

i don't think, we have a python example,but the algorithm is:

  • find the center of the contour (moments() or getBoundingRect())
  • subtract it from each point in the contour
  • multiply contour points x,y by a scale factor
  • add the center again to each point
berak gravatar imageberak (Jun 9 '18)edit
1

Thank You very much for the quick response.. Appreciate it a lot.

fzuffer gravatar imagefzuffer (Jun 9 '18)edit

Question Tools

Stats

Asked: Oct 16 '14

Seen: 21,773 times

Last updated: Dec 05 '18