Ответ 1
import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')
added_image = cv2.addWeighted(background,0.4,overlay,0.1,0)
cv2.imwrite('combined.png', added_image)
Как я могу наложить прозрачный PNG на другое изображение, не теряя его прозрачность, используя openCV в Python?
import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')
# Help please
cv2.imwrite('combined.png', background)
Источники:
import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')
added_image = cv2.addWeighted(background,0.4,overlay,0.1,0)
cv2.imwrite('combined.png', added_image)
import numpy as np
import cv2
# ==============================================================================
def blend_transparent(face_img, overlay_t_img):
# Split out the transparency mask from the colour info
overlay_img = overlay_t_img[:,:,:3] # Grab the BRG planes
overlay_mask = overlay_t_img[:,:,3:] # And the alpha plane
# Again calculate the inverse mask
background_mask = 255 - overlay_mask
# Turn the masks into three channel, so we can use them as weights
overlay_mask = cv2.cvtColor(overlay_mask, cv2.COLOR_GRAY2BGR)
background_mask = cv2.cvtColor(background_mask, cv2.COLOR_GRAY2BGR)
# Create a masked out face image, and masked out overlay
# We convert the images to floating point in range 0.0 - 1.0
face_part = (face_img * (1 / 255.0)) * (background_mask * (1 / 255.0))
overlay_part = (overlay_img * (1 / 255.0)) * (overlay_mask * (1 / 255.0))
# And finally just add them together, and rescale it back to an 8bit integer image
return np.uint8(cv2.addWeighted(face_part, 255.0, overlay_part, 255.0, 0.0))
# ==============================================================================
# We load the images
face_img = cv2.imread("field.jpg")
overlay_t_img = cv2.imread("dice.png", -1) # Load with transparency
result_2 = blend_transparent(face_img, overlay_t_img)
cv2.imwrite("merged_transparent.png", result_2)
Прошло некоторое время с тех пор, как появился этот вопрос, но я считаю, что это правильный простой ответ, который еще может кому-то помочь.
background = cv2.imread('road.jpg')
overlay = cv2.imread('traffic sign.png')
rows,cols,channels = overlay.shape
overlay=cv2.addWeighted(background[250:250+rows, 0:0+cols],0.5,overlay,0.5,0)
background[250:250+rows, 0:0+cols ] = overlay
Это наложит изображение на фоновое изображение, как показано здесь:
Игнорировать прямоугольники ROI
Обратите внимание, что я использовал фоновое изображение размером 400x300 и оверлейное изображение размером 32x32, которое отображается в части x [0-32] и y [250-282] фонового изображения в соответствии с заданными для него координатами, чтобы сначала вычислите смесь, а затем поместите рассчитанную смесь в ту часть изображения, где я хочу ее разместить.
(оверлей загружается с диска, а не с самого фонового изображения, к сожалению, у оверлейного изображения есть свой собственный белый фон, так что вы можете увидеть это и в результате)
Следующий код будет использовать альфа-каналы наложенного изображения, чтобы правильно смешать его с фоновым изображением, используйте x
и y
чтобы установить левый верхний угол наложенного изображения.
import cv2
import numpy as np
def overlay_transparent(background, overlay, x, y):
background_width = background.shape[1]
background_height = background.shape[0]
if x >= background_width or y >= background_height:
return background
h, w = overlay.shape[0], overlay.shape[1]
if x + w > background_width:
w = background_width - x
overlay = overlay[:, :w]
if y + h > background_height:
h = background_height - y
overlay = overlay[:h]
if overlay.shape[2] < 4:
overlay = np.concatenate(
[
overlay,
np.ones((overlay.shape[0], overlay.shape[1], 1), dtype = overlay.dtype) * 255
],
axis = 2,
)
overlay_image = overlay[..., :3]
mask = overlay[..., 3:] / 255.0
background[y:y+h, x:x+w] = (1.0 - mask) * background[y:y+h, x:x+w] + mask * overlay_image
return background
Этот код изменяет фон, поэтому создайте копию, если вы хотите сохранить исходное фоновое изображение.
Вам нужно открыть прозрачное изображение в формате png, используя флаг IMREAD_UNCHANGED
Mat overlay = cv::imread("dice.png", IMREAD_UNCHANGED);
Затем разделите каналы, сгруппируйте RGB и используйте прозрачный канал в качестве маски, сделайте так:
/**
* @brief Draws a transparent image over a frame Mat.
*
* @param frame the frame where the transparent image will be drawn
* @param transp the Mat image with transparency, read from a PNG image, with the IMREAD_UNCHANGED flag
* @param xPos x position of the frame image where the image will start.
* @param yPos y position of the frame image where the image will start.
*/
void drawTransparency(Mat frame, Mat transp, int xPos, int yPos) {
Mat mask;
vector<Mat> layers;
split(transp, layers); // seperate channels
Mat rgb[3] = { layers[0],layers[1],layers[2] };
mask = layers[3]; // png alpha channel used as mask
merge(rgb, 3, transp); // put together the RGB channels, now transp insn't transparent
transp.copyTo(frame.rowRange(yPos, yPos + transp.rows).colRange(xPos, xPos + transp.cols), mask);
}
Можно назвать так:
drawTransparency(background, overlay, 10, 10);
Поскольку вы хотите работать с прозрачностью, обязательно проверьте ЭТО ОТВЕТ, который я предоставил месяц назад. Я бы взял ссылку с другого сообщения в блоге, также упомянутого там.
Не стесняйтесь оставлять комментарий, если найдете его полезным или в случае, если у вас есть другие проблемы.