Python 使用 openCV 将透明图像叠加到另一个图像上
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40895785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using openCV to overlay transparent image onto another image
提问by Anthony Budd
How can I overlay a transparent PNG onto another image without loosing it's transparency using openCV in python?
如何在 python 中使用 openCV 将透明 PNG 覆盖到另一个图像上而不会失去它的透明度?
import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')
# Help please
cv2.imwrite('combined.png', background)
Sources:
资料来源:
回答by Manivannan Murugavel
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)
回答by Cristian Garcia
The following code will use the alpha channels of the overlay image to correctly blend it into the background image, use x
and y
to set the top-left corner of the overlay image.
以下代码将使用叠加图像的 Alpha 通道将其正确混合到背景图像中,使用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
This code will mutate background so create a copy if you wish to preserve the original background image.
此代码将改变背景,因此如果您希望保留原始背景图像,请创建一个副本。
回答by GodIsAnAstronaut
Been a while since this question appeared, but I believe this is the right simple answer, which could still help somebody.
这个问题出现已经有一段时间了,但我相信这是正确的简单答案,它仍然可以帮助某人。
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
This will overlay the image over the background image such as shown here:
这会将图像覆盖在背景图像上,如下所示:
Ignore the ROI rectangles
忽略 ROI 矩形
Note that I used a background image of size 400x300 and the overlay image of size 32x32, is shown in the x[0-32] and y[250-282] part of the background image according to the coordinates I set for it, to first calculate the blend and then put the calculated blend in the part of the image where I want to have it.
请注意,我使用了大小为 400x300 的背景图像和大小为 32x32 的叠加图像,根据我为其设置的坐标显示在背景图像的 x[0-32] 和 y[250-282] 部分,以首先计算混合,然后将计算出的混合放入我想要的图像部分。
(overlay is loaded from disk, not from the background image itself,unfortunately the overlay image has its own white background, so you can see that too in the result)
(覆盖从磁盘加载,而不是从背景图像本身加载,不幸的是覆盖图像有自己的白色背景,所以你也可以在结果中看到)
回答by Mala
The correct answer to this was far too hard to come by, so I'm posting this answer even though the question is really old. What you are looking for is "over" compositing, and the algorithm for this can be found on Wikipedia: https://en.wikipedia.org/wiki/Alpha_compositing
这个问题的正确答案太难了,所以即使这个问题真的很老,我还是发布了这个答案。您正在寻找的是“过度”合成,可以在维基百科上找到该算法:https: //en.wikipedia.org/wiki/Alpha_compositing
I am far from an expert with OpenCV, but after some experimentation this is the most efficient way I have found to accomplish the task:
我远不是 OpenCV 的专家,但经过一些实验,这是我发现完成任务的最有效方法:
import cv2
background = cv2.imread("background.png", cv2.IMREAD_UNCHANGED)
foreground = cv2.imread("overlay.png", cv2.IMREAD_UNCHANGED)
# normalize alpha channels from 0-255 to 0-1
alpha_background = background[:,:,3] / 255.0
alpha_foreground = foreground[:,:,3] / 255.0
# set adjusted colors
for color in range(0, 3):
background[:,:,color] = alpha_foreground * foreground[:,:,color] + \
alpha_background * background[:,:,color] * (1 - alpha_foreground)
# set adjusted alpha and denormalize back to 0-255
background[:,:,3] = (1 - (1 - alpha_foreground) * (1 - alpha_background)) * 255
# display the image
cv2.imshow("Composited image", background)
cv2.waitKey(0)
回答by Derzu
You need to open the transparent png image using the flag IMREAD_UNCHANGED
您需要使用标志 IMREAD_UNCHANGED 打开透明 png 图像
Mat overlay = cv::imread("dice.png", IMREAD_UNCHANGED);
Then split the channels, group the RGB and use the transparent channel as an mask, do like that:
然后拆分通道,将 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);
}
Can be called like that:
可以这样调用:
drawTransparency(background, overlay, 10, 10);
回答by Saurabh yadav
To overlay png image watermark over normal 3 channel jpeg image
在普通 3 通道 jpeg 图像上覆盖 png 图像水印
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
Usage:
用法:
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)
回答by Jeru Luke
Since you want to work with transparency, be sure to check THIS ANSWERI provided a month ago. I would have taken reference from another blog post also mentioned there.
由于您想使用透明度,请务必查看我一个月前提供的这个答案。我会参考那里也提到的另一篇博文。
Feel free to leave a comment if you find it useful or in case you have other issues.
如果您觉得有用或有其他问题,请随时发表评论。