左上方:前景图像。右上方:Alpha蒙版。左下:背景图像。右下:最终的合成图像。
在本教程中,我们将学习如何Alpha混合两个图像。想要在另一个图像上叠加一个透明的PNG图像吗?
什么是Alpha混合?
Alpha混合是将前景图像与背景图像叠加在一起的过程。透明度通常是图像的第四个通道(例如,在透明的PNG中),但是它也可以是单独的图像。这种透明蒙版通常称为alpha蒙版或alpha遮罩。
在本文顶部的功能图像中,前景图像显示在左上方,灰度alpha蒙版显示在右上方,背景图像显示在左下方,以及通过混合获得的合成图像右下角显示使用alpha蒙版的前景图像和背景图像。
alpha混合背后的数学很简单。在图像的每个像素处,我们都需要使用Alpha遮罩(α)组合前景图像颜色(F)和背景图像颜色(B )。
注意:α公式中使用的值实际上是alpha蒙版中的像素值除以255。因此,在下面的公式中,0 =< α =< 1
I = α F +(1-α)B
从上面的方程式,您可以进行以下观察。
当为时α = 0,输出像素颜色为背景。
当为时α = 1,输出像素颜色仅是前景。
当0 <α <1输出像素颜色是背景和前景的混合色时。为了进行逼真的混合,alpha蒙版的边界通常具有介于0和1之间的像素。
如何在OpenCV(C ++ / Python)中实现Alpha混合?
让我们来看一个用C ++和Python编写的示例,看看如何在OpenCV中实现α混合。在后面的部分中,我们还将展示C ++代码的有效实现。
#include opencv2/opencv.hpp
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// Read the images
Mat foreground = imread("puppets.png");
Mat background = imread("ocean.png");
Mat alpha = imread("puppets_alpha.png");
// Convert Mat to float data type
foreground.convertTo(foreground, CV_32FC3);
background.convertTo(background, CV_32FC3);
// Normalize the alpha mask to keep intensity between 0 and 1
alpha.convertTo(alpha, CV_32FC3, 1.0/255); //
// Storage for output image
Mat ouImage = Mat::zeros(foreground.size(), foreground.type());
// Multiply the foreground with the alpha matte
multiply(alpha, foreground, foreground);
// Multiply the background with ( 1 - alpha )
multiply(Scalar::all(1.0)-alpha, background, background);
// Add the masked foreground and background.
add(foreground, background, ouImage);
// Display image
imshow("alpha blended image", ouImage/255);
waitKey(0);
return 0;
}
Alpha混合:Python
import cv2
# Read the images
foreground = cv2.imread("puppets.png")
background = cv2.imread("ocean.png")
alpha = cv2.imread("puppets_alpha.png")
# Convert uint8 to float
foreground = foreground.astype(float)
background = background.astype(float)
# Normalize the alpha mask to keep intensity between 0 and 1
alpha = alpha.astype(float)/255
# Multiply the foreground with the alpha matte
foreground = cv2.multiply(alpha, foreground)
# Multiply the background with ( 1 - alpha )
background = cv2.multiply(1.0 - alpha, background)
# Add the masked foreground and background.
outImage = cv2.add(foreground, background)
# Display image
cv2.imshow("outImg", outImage/255)
cv2.waitKey(0)
使用OpenCV(C ++)进行有效的Alpha混合
上面的代码很干净,但效率却不尽如人意。请注意,我们对前景图像进行了两次遍历-一次是与alpha乘以,另一次是与蒙版背景相加。同样,我们在背景图片上进行了多次传递。
对于小型(例如250×250)和中型(例如800×800)图像,上述方法很好,但是如果我们对效率特别感兴趣,特别是对于大型图像(例如2000×2000),则可以直接处理数据以获得更好的性能。以下是相同的CPP代码。
void alphaBlend(Mat& foreground, Mat& background, Mat& alpha, Mat& outImage)
{
// Find number of pixels.
int numberOfPixels = foreground.rows * foreground.cols * foreground.channels();
// Get floating point pointers to the data matrices
float* fptr = reinterpret_cast
(foreground.data); float* bptr = reinterpret_cast
(background.data); float* aptr = reinterpret_cast
(alpha.data); float* outImagePtr = reinterpret_cast
(outImage.data);
// Loop over all pixesl ONCE
for(
int i = 0;
i < numberOfPixels;
i++, outImagePtr++, fptr++, aptr++, bptr++
)
{
*outImagePtr = (*fptr)*(*aptr) + (*bptr)*(1 - *aptr);
}
}
运行时比较
在下表中,我们显示了两种方法在各种大小的图像上的运行时比较。这些数字是超过3000次跑步的平均时间。如您所见,对于较大的图像,一次通过图像的有效方法所花费的时间不到一半!目前尚不清楚为什么单次通过方法对于小图像会稍差一些。
相关图片源码下载地址:关注“图像算法”微信公众号,回复图像混合