it-swarm.com.ru

Эквивалент copyTo в привязках Python OpenCV?

OpenCV имеет функцию copyTo, которая позволяет копировать замаскированную область с одного коврика на другой. 

http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a4331fa88593a9a9c14c0998574695ebb

Что эквивалентно этому в привязках Python? Я хотел бы скопировать область изображения в другое изображение с помощью двоичной маски. 

10
mikevanis

cv::Mat::copyTo делает одну из двух вещей в зависимости от того, была ли инициализирована матрица вывода. Если ваша выходная матрица не инициализирована, использование copyTo с маской создает новую выходную матрицу того же типа, что и вход, и для всех значений установлено значение 0 по всем каналам. Как только это происходит, данные изображения, определенные маской, копируются, а остальная часть матрицы устанавливается на 0. Если ваша выходная матрица инициализирована и уже состоит из содержимого, copyTo копирует пиксели, которые определяется в маске из источника и оставляет пиксели, которые не были частью маски, неизменными в месте назначения. Поэтому замена пикселей, которые определены маской из исходного изображения, копируется на выход.

Поскольку OpenCV теперь использует numpy для взаимодействия с библиотекой, очень легко использовать любой из этих методов. Чтобы отличить его от другого ответа, приведенного в этом посте, первый метод можно выполнить, просто умножив маску на изображение поэлементно. Предполагая, что ваш ввод называется img, а ваша двоичная маска называется mask, где я предполагаю, что маска 2D, просто сделайте следующее:

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here

# Create new image
new_image = img * (mask.astype(img.dtype))

Приведенный выше код предполагает, что и img, и mask совместно используют одинаковое количество каналов. Это будет сложно, если вы используете цветное изображение в качестве источника и маску 2D, как я уже предполагал. Таким образом, общее количество каналов равно 2, а не 3, и поэтому приведенный выше синтаксис выдаст ошибку, поскольку размеры между этими двумя больше не совместимы. Вам нужно будет учесть это при использовании цветных изображений. Вы можете сделать это, добавив одноэлементное третье измерение к маске, чтобы можно было использовать широковещательную передачу.

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here

# Create new image
# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(mask.shape) != 3:
    new_image = img * (mask[:,:,None].astype(img.dtype))
# Case #2 - Both images are colour or grayscale
Elif (len(img.shape) == 3 and len(mask.shape) == 3) or \
   (len(img.shape) == 1 and len(mask.shape) == 1):
    new_image = img * (mask.astype(img.dtype))
# Otherwise, we can't do this
else:
    raise Exception("Incompatible input and mask dimensions")

Для второго подхода давайте предположим, что у нас есть другое изображение с именем other_image, куда вы хотите скопировать содержимое этого изображения, определенного вашей маской, обратно в целевое изображение img. В этом случае первым делом определите все ненулевые местоположения в маске с помощью numpy.where , а затем используйте их для индексирования или вставки в ваше изображение, а также куда вы хотите скопировать. Мы также должны помнить о количестве каналов между двумя изображениями, как при первом подходе:

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here
other_image = cv2.imread(...) # Define other image here

locs = np.where(mask != 0) # Get the non-zero mask locations

# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(other_image.shape) != 3:
    img[locs[0], locs[1]] = other_image[locs[0], locs[1], None]
# Case #2 - Both images are colour or grayscale
Elif (len(img.shape) == 3 and len(other_image.shape) == 3) or \
   (len(img.shape) == 1 and len(other_image.shape) == 1):
    img[locs[0], locs[1]] = other_image[locs[0], locs[1]]
# Otherwise, we can't do this
else:
    raise Exception("Incompatible input and output dimensions")

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

 enter image description here

Я также искусственно сделал цвет изображения, хотя он отображается в градациях серого, но интенсивности будут скопированы на все каналы. Я также собираюсь определить маску, которая является просто верхним левым субрегионом 100 x 100, и поэтому мы создадим выходное изображение, которое будет копировать только этот субрегион:

import numpy as np
import cv2

# Define image
img = cv2.imread("cameraman.png")

# Define mask
mask = np.zeros(img.shape, dtype=np.bool)
mask[:100, :100] = True

Когда вы используете первый метод и когда мы показываем результаты, мы получаем:

 enter image description here

Мы можем видеть, что мы создали выходное изображение, в котором верхний левый субрегион 100 x 100 содержит данные нашего изображения, а остальные пиксели установлены равными 0. Это зависит от расположения маски, установленного на True. Для второго подхода мы создадим другое изображение, которое будет случайным, того же размера, что и входное изображение, которое охватывает [0, 255] для всех каналов.

# Define other image
other_image = (255*np.random.Rand(*img.shape)).astype(np.uint8)

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

 enter image description here

Как вы можете видеть, верхний левый угол изображения был обновлен в соответствии с местоположениями маски, которые установлены на True.

12
rayryeng

Обратите внимание, если это именно то, что вы хотите, но для копирования с масками в Python, я бы пошел с cv2.bitwise_

new_image = cv2.bitwise_and(old_image,binary_mask)
3
Soltius