Я бы предложил вычислить маску, как в ответе Натанси , но затем просто подсчитать количество пикселей в маске opening
, которую он вычислил (что является объективной оценкой площади отверстия) и затем переводим область в радиус, используя radius = sqrt(area/pi)
. Это даст вам радиус круга с той же площадью, что и отверстие, и соответствует одному методу для получения круга наилучшего соответствия.
Другой способ получения круга наилучшего соответствия - это взять контур дыра (как возвращено в cnts
на cv.findContours
в ответе Нэтэнси), нахождение ее центроида , а затем вычисление среднего расстояния каждой вершины до центроида. Это приблизительно соответствует * подгонке круга наименьших квадратов к периметру отверстия.
* Я говорю приблизительно, потому что вершины контура являются приближением к контуру, а расстояния между этими вершинами скорее всего не равномерно. Однако ошибка должна быть очень маленькой.
Вот пример кода с использованием DIPlib (раскрытие: я автор) (примечание: для утверждения import PyDIP
, приведенного ниже, требуется вы устанавливаете DIPlib, и вы не можете установить его с pip
, на странице GitHub есть бинарный выпуск для Windows, или вам нужно собрать его из исходников).
import PyDIP as dip
import imageio
import math
img = imageio.imread('https://i.stack.imgur.com/szvc2.jpg')
img = dip.Image(img[:,2600:-1])
img.SetPixelSize(0.01, 'mm') # Use your actual values!
bin = ~dip.OtsuThreshold(dip.Gauss(img, [3]))
bin = dip.Opening(bin, 25)
#dip.Overlay(img, bin - dip.BinaryErosion(bin, 1, 3)).Show()
msr = dip.MeasurementTool.Measure(dip.Label(bin), features=['Size', 'Radius'])
#print(msr)
print('Method 1:', math.sqrt(msr[1]['Size'][0] / 3.14), 'mm')
print('Method 2:', msr[1]['Radius'][1], 'mm')
MeasurementTool.Measure
функция вычисляет 'Size'
, которая является областью; и 'Radius'
, который возвращает максимальное, среднее, минимальное и стандартное отклонение расстояний между каждым граничным пикселем и центроидом. Из 'Radius'
мы берем 2-е значение, средний радиус.
Это выводит:
Method 1: 7.227900647539411 mm
Method 2: 7.225178113501325 mm
Но обратите внимание, что я назначил случайный размер пикселя (0,01 мм на пиксель), вам нужно будет указать правильное значение преобразования пикселов в мм.
Обратите внимание, что эти две оценки очень близки. Оба метода хорошие, объективные оценки. Первый метод в вычислительном отношении дешевле.