Python: вычислить площадь и периметр конструкций из массивов единиц и нулей. - PullRequest
1 голос
/ 13 июля 2020

Я столкнулся со следующей проблемой: у меня есть два 2D-массива единиц и нулей (одинаковой формы; (1920,1440)), которые определяют маски и очертания объектов. Здесь единицы указывают на пространство, занимаемое указанными объектами, а нули указывают на пустое пространство (единицы указывают на контуры, а нули указывают на пустое пространство соответственно).

Здесь вы можете найти графическое представление массива масок: https://ibb.co/v36TrJv и здесь вы можете найти графическое представление массива контуров: https://ibb.co/FxKwmTq. Единицы изображены белым, а нули - черным.

Как видите, маски образуют эллиптические структуры, которые не перекрываются, а контуры всегда образуют замкнутые контуры. Теперь я хотел бы вычислить площадь, занимаемую каждой структурой, а также периметр. В идеале я бы получил два 2D-массива с той же формой, что и входные массивы. Здесь первый массив будет содержать площадь каждой структуры в тех точках, где массив масок имеет значение, равное единице. Аналогично, второй массив будет удерживать соответствующий периметр каждой структуры в этих точках. Мне нужно, чтобы выходные массивы были в этой форме, чтобы я мог выполнять вычисления индекса формы и создавать графические представления результатов.

В качестве минимально воспроизводимого примера вы можете загрузить изображения по предоставленным ссылкам и использовать следующие код для извлечения из них массивов:

import skimage.io as sio
import numpy as np

masks = sio.imread("masks.png")
masks = np.mean(masks, axis =2)/255

outlines = sio.imread("outlines.png")
outlines = np.mean(outlines, axis=2)/255

Я уже немного поигрался с OpenCV, так как он, по-видимому, имеет функции, специально разработанные для приложений, которые я ищу. Но пока мои усилия не дали заметных результатов. Я попытался адаптировать пример кода из раздела функций контура в документах OpenCV (https://docs.opencv.org/trunk/dd/d49/tutorial_py_contour_features.html):

import cv2 as cv
img = cv.imread('masks.png',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
print(cnt)

Здесь результат, похоже, не тот, что я ищу для. Я также пытался отрегулировать порог, но безуспешно. Я не могу понять, какие корректировки мне нужно было бы внести, чтобы достичь желаемых результатов с помощью OpenCV.

Кроме того, я столкнулся с теоремой Грина (https://en.wikipedia.org/wiki/Green%27s_theorem) и рассматривал возможность его реализации для моей цели. Но я подумал, что сначала прошу внешней помощи, потому что чувствую, что должно быть более прямое решение моей проблемы. Любая помощь будет принята с благодарностью!

1 Ответ

2 голосов
/ 13 июля 2020

Контуры OpenCV сделают вашу работу. Я думаю, вы их неправильно понимаете. В вашем коде contours [0] даст только первый обнаруженный контур. Принимая во внимание, что вы должны перебирать переменную контуров, например for contour in contours:, а затем для каждого контура получить площадь и периметр, используя функции, указанные в do c, которым вы поделились, и сохранить эти данные в списке списка. Таким образом, ваш окончательный список будет иметь размер n × 2, где n - количество объектов на вашем изображении.

Кроме того, там предлагается найти контуры на изображении с объектами, заполненными единицами, и фоном с 0 как на первом изображении, которым вы поделились. Кроме того, на всякий случай, поскольку все ваши объекты разделены, используйте RETR_EXTERNAL в качестве флага при поиске контуров. Обратитесь к документации OpenCV, чтобы получить дополнительную информацию об этом.

...