Каков результат arcLength для контура? - PullRequest
0 голосов
/ 12 февраля 2020

Я искал arcLength в Google, и хорошо, может быть, я могу понять это, но как это работает для контуров в изображении в 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 было:

  • Когда линия 1 пиксель -> arcLength было 0.
  • Когда линия 2 пикселя -> arcLength было 2.
  • Когда строка 3 пикселя -> arcLength было 4.

Это мое изображение, когда линия 3 пикселя.

enter image description here

Может ли кто-нибудь объяснить мне результаты?

1 Ответ

2 голосов
/ 12 февраля 2020

arcLength делает именно то, что заявляет:

Вычисляет периметр контура или длину кривой.

В вашем примере (s) ) вас одурачивает специфическая проблема c с 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, таким образом, периметр контура (= ar c длина) также равен 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, так что периметр контура (= ar c длина) также равен 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] равно 1,414 ... (квадрат root из 2). Каждые две соседние точки контура имеют это расстояние (см. Изображение), поэтому у нас есть периметр контура (= ar c длина) 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
----------------------------------------
...