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