Ask Your Question

Opencv findCountours is not find all contours

asked 2018-08-08 09:54:25 -0600

I'm trying to find the contours of this image, but the method findContours only returns 1 contour, the contour is highlighted in image 2. I'm trying to find all external contours like these circles where the numbers are inside. What am i doing wrong? What can i do to accomplish it?

image description image 1

image description image 2

Below is the relevant portion of my code.

thresh = cv2.threshold(image, 0, 255,
                           cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
edit retag flag offensive close merge delete



you will find the answer in the documentation

sturkmen gravatar imagesturkmen ( 2018-08-08 10:02:35 -0600 )edit

@sturkmen i tried the other options like "RETR_LIST" but it seems to find the same border twice. I'm trying to detect these circles but when i try "RETR_LIST" or others it returns the same contour of each circle twice.

zzbruno gravatar imagezzbruno ( 2018-08-08 11:05:08 -0600 )edit

After the thresholding apply a bitwise not then apply findContours but with RETR_TREE. findContours return three outputs, the image, the contours and a hierachy matrix. The hierarchy matrix contains a relashionship of the contours. You can refine it in order to only keep the hierarchy that fit your purpose

js4267 gravatar imagejs4267 ( 2018-08-09 08:32:36 -0600 )edit

2 answers

Sort by ยป oldest newest most voted

answered 2018-08-08 12:39:28 -0600

updated 2018-08-08 12:45:16 -0600

i modified /samples/cpp/contours2.cpp

i hope it will be a good start to solve your problem.

try to find a way for better result ( you can filter contours using their roundness ) or wait my update.

image description

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

const int w = 500;
int levels = 3;

vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

static void on_trackbar(int, void*)
    Mat cnt_img = Mat::zeros(w, w, CV_8UC3);
    int _levels = levels - 3;
    drawContours( cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128,255,255),
                  1, LINE_AA, hierarchy, std::abs(_levels) );

    imshow("contours", cnt_img);

int main( int, char** argv)
    Mat img = imread(argv[1], 0);
    img = img < 170;
    imshow( "image", img );
    //Extract the contours so that
    vector<vector<Point> > contours0;

    findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

    for( size_t k = 0; k < contours0.size(); k++ )
        approxPolyDP(Mat(contours0[k]), contours[k], 3, true);

    namedWindow( "contours", 1 );
    createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );


    return 0;
edit flag offensive delete link more

answered 2018-08-15 17:06:47 -0600

js4267 gravatar image

updated 2018-08-16 01:02:50 -0600


This solution is not optimal but ... it work in such case:

import numpy as np import cv2 from matplotlib import pyplot as plt

I = cv2.imread('ext_contours.png',cv2.IMREAD_GRAYSCALE)

_,I = cv2.threshold(I,0.,255.,cv2.THRESH_OTSU)
I = cv2.bitwise_not(I)

_,labels,stats,centroid = cv2.connectedComponentsWithStats(I)

result = np.zeros((I.shape[0],I.shape[1],3),np.uint8)

for i in range(0,labels.max()+1):
    mask =,i,cv2.CMP_EQ)

    _,ctrs,_ = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    result = cv2.drawContours(result,ctrs,-1,(0xFF,0,0))


Hope it helps.

edit flag offensive delete link more

Question Tools

1 follower


Asked: 2018-08-08 09:54:25 -0600

Seen: 1,960 times

Last updated: Aug 16 '18