What's the middle dimension for the result of findCountours?

findCountours returns a list of arrays.
What does the middle dimension for the contours represent?

contours[0].shape -> (136, 1, 2)

It’s an array of 136 points and a point is an array of 1 row and 2 columns

Yes. We have: (point, ??, xy)
Why arity 3 indexes when 2, (point, xy), is sufficient?

Let me explain. It all begins in C++.

cv::Mat is not quite a matrix. it’s an image container. it has a number of rows and columns, but also a number of channels.

each entry of the matrix can be a single number, but it can also be a “vector”, or cv::Scalar (really a vector). for images, a cv::Mat has 3 channels or something like that.

This “Scalar” thing is convenient because now you can index a single element of the matrix and you get a Scalar/vector. you don’t need to “select the row”, as you would otherwise.

the result of findContours is a list of contours. each contour is a Mat, containing the points. the points are put into the Mat as a “column vector” of points.

that means the Mat is Nx1, and 2-channel (CV_32SC2 perhaps), so it can hold (x,y) Points.

the mapping from cv::Mat to numpy array always maps to (nrows, ncols, nchannels) or (nrows, ncols) if there’s just one channel (grayscale image or “actual” matrix data).

that’s why you get (N, 1, 2).

2 Likes

just for the record, starting with 4.6.0, python bindings changed, the additional dimension (wrapping std::vector<T>) was removed, so we have:

  • pre 4.6
    std::vector<cv::Point> -> [N, 1, 2]
  • post 4.6
    std::vector<cv::Point> -> [N, 2]

(just saying, not all of the python samples might be up to date here !)

1 Like
import cv2 as cv
import numpy as np
img = np.zeros((256, 256), np.uint8)
cv.rectangle(img,(160, 100, 50, 20), 255, -1)
img = cv.circle(img, (50,50), 20, 255, -1)
ctr, _ =cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)

then ctr is a list

>>> len(ctr)
2

and

>>> ctr[0].shape
(136, 1, 2)

and

>>> print(cv.getBuildInformation())

General configuration for OpenCV 4.7.0-dev =====================================
  Version control:               4.7.0-185-g61d255887c

  Extra modules:
    Location (extra):            C:/lib/opencv_contrib/modules
    Version control (extra):     4.7.0-31-g853144ef
2 Likes

that’s because std::vector<cv::Mat> are returned, not vectors of cv::Points. I don’t believe that std::vector<cv::Point> ever mapped to an additional dimension, so that is irrelevant to the situation.

1 Like