图像的线性混合

mac2022-06-30  28

[TOC]


注:原创不易,转载请务必注明原作者和出处,感谢支持!

一 图像的线性混合

什么是图像的线性混合(linear blending)?

如下面的公式所示。所谓的图像线性混合是指对于输入的两张图像$I_0$和$I_1$,取它们相同位置处的像素值进行线性相加,然后将结果赋值给目标图像相同位置处的像素。其中参数$\alpha$控制了两张图片在目标图像中的权重。

\[ g(x) = \alpha I_0(x) + (1-\alpha)I_1(x) \]

图像的线性混合有什么作用呢?在幻灯片翻页或者电影制作中,经常需要产生画面叠加的效果。在上式中,只要使得$\alpha$从1逐渐减小到0即可产生从图像$I_0$过渡到图像$I_1$时的叠加效果了。

OpenCV中提供了一个用于两张图像线性混合的API。API所依据的计算公式如下:

\[ dst(I) = saturate\_cast(src1(I) * alpha + src2(I) * beta + gamma) \] void cv::addWeighted( InputArray src1, // 输入图像1 double alpha, // 图像1的权重 InputArray src2, // 输入图像2 double beta, // 图像2的权重 double gamma, // gamma值 OutputArray dst, // 输出图像 int dtype = -1 );

注意:用于线性混合的两张图像必须是同等大小和同等类型的!


二 代码实现

如果不使用OpenCV提供的API,仅依靠OpenCV提供的像素级访问功能,则图像的线性混合可以实现如下。

#include <iostream> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char **argv) { // load two images with the same size and type Mat windows = imread("D:\\IMG\\windows.jpg", IMREAD_COLOR); Mat linux = imread("D:\\IMG\\linux.jpg", IMREAD_COLOR); if (windows.empty() || linux.empty()) { cout << "Error : could not load image." << endl; return -1; } imshow("input - windows", windows); imshow("input - linux", linux); // check if two images are with the same size and type if (windows.size() != linux.size() || windows.type() != linux.type()) { cout << "Error : two input images do NOT match in size or type." << endl; return -1; } // parameters for linear blending double alpha = 0.5; double beta = 1 - alpha; double gamma = 0.0; Mat dst(windows.size(), windows.type()); decltype(windows.rows) row, col; double output, b, g, r; int f1, f2, b1, b2, g1, g2, r1, r2; for (row = 0; row < windows.rows; ++row) { for (col = 0; col < windows.cols; ++col) { // single channel (gray image) or three channels (RGB image) only if (windows.channels() == 1) { f1 = windows.at<uchar>(row, col); f2 = linux.at<uchar>(row, col); output = f1 * alpha + f2 * beta + gamma; dst.at<uchar>(row, col) = saturate_cast<uchar>(output); } else if (windows.channels() == 3) { b1 = windows.at<Vec3b>(row, col)[0]; b2 = linux.at<Vec3b>(row, col)[0]; g1 = windows.at<Vec3b>(row, col)[1]; g2 = linux.at<Vec3b>(row, col)[1]; r1 = windows.at<Vec3b>(row, col)[2]; r2 = linux.at<Vec3b>(row, col)[2]; b = b1 * alpha + b2 * beta + gamma; g = g1 * alpha + g2 * beta + gamma; r = r1 * alpha + r2 * beta + gamma; dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b); dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g); dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r); } } } imshow("output (alpha = 0.5)", dst); waitKey(0); return 0; }

如果使用addWeighted(),则可以简单地实现如下

addWeighted(windows, alpha, linux, beta, 0, dst); imshow("output (alpha = 0.9)", dst);

三 实现效果

(1) 两张原图

(2) 手写代码实现,$\alpha$值分别为0.1、0.5、0.9

(3) 调用API实现,$\alpha$值分别为0.1、0.5、0.9

可以看到,手写代码实现所呈现的效果和调用APIaddWeighted()的效果并没有明显的差异。但很可能的是自己手写的与API相比,性能会更差一点。

转载于:https://www.cnblogs.com/laizhenghong2012/p/11253100.html

最新回复(0)