Search code examples
c++opencvmat

OpenCV: arcLength assert fails with cv::Mat


I tried to calculate contour perimeter using arcLength. The contour is read from the file into Mat which is a black and white picture of contour only. However, when I pass this Mat into function it throws an error:

Assertion failed (curve.checkVector(2) >= 0 && (curve.depth() == CV_32F || curve.depth() == CV_32S)) in arcLength

I have figured out that the actual cause is that curve.checkVector(2) returns -1. Although I have read the documentation about this method I still do not understand how to fix this error.
Here is the test image with corner points (1,1), (1,21), (21,21), (21,1)


Solution

  • The contour should be (from OpenCV doc):

    Input vector of 2D points, stored in std::vector or Mat.

    not a b/w image.

    You can compute the perimeter is different ways. The most robust is to use findContours to find external contours only (RETR_EXTERNAL), and call arcLength on that contour.

    A few examples:

    #include <opencv2\opencv.hpp>
    #include <vector>
    
    using namespace std;
    using namespace cv;
    
    int main()
    {
        Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
    
        // Method 1: length of unsorted points
        // NOTE: doesn't work!
    
        vector<Point> points;
        findNonZero(img, points);
        double len1 = arcLength(points, true);
        // 848.78
    
        // Method 2: length of the external contour
    
        vector<vector<Point>> contours;
        findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); // Retrieve only external contour
        double len2 = arcLength(contours[0], true);
        // 80
    
    
    
        // Method 3: length of convex hull of contour
        // NOTE: convex hull based methods work reliably only for convex shapes.
    
        vector<Point> hull1;
        convexHull(contours[0], hull1);
        double len3 = arcLength(hull1, true);
        // 80
    
        // Method 4: length of convex hull of unsorted points
        // NOTE: convex hull based methods work reliably only for convex shapes.
    
        vector<Point> hull2;
        convexHull(points, hull2);
        double len4 = arcLength(hull2, true);
        // 80
    
    
        // Method 5: number of points in the contour
        // NOTE: this will simply count the number of points in the contour.
        // It works only if: 
        //     1) findContours was used with option CHAIN_APPROX_NONE.
        //     2) the contours is thin (has thickness of 1 pixel).
    
        double len5 = contours[0].size(); 
        // 80
    
        return 0;
    }