Вопрос по python – OpenCV - применить маску к цветному изображению

23

Как я могу применить маску к цветному изображению в последней привязке Python (cv2)? В предыдущем связывании Python самым простым способом было использоватьcv.Copy например

cv.Copy(dst, src, mask)

Но эта функция недоступна в привязке cv2. Есть ли обходной путь без использования стандартного кода?

Что ты пытаешься сделать.? поскольку он имеет поддержку NumPy, вы можете использовать функции NUMPY. Abid Rahman K
Я делаю некоторую фильтрацию в цветовом пространстве HSV для исходного изображения pzo

Ваш Ответ

5   ответов
11

вот решение, если вы хотите, чтобы фон отличался от сплошного черного цвета. Нам нужно только инвертировать маску и применить ее в фоновом изображенииof the same size а затем объединить фон и передний план. Плюсом этого решения является то, что фоном может быть что угодно (даже другое изображение).

Этот пример изменен сHough Circle Transform, Первое изображение - логотип OpenCV, второе - оригинальная маска, третье - объединенный фон + передний план.

apply mask and get a customized background

# http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.html
import cv2
import numpy as np

# load the image
img = cv2.imread('E:\\FOTOS\\opencv\\opencv_logo.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# detect circles
gray = cv2.medianBlur(cv2.cvtColor(img, cv2.COLOR_RGB2GRAY), 5)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=50, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))

# draw mask
mask = np.full((img.shape[0], img.shape[1]), 0, dtype=np.uint8)  # mask is only 
for i in circles[0, :]:
    cv2.circle(mask, (i[0], i[1]), i[2], (255, 255, 255), -1)

# get first masked value (foreground)
fg = cv2.bitwise_or(img, img, mask=mask)

# get second masked value (background) mask must be inverted
mask = cv2.bitwise_not(mask)
background = np.full(img.shape, 255, dtype=np.uint8)
bk = cv2.bitwise_or(background, background, mask=mask)

# combine foreground+background
final = cv2.bitwise_or(fg, bk)

Note: It is better to use the opencv methods because they are optimized.

3

пользовать однозначное одноканальное изображение в градациях серого в качестве маски (например, из альфа-канала), вы можете расширить его до трех каналов, а затем использовать для интерполяции:

assert len(mask.shape) == 2 and issubclass(mask.dtype.type, np.floating)
assert len(foreground_rgb.shape) == 3
assert len(background_rgb.shape) == 3

alpha3 = np.stack([mask]*3, axis=2)
blended = alpha3 * foreground_rgb + (1. - alpha3) * background_rgb

Обратите внимание, чтоmask должен быть в диапазоне0..1 чтобы операция прошла успешно. Также предполагается, что1.0 кодирует, сохраняя только передний план, в то время как0.0 значит держать только фон.

Если маска может иметь форму(h, w, 1), это помогает:

alpha3 = np.squeeze(np.stack([np.atleast_3d(mask)]*3, axis=2))

Вотnp.atleast_3d(mask) делает маску(h, w, 1) если это(h, w) а такжеnp.squeeze(...) изменяет результат от(h, w, 3, 1) в(h, w, 3).

0

ашел очень полезным, но застрял.

Вот так я копирую изображение с заданной маской.

x, y = np.where(mask!=0)
pts = zip(x, y)
# Assuming dst and src are of same sizes
for pt in pts:
   dst[pt] = src[pt]

Это немного медленно, но дает правильные результаты.

РЕДАКТИРОВАТЬ:

Питонический путь.

idx = (mask!=0)
dst[idx] = src[idx]
Здесь нет необходимости заново изобретать колесо, когда "bitwise_and" Метод в cv2 работает на 100%, как просили. Не только это, но это очень очевидно, что он делает.
Что неверного в ответе Абида?
2
import cv2 as cv

im_color = cv.imread("lena.png", cv.IMREAD_COLOR)
im_gray = cv.cvtColor(im_color, cv.COLOR_BGR2GRAY)

8-bit, uint8 изображения здесь. Это означает, что изображения могут иметь значения пикселей в диапазоне[0, 255] и значения должны быть целыми числами.

left-color,right-gray

Давайте сделаем двоичную операцию порога. Создает замаскированное изображение. Черные регионы имеют значение0 и белые регионы255

_, mask = cv.threshold(im_gray, thresh=180, maxval=255, type=cv.THRESH_BINARY)
im_thresh_gray = cv.bitwise_and(im_gray, mask)

Двоичная маска видна ниже слева. Изображение на нем справа - результат примененияbitwise_and операция между серым изображением и маской. Получилось так, что пространственные местоположения, где маска имела нулевое значение пикселя (чёрное), стали нулевым значением пикселя в результирующем изображении. В местах, где маска имела значение пиксела 255 (белый), полученное изображение сохраняло свое первоначальное значение серого.

left-mask,right-bitwise_and_with_mask

Чтобы применить эту маску к нашему исходному цветному изображению, нам нужно преобразовать маску в 3-канальное изображение, поскольку исходное цветное изображение - это 3-канальное изображение.

mask3 = cv.cvtColor(mask, cv.COLOR_GRAY2BGR)  # 3 channel mask

Затем мы можем применить эту маску к нашему исходному цветному изображению, используя тот жеbitwise_and функция.

im_thresh_color = cv.bitwise_and(im_color, mask3)

mask3 из кода это изображение ниже слева, иim_thresh_color на это право.

left-mask-3channel,right-bitwise_and_with_3channel-mask

Вы можете построить результаты и сами убедиться.

cv.imshow("original image", im_color)
cv.imshow("binary mask", mask)
cv.imshow("3 channel mask", mask3)
cv.imshow("im_thresh_gray", im_thresh_gray)
cv.imshow("im_thresh_color", im_thresh_color)
cv.waitKey(0)

Исходное изображениеlenacolor.png что я нашелВот.

41

cv2.bitwise_and Функция, если у вас уже есть изображение маски.

Для проверки ниже код:

img = cv2.imread('lena.jpg')
mask = cv2.imread('mask.png',0)
res = cv2.bitwise_and(img,img,mask = mask)

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

enter image description here

Я пытаюсь сделать что-то подобное. Маска должна быть черной или белой? Извините за основной вопрос, я новичок в opencv. Спасибо
Вы можете выбрать срез изображения. roi = img [y: y + h, x: x + w], где x, y - верхняя левая точка области, h, w - высота и ширина области.
Я мог бы сделать это =), теперь мне нужно избавиться от черной области ... Есть идеи, как это сделать?
Большое спасибо, Абид! Я попробую это сегодня вечером, когда вернусь домой. Я должен разделить изображение на несколько областей (и повторить этот процесс на несколько изображений). С уважением!
Да, вы правы, маска должна быть черно-белой и одноканальной. Какую область на изображении вы хотите обработать, эта область в маске должна быть белой, а все остальное - черной. И вам не нужно сожалеть, что задали этот вопрос, все начинающие, когда я начинаю учиться, даже я.

Похожие вопросы