首页 > 解决方案 > 轮廓的 arcLength 的结果是什么?

问题描述

我在 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 像素时的图像。

在此处输入图像描述

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

标签: c#opencvemgucv

解决方案


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))

输出:

[[  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]在轮廓中出现了两次,所以我们总共有四个轮廓点,两个相邻轮廓点之间的每个“距离”都是 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

我们得到六个轮廓点,两个相邻轮廓点之间的每个“距离”再次为 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]从to的“距离”[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
----------------------------------------

推荐阅读