#python #opencv #photoshop #cv2 #opencv-python
#python #opencv #обработка изображений #математическая морфология
Вопрос:
У меня есть маска выделения на изображении в cv2, и я хочу расширить выделение пикселей таким образом, чтобы каждый пиксель в радиусе R от уже выбранного пикселя мог быть добавлен к выделению.
Я бы хотел, чтобы он работал идентично функции расширения в Photoshop.
Единственный способ, который я могу себе представить, чтобы сделать это, — посмотреть на каждый пиксель на изображении, и если он находится в выделении, затем измените каждый пиксель в радиусе R, чтобы он был частью выделения.
Большая проблема с этим заключается в том, что у него время выполнения O (R ^ 2 * # пикселей).
Это действительно медленно, и я знаю, что должен быть лучший способ, потому что метод расширения выделения Photoshop работает почти мгновенно даже для больших изображений. Итак, я хотел бы найти способ изменить мой метод в cv2 или в numpy, чтобы сделать его быстрее. (может быть, есть способ его векторизации, но я не знаю)
Комментарии:
1. вы говорите «мой метод», но не показываете его в своем вопросе.
Ответ №1:
Попытка другого решения все еще казалась очень медленной,
def expand(selection, radius):
kernel = np.array([[x**2 y**2 for x in range(-radius,radius 1)]
for y in range(-radius,radius 1)]) < (radius 1)**2
kernel = np.uint8(kernel)
return cv2.dilate(selection, kernel, iterations=1)
Кажется, это намного быстрее, с почти идентичными результатами (8 секунд против 0,15 секунды, тестирование на colab с радиусом 30).
Комментарии:
1. Мне нравится, как вы вычисляете ядро (оно точное и симметричное, в отличие от OpenCV, которое имеет кусковую автофокусировку), но с помощью numpy meshgrid или подобных вещей вы могли бы сделать эту часть быстрее.
Ответ №2:
Это запрашивает операции морфологии.
cv.dilate
совершенно счастлив увеличить области двоичной маски с положительными значениями. Кроме того, это быстро.
Для разных ядер / структурирующих элементов есть getStructuringElement
. Это может дать вам квадраты / прямоугольники, круги / эллипсы, кресты, …
Пример ввода и расширенного:
Подробнее: https://docs.opencv.org/4.x/d9/d61/tutorial_py_morphological_ops.html
Ответ №3:
Я выяснил, как расширить выделение, единственная проблема в том, что у него могут быть некоторые ошибки на краю изображения. На самом деле это довольно просто, если предположить, что у вас есть маска логических значений. За исключением того, что на самом деле это не имеет большого значения, оно все равно работает, если маска состоит из нулей, представляющих невыбранные области, и положительных чисел, представляющих выбранные области.
def expand(selection, radius):
cop = np.copy(selection)
for x in range(-radius,radius 1):
for y in range(-radius,radius 1):
if (y==0 and x==0) or (x**2 y**2 > radius **2):
continue
shift = np.roll(np.roll(selection, y, axis = 0), x, axis = 1)
cop = shift
return cop
Вот краткий пример, который работает довольно хорошо
sel = np.array([[False, False, False, False, False],
[False, False, False, False, False],
[False, False, True, False, False],
[False, False, False, False, False],
[False, False, False, False, False]])
expand(sel, 2)
Это выполняется намного быстрее, я также считаю, что это O (R ^ 2), что довольно быстро. Это также дает аналогичные результаты для функции расширения photoshop для выделения. Я считаю, что единственное отличие заключается в том, что мой метод выбирает пиксели, которые попадают в круг радиуса R, но Photoshop выбирает пиксели в пределах шестиугольника радиуса R, это небольшое отличие, которое можно добавить к оператору if .