等高线的 arcLength 结果是什么?

What is the result of arcLength for a contour?

我在 Google 中搜索了 arcLength,好吧,也许我能理解它,但是它如何在 EmguCV 或 OpenCV 中对图像中的轮廓起作用?我尝试使用 MATLAB 制作一个小图像。图像是 9 x 9,我在图像中画了一条线,那条线是 1 个像素。我在 EmguCV 中使用这段代码来检测轮廓:

VectorOfVectorOfPoint cons = new VectorOfVectorOfPoint();

        CvInvoke.FindContours(img_gray, cons, null, RetrType.List, ChainApproxMethod.ChainApproxNone);
        for(int i=0; i<cons.Size;i++)
        {
            VectorOfPoint points = cons[i];
            for(int x =0; x<points.Size;x++)
            {
               temp[points[x]] = new Gray(255);
            }
           double c= CvInvoke.ArcLength(cons[i], true);
            textBox1.Text = c.ToString();             
        }

        imageBox2.Image = temp;

arcLength 是:

这是我在线条为 3 像素时的图像。

谁能给我解释一下结果吗?

arcLength 确实如其所言:

Calculates a contour perimeter or a curve length.

在您的示例中,您被 findContours(!) 的特定问题所愚弄,即应用于 1 像素宽的线条时! (实施问题、算法问题、"border following" 的一般问题,...!?)

让我们看看下面的例子(很抱歉在这里使用Python API,但是概念应该清楚了)。


示例 1: 3 x 1 黑色图像上的白线

import cv2
import numpy as np

# Generate 5 x 5 black image
img = np.zeros((5, 5), np.uint8)

# Draw 3 x 1 white line
img = cv2.rectangle(img, (1, 1), (3, 1), 255, cv2.FILLED)

# Find contours
cnts = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]

# Outputs
print(img, '\n')                                    # Image
print(np.squeeze(cnts[0]), '\n')                    # Contour
print('Contour points:', cnts[0].shape[0], '\n')    
print('arcLength:', cv2.arcLength(cnts[0], True))

输出:

[[  0   0   0   0   0]
 [  0 255 255 255   0]
 [  0   0   0   0   0]
 [  0   0   0   0   0]
 [  0   0   0   0   0]] 

[[1 1]
 [2 1]
 [3 1]
 [2 1]] 

Contour points: 4 

arcLength: 4.0

请注意,[2 1]在轮廓中出现了两次,所以我们总共有四个轮廓点,两个相邻轮廓点之间的每个"distance"都是1,因此轮廓周长(=弧长)也是 4.


示例 2: 3 x 2 黑色图像上的白色矩形

import cv2
import numpy as np

# Generate 5 x 5 black image
img = np.zeros((5, 5), np.uint8)

# Draw 3 x 2 white rectangle
img = cv2.rectangle(img, (1, 1), (3, 2), 255, cv2.FILLED)

# Find contours
cnts = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]

# Outputs
print(img, '\n')                                    # Image
print(np.squeeze(cnts[0]), '\n')                    # Contour
print('Contour points:', cnts[0].shape[0], '\n')
print('arcLength:', cv2.arcLength(cnts[0], True))

输出:

[[  0   0   0   0   0]
 [  0 255 255 255   0]
 [  0 255 255 255   0]
 [  0   0   0   0   0]
 [  0   0   0   0   0]] 

[[1 1]
 [1 2]
 [2 2]
 [3 2]
 [3 1]
 [2 1]] 

Contour points: 6 

arcLength: 6.0

我们得到六个轮廓点,并且两个相邻轮廓点之间的每个 "distance" 都是 1,因此轮廓周长(= 弧长)也是 6 – 这似乎(更)合理。


示例 3: 黑色图像上半径为 2 的白色圆圈

import cv2
import numpy as np

# Generate 5 x 5 black image
img = np.zeros((5, 5), np.uint8)

# Draw white circle with radius 2
img = cv2.circle(img, (2, 2), 2, 255, cv2.FILLED)

# Find contours
cnts = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]

# Outputs
print(img, '\n')                                    # Image
print(np.squeeze(cnts[0]), '\n')                    # Contour
print('Contour points:', cnts[0].shape[0], '\n')
print('arcLength:', cv2.arcLength(cnts[0], True))

输出:

[[  0   0 255   0   0]
 [  0 255 255 255   0]
 [255 255 255 255 255]
 [  0 255 255 255   0]
 [  0   0 255   0   0]] 

[[2 0]
 [1 1]
 [0 2]
 [1 3]
 [2 4]
 [3 3]
 [4 2]
 [3 1]] 

Contour points: 8 

arcLength: 11.313708305358887

[2 0][1 1] 的 "distance" 是 1.414...(2 的平方根)。每两个相邻的轮廓点都有那个距离(见图),所以我们的轮廓周长(=弧长)为 8 * 1.414... = 11.313...


希望对理解有所帮助!

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
NumPy:       1.18.1
OpenCV:      4.2.0
----------------------------------------