# Canny on a concave grayscale, the result contours can not end in closure

**URL:** <https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196>\
**Category:** C++\
**Created:** [September 14, 2022, 10:04am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196 "2022-09-14T10:04:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![victor](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/victor/32/6052_2.png) [@victor](https://forum.opencv.org/u/victor)\
**Post date:** [September 14, 2022, 10:04am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/1 "2022-09-14T10:04:27Z")

</div>

![image](https://us1.discourse-cdn.com/flex020/uploads/opencv/original/2X/1/1ddb5fb4cbf59ac1ba4e520360e8e449d35ad48b.png)  
i have a grayscale which has only binary color (on left of above image), run Canny on it, the right part of above image is result. The result contours can not end in closure, the contours just wrap the border like the right line. So points like (60,50)(70,60) are out of polygon from contours by using cv::pointPolygonTest.

simple test code as following:

```auto
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

using namespace cv;
using namespace std;

#define AREA_COLOR_IN_GRAYSCALE 100

Mat ReadGrayscale(const char* filename)
{
    Mat src = imread(filename);
    if( src.empty() )
    {
        printf("Could not open or find the image!\n");
    }
    return src;
}

void GetContoursAndGenPolygon(const char *filename)
{
    int32_t threshH = AREA_COLOR_IN_GRAYSCALE - 1;
    int32_t threshL = threshH >> 1;
    Mat grayscale = ReadGrayscale(filename);
    Mat edgeMat;
    Canny(grayscale, edgeMat, threshL, threshH);

    cv::imwrite("edge.ppm", edgeMat);

    vector<vector<Point> > contours;
    findContours(edgeMat, contours, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE );

    for( size_t i = 0; i< contours.size(); i++ )
    {
        printf("contour[%zd] has %zd points\n", i, contours[i].size());

        for (const auto& p : contours[i])
        {
            printf("(%d,%d) ", p.x, p.y);
        }
        printf("\n");        
    }

    auto checkPolygon = [&](cv::Point2f p)
    {
        double d = cv::pointPolygonTest(contours[0], p, false);
        printf("(%.0f,%.0f) is %s polygon, d %.2f\n", p.x, p.y, (d >= 0.0) ? "in" : "out of", d);
    };
    if (contours.size() >= 1)
    {
        checkPolygon(cv::Point2f(60,50));
        checkPolygon(cv::Point2f(70,60));
    }
}

int main( int argc, char** argv )
{
    printf("opencv verison %d.%d\n", CV_MAJOR_VERSION, CV_MINOR_VERSION);
    GetContoursAndGenPolygon("concave.ppm");
    return 0;
}

```

the output

```auto
opencv verison 3.3
contour[0] has 29 points
(57,46) (55,48) (55,51) (56,52) (64,52) (65,53) (65,64) (66,65) (72,65) (72,54) (71,53) (67,53) (71,53) (72,54) (72,64) (71,65) (66,65) (65,64) (65,53) (64,52) (56,52) (55,51) (55,48) (57,46) (65,46) (66,47) (66,51) (66,47) (65,46) 
(60,50) is out of polygon, d -1.00
(70,60) is out of polygon, d -1.00

```

**My questions:**  
**1. why contours are not closed around point (66,52)**  
**2. how to avoid it, i want to get a correct polygon**

---

<div class="post-metadata">

**Author:** ![victor](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/victor/32/6052_2.png) [@victor](https://forum.opencv.org/u/victor)\
**Post date:** [September 14, 2022, 10:05am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/2 "2022-09-14T10:05:12Z")

</div>

![concave](https://us1.discourse-cdn.com/flex020/uploads/opencv/original/2X/2/2fb3d7921875ac2decb7e83330d972cd339837ed.jpeg)  
source image with extension jpg

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [September 14, 2022, 11:40am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/3 "2022-09-14T11:40:54Z")

</div>

**don’t** use Canny here. Canny is rarely useful and most often _harms_ because beginners think they have to apply it to everything.

simply apply `findContours`.

who told you that you should use Canny for this?

---

<div class="post-metadata">

**Author:** ![victor](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/victor/32/6052_2.png) [@victor](https://forum.opencv.org/u/victor)\
**Post date:** [September 14, 2022, 12:00pm UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/4 "2022-09-14T12:00:04Z")

</div>

> [@crackwitz](#):
>
> findContours

3ks a lot.  
it works to just apply findContours on grayscale. great!  
I reference some opencv doc, such as [this](https://docs.opencv.org/4.x/df/d0d/tutorial_find_contours.html), it **Canny** and then **findContours** , so i thought it was a correct routine

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [September 14, 2022, 1:39pm UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/5 "2022-09-14T13:39:53Z")

</div>

> [@victor](#):
>
> [this](https://docs.opencv.org/4.x/df/d0d/tutorial_find_contours.html)

wow that thing is rubbish. “you will learn”, yeah right, code dump, tada, curtain call. I’m sorry you had to see that article. one of these days I’ve got to put big red warning signs on every use of Canny in the docs.

it’s absolutely _not_ something to just apply for the hell of it. just like an appendectomy, it’s an intervention with serious negative consequences, and only justified if all its effects are acknowledged.

as long as you have clear contrast, meaning two distinct “modes” in the histogram that are easy to _threshold_ globally, all methods that _need_ a mask (binarized image) will just work.

if you _don’t_ have that, i.e. you need to deal with multiple contrasts at various levels, you would want to apply some kind of “highpass” filter, to move those modes such that you _can_ threshold easily. that’s still not where Canny is used.

Canny implicitly calculates _edges/gradients_ of the image. that is done when you don’t care about the levels in your picture, just the edges. Canny is an extremely crude _postprocessing_ step applied _after_ having an edge map. it _adaptively thresholds_ the edge map of a picture, i.e. first an edge map is computed (a general operation) and then Canny comes along and binarizes that adaptively.

you don’t need a highpass or an edge map. you just needed to threshold the picture to clearly differentiate black from gray. in your case, the background is already black (zero) and the foreground is gray (nonzero), so that can already be interpreted as a binary mask.

---

<div class="post-metadata">

**Author:** ![victor](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/victor/32/6052_2.png) [@victor](https://forum.opencv.org/u/victor)\
**Post date:** [September 15, 2022, 3:06am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/6 "2022-09-15T03:06:42Z")

</div>

thank you for your explanation about Canny.  
Let me simplify my case. My goal is to extract polygon (rectangle is preferred if possible) for gray pattern in the image.I have already generated a binarized image and smoothed it, so just findContours on it will work.  
is there anything else i should take care, or any more advice?

---

<div class="post-metadata">

**Author:** ![victor](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/victor/32/6052_2.png) [@victor](https://forum.opencv.org/u/victor)\
**Post date:** [September 16, 2022, 2:22am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/7 "2022-09-16T02:22:41Z")

</div>

> [@crackwitz](#):
>
> you don’t need a highpass or an edge map. you just needed to threshold the picture to clearly differentiate black from gray. in your case, the background is already black (zero) and the foreground is gray (nonzero), so that can already be interpreted as a binary mask.

thank you for your explanation about Canny.  
Let me simplify my case. My goal is to extract polygon (rectangle is preferred if possible) for gray pattern in the image.I have already generated a binarized image and smoothed it, so just findContours on it will work.  
is there anything else i should take care, or any more advice?

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [September 16, 2022, 10:06am UTC](https://forum.opencv.org/t/canny-on-a-concave-grayscale-the-result-contours-can-not-end-in-closure/10196/8 "2022-09-16T10:06:08Z")

</div>

findContours is sufficient.
