import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png', cv2.IMREAD_UNCHANGED) # IMREAD_UNCHANGED => open image with the alpha channel
height, width = overlay.shape[:2]
for y in range(height):
for x in range(width):
overlay_color = overlay[y, x, :3] # first three elements are color (RGB)
overlay_alpha = overlay[y, x, 3] / 255 # 4th element is the alpha channel, convert from 0-255 to 0.0-1.0
# get the color from the background image
background_color = background[y, x]
# combine the background color and the overlay color weighted by alpha
composite_color = background_color * (1 - overlay_alpha) + overlay_color * overlay_alpha
# update the background image in place
background[y, x] = composite_color
cv2.imwrite('combined.png', background)
import cv2
import numpy as np
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png', cv2.IMREAD_UNCHANGED) # IMREAD_UNCHANGED => open image with the alpha channel
# separate the alpha channel from the color channels
alpha_channel = overlay[:, :, 3] / 255 # convert from 0-255 to 0.0-1.0
overlay_colors = overlay[:, :, :3]
# To take advantage of the speed of numpy and apply transformations to the entire image with a single operation
# the arrays need to be the same shape. However, the shapes currently looks like this:
# - overlay_colors shape:(width, height, 3) 3 color values for each pixel, (red, green, blue)
# - alpha_channel shape:(width, height, 1) 1 single alpha value for each pixel
# We will construct an alpha_mask that has the same shape as the overlay_colors by duplicate the alpha channel
# for each color so there is a 1:1 alpha channel for each color channel
alpha_mask = np.dstack((alpha_channel, alpha_channel, alpha_channel))
# The background image is larger than the overlay so we'll take a subsection of the background that matches the
# dimensions of the overlay.
# NOTE: For simplicity, the overlay is applied to the top-left corner of the background(0,0). An x and y offset
# could be used to place the overlay at any position on the background.
h, w = overlay.shape[:2]
background_subsection = background[0:h, 0:w]
# combine the background with the overlay image weighted by alpha
composite = background_subsection * (1 - alpha_mask) + overlay_colors * alpha_mask
# overwrite the section of the background image that has been updated
background[0:h, 0:w] = composite
cv2.imwrite('combined.png', background)
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's 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);
}
import cv2
import numpy as np
def logoOverlay(image,logo,alpha=1.0,x=0, y=0, scale=1.0):
(h, w) = image.shape[:2]
image = np.dstack([image, np.ones((h, w), dtype="uint8") * 255])
overlay = cv2.resize(logo, None,fx=scale,fy=scale)
(wH, wW) = overlay.shape[:2]
output = image.copy()
# blend the two images together using transparent overlays
try:
if x<0 : x = w+x
if y<0 : y = h+y
if x+wW > w: wW = w-x
if y+wH > h: wH = h-y
print(x,y,wW,wH)
overlay=cv2.addWeighted(output[y:y+wH, x:x+wW],alpha,overlay[:wH,:wW],1.0,0)
output[y:y+wH, x:x+wW ] = overlay
except Exception as e:
print("Error: Logo position is overshooting image!")
print(e)
output= output[:,:,:3]
return output
用法:
background = cv2.imread('image.jpeg')
overlay = cv2.imread('logo.png', cv2.IMREAD_UNCHANGED)
print(overlay.shape) # must be (x,y,4)
print(background.shape) # must be (x,y,3)
# downscale logo by half and position on bottom right reference
out = logoOverlay(background,overlay,scale=0.5,y=-100,x=-100)
cv2.imshow("test",out)
cv2.waitKey(0)
9条答案
按热度按时间eblbsuwk1#
s2j5cfk02#
这个问题的正确答案太难找到了,所以我在这里给出了这个答案,尽管这个问题已经很老了。你要找的是“过度”合成,这个问题的算法可以在维基百科上找到:https://en.wikipedia.org/wiki/Alpha_compositing
我远非OpenCV的Maven,但经过一些实验后,这是我发现的完成任务的最有效的方法:
gk7wooem3#
下面的代码将使用覆盖图像的Alpha通道将其正确地混合到背景图像中,使用
x
和y
设置覆盖图像的左上角。这段代码将改变背景,所以如果你想保留原始的背景图像,可以创建一个副本。
bq3bfh9z4#
这个问题出现已经有一段时间了,但我相信这是正确的简单答案,仍然可以帮助一些人。
这将使图像覆盖在背景图像上,如下所示:
忽略ROI矩形
注意,我使用了大小为400 x300的背景图像和大小为32 x32的覆盖图像,根据我为它设置的坐标显示在背景图像的x[0-32]和y[250-282]部分,首先计算混合,然后将计算出的混合放在图像中我想要的部分。
(叠加是从磁盘加载的,而不是从背景图像本身,不幸的是,叠加图像有自己的白色背景,所以你也可以在结果中看到)
zpjtge225#
如果性能不是问题,那么你可以迭代覆盖层的每个像素,然后将其应用到背景中,这不是很有效,但它确实有助于理解如何使用png的alpha层。
慢速版本
结果:x1c 0d1x
快速版本
我在尝试添加一个png覆盖到一个实时视频源时偶然发现了这个问题,上面的解决方案太慢了,我们可以使用numpy的向量函数来显著提高算法的速度。
在我的机器上,慢速方法大约需要3秒,优化方法大约需要30毫秒。因此,大约快了100倍!
Package 在函数中
此函数处理不同大小的前景和背景图像,并且还支持负偏移和正偏移,以便在任何方向上跨越背景图像的边界移动覆盖。
示例用法:
zi8p0yeb6#
您需要使用标志IMREAD_UNCHANGED打开透明png图像
然后分割通道,分组RGB和使用透明通道作为一个遮罩,这样做:
可以这样称呼:
disbfnqx7#
在普通3通道jpeg图像上叠加png图像水印
用法:
ar7v8xwq8#
xzv2uavs9#
使用此函数将覆盖图放置在任何背景图像上。如果要调整覆盖图的大小,请使用此
overlay = cv2.resize(overlay, (200,200))
,然后将调整大小后的覆盖图传递给此函数。背景. jpg
输出. png