opencv — замена части изображения на другую с использованием двоичной маски, но строки с псевдонимами не дает хорошего результата

#python #opencv #mask #bitmask

#python #opencv #маска #битовая маска

Вопрос:

Я работаю с двоичными масками в OpenCV на Python и создал одну с помощью fillConvexPoly. Первый результат можно увидеть на рисунке 1. Как вы можете видеть, край не гладкий, а скорее похож на лестницу.

Поэтому я использую флаг сглаживания в fillconvexpoly, который является cv2.LINE_AA. Результат выглядит многообещающим, как вы можете видеть на рисунке 2. Проблема в том, что использование этой маски в побитовых операциях приводит к ошибкам. Почему?

Что ж, при ближайшем рассмотрении и взгляде на фактические значения пикселей я вижу, что строка представлена уменьшением значений пикселей, а не pixel (x, y) = 255, pixel (x 1, y) = 0 и pixel (x 1, y 1) =255. На рисунке 3 (большое изображение) вы можете видеть уменьшение значения в пикселях в одной строке. На рисунке 4 вы можете увидеть, что я хотел бы получить в результате. Я понимаю, что это нереально, поскольку линия не имеет такого угла, но должно быть лучшее представление, которое есть на рисунке 1, верно ?. Причина, по которой мне это нужно, заключается в том, что я заменяю часть изображения другим изображением, а маска представляет замененную область. Я использую побитовые операции для получения моего результата. Использование побитовых операций со значениями, отличными от 0 или 255, приводит к ошибкам и другим цветам и т.д. Поэтому мне нужно, чтобы оно было 0 или 255. Результат на данный момент на рисунке 5, где заменена синяя область (раньше была красной). Как вы можете видеть, результат не очень привлекательный. Если бы это была «прямая» строка, результат выглядел бы намного лучше. (применение размытия к прямым краям впоследствии делает его хорошо выглядящим, но движение по лестнице все еще видно после размытия).

Что я пробовал:

  1. Пороговое значение значений пикселей. Это приводит к fillconvexpoly без LINE_AA, что логично, потому что значения горизонтальных пикселей уменьшаются, например, на 15 пикселей, а затем достигают 0, где уменьшение теперь начинается со следующей строки, что снова приводит к уменьшению значения на 15 пикселей в той же строке, … Таким образом, пороговое значение любого значения приводит к тому же результату с другим смещением.
  2. Морфологические операции, такие как открытие / закрытие / расширение / эрозия и т.д., не работают с этими типами линий. Также логично, когда я читаю, как они работают и для чего они используются.
  3. Затем размыта маска и пороговое значение, что приводит к тому же зазубренному / ступенчатому краю.
  4. Сканировал stackoverflow в течение нескольких дней в поисках решения.

Если у вас есть другое предложение по этой проблеме, я был бы рад его услышать. Заранее спасибо.

РЕДАКТИРОВАТЬ: использование размытия в конечном результате хорошо работает для строк с большим количеством шагов, например, каждые 2 или 3 пикселя. От: оригинал. Применил размытие по краю: результат, но применил эту технику к очень длинной строке за несколько шагов: оригинал: см. Рисунок 5 и результат. Как вы можете видеть, результат неплохой, но все же содержит этот пошаговый шаблон. Действительно пытаюсь избавиться от этого. (Свечение, исходящее снизу, — это то, с чем я буду иметь дело в будущем)

Комментарии:

1. Кажется, разрешение изображения 1 слишком низкое, чтобы вы могли получить желаемый результат. Высота каждого шага, подобного шаблону, остается одним пикселем. вы можете применить функцию сглаживания по краям конечного изображения.

2. Привет, Джихан, спасибо за отличное предложение, но я уже пробовал это. (Я отредактировал свой пост с тем, что у меня получилось). Результат неплохой, но все еще содержит пошаговый шаблон.

Ответ №1:

Вы можете решить эту проблему с помощью эквивалента функции addWeighted для весов на основе массива. Предполагая, что у вас есть 8-разрядные массивы image , overlay , и mask , и поскольку ваша маска, похоже, применяется к наложению, а не к базовому изображению, вы могли бы сделать что-то вроде

 import cv2
import numpy as np

... # get/read image and overlay, create mask

alpha = mask / 255 # convert to 0-1 range, could also use cv2.normalize
combined = np.uint8(overlay * alpha   image * (1 - alpha))
 

Комментарии:

1. Это не работает. cv2.addWeighted принимает единственное значение в качестве альфа-параметра, а не веса на пиксель. Тем не менее, спасибо за предложение.

2. Прошу прощения — прошло много времени, и я должен был должным образом подтвердить это документами и тестом. Я отредактировал решение, чтобы включить ручную реализацию, которая принимает взвешивания на основе массива.