• 图像的线性混合



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

    一 图像的线性混合

    什么是图像的线性混合(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相比,性能会更差一点。

  • 相关阅读:
    Websocket基础知识简记
    jmeter websocket接口测试
    软件测试的艺术 笔记(上)
    错误提示Unable to preventDefault inside passive event listener解决方法
    vue-cil3关闭eslint语法检查
    mongoDB无法启动服务器
    Vue之todoList
    react踩坑第一章
    父组件向孙子组件传值(Context)特性
    变量声明
  • 原文地址:https://www.cnblogs.com/laizhenghong2012/p/11253100.html
Copyright © 2020-2023  润新知