轮廓的 arcLength 的结果是什么?

Sal*_*7ty 2 c# opencv emgucv

我在 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;
Run Code Online (Sandbox Code Playgroud)

arcLength曾是:

  • 当线条为 1 像素时 ->arcLength为 0。
  • 当线条为 2 个像素时 ->arcLength为 2。
  • 当线条为 3 像素时 ->arcLength为 4。

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

在此输入图像描述

任何人都可以向我解释一下结果吗?

Han*_*rse 12

arcLength确实如其所声称的那样:

计算轮廓周长或曲线长度。

在您的示例中,您被findContours(!) 的特定问题所愚弄,即应用于 1 像素宽的线条时!(实现问题,算法问题,“边界跟踪”的一般问题,......!?)

让我们看一下下面的示例(很抱歉在这里使用了 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))
Run Code Online (Sandbox Code Playgroud)

输出:

[[  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
Run Code Online (Sandbox Code Playgroud)

请注意,这[2 1]在轮廓中出现了两次,所以我们总共有四个轮廓点,并且两个相邻轮廓点之间的每个“距离”都是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))
Run Code Online (Sandbox Code Playgroud)

输出:

[[  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
Run Code Online (Sandbox Code Playgroud)

我们得到六个轮廓点,两个相邻轮廓点之间的每个“距离”都是 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))
Run Code Online (Sandbox Code Playgroud)

输出:

[[  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
Run Code Online (Sandbox Code Playgroud)

[2 0]到 的“距离”[1 1]是 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
----------------------------------------
Run Code Online (Sandbox Code Playgroud)