核心功能:使用 OpenCV 添加(融合)两幅图像 OpenCV v4.8.0

上一个教程图像操作

下一个教程更改图像的对比度和亮度

原作者Ana Huamán
兼容性OpenCV >= 3.0

我们将学习如何混合两幅图像!

目标

在本教程中,您将学习

  • 什么是线性混合?
  • 如何使用 addWeighted() 添加两幅图像

原理

注释
以下解释来自 Richard Szeliski 所著的《Computer Vision: 算法与应用》一书中的内容。
通过前面的教程,我们已经对像素算子有了一些了解。一个有趣的二元(双输入)算子是线性混合算子:

g ( x ) = ( 1 − α ) f 0 ( x ) + α f 1 ( x ) g\left( x \right) =\left( 1-\alpha \right) f_0\left( x \right) +\alpha f_1\left( x \right) g(x)=(1α)f0(x)+αf1(x)

通过在 0→1 的范围内改变 α,该算子可用于在两幅图像或视频之间进行时空交叉溶解,就像幻灯片和电影制作中看到的那样(很酷吧?)

源代码

  • C++
    此处下载源代码。

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
// 我们在此不使用 "using namespace std;",以避免 c++17 中的 beta 变量与 std::beta 发生冲突
using std::cin;
using std::cout;
using std::endl;
int main( void )
{
 double alpha = 0.5; double beta; double input;
 Mat src1, src2, dst;
 cout << " Simple Linear Blender " << endl;
 cout << "-----------------------" << endl;
 cout << "* Enter alpha [0.0-1.0]: ";
 cin >> input;
 // 如果用户提供的 alpha 值介于 0 和 1 之间,我们将使用该值
 if( input >= 0 && input <= 1 )
 { alpha = input; }
 src1 = imread( samples::findFile("LinuxLogo.jpg") );
 src2 = imread( samples::findFile("WindowsLogo.jpg") );
 if( src1.empty() ) { cout << "Error loading src1" << endl; return EXIT_FAILURE; }
 if( src2.empty() ) { cout << "Error loading src2" << endl; return EXIT_FAILURE; }
 beta = ( 1.0 - alpha );
 addWeighted( src1, alpha, src2, beta, 0.0, dst);
 imshow( "Linear Blend", dst );
 waitKey(0);
 return 0;
}
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import java.util.Locale;
import java.util.Scanner;
class AddingImagesRun{
 public void run() {
 double alpha = 0.5; double beta; double input;
 Mat src1, src2, dst = new Mat();
 System.out.println(" Simple Linear Blender ");
 System.out.println("-----------------------");
 System.out.println("* Enter alpha [0.0-1.0]: ");
 Scanner scan = new Scanner( System.in ).useLocale(Locale.US);
 input = scan.nextDouble();
 if( input >= 0.0 && input <= 1.0 )
 alpha = input;
 src1 = Imgcodecs.imread("../../images/LinuxLogo.jpg");
 src2 = Imgcodecs.imread("../../images/WindowsLogo.jpg");
 if( src1.empty() == true ){ System.out.println("Error loading src1"); return;}
 if( src2.empty() == true ){ System.out.println("Error loading src2"); return;}
 beta = ( 1.0 - alpha );
 Core.addWeighted( src1, alpha, src2, beta, 0.0, dst);
 HighGui.imshow("Linear Blend", dst);
 HighGui.waitKey(0);
 System.exit(0);
 }
}
public class AddingImages {
 public static void main(String[] args) {
 // Load the native library.
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
 new AddingImagesRun().run();
 }
}
  • Python
    此处下载源代码
from __future__ import print_function
import cv2 as cv
alpha = 0.5
try:
 raw_input # Python 2
except NameError:
 raw_input = input # Python 3
print(''' Simple Linear Blender
-----------------------
* Enter alpha [0.0-1.0]: ''')
input_alpha = float(raw_input().strip())
if 0 <= alpha <= 1:
 alpha = input_alpha
# [load]
src1 = cv.imread(cv.samples.findFile('LinuxLogo.jpg'))
src2 = cv.imread(cv.samples.findFile('WindowsLogo.jpg'))
# [load]
if src1 is None:
 print("Error loading src1")
 exit(-1)
elif src2 is None:
 print("Error loading src2")
 exit(-1)
# [blend_images]
beta = (1.0 - alpha)
dst = cv.addWeighted(src1, alpha, src2, beta, 0.0)
# [blend_images]
# [display]
cv.imshow('dst', dst)
cv.waitKey(0)
# [display]
cv.destroyAllWindows()

解释

因为我们要执行

g ( x ) = ( 1 − α ) f 0 ( x ) + α f 1 ( x ) g\left( x \right) =\left( 1-\alpha \right) f_0\left( x \right) +\alpha f_1\left( x \right) g(x)=(1α)f0(x)+αf1(x)

我们需要两个源图像(f0(x) 和 f1(x))。因此,我们按照通常的方法加载它们:

  • C++
 src1 = imread( samples::findFile("LinuxLogo.jpg") );
 src2 = imread( samples::findFile("WindowsLogo.jpg") );
  • Java
 src1 = Imgcodecs.imread("../../images/LinuxLogo.jpg");
 src2 = Imgcodecs.imread("../../images/WindowsLogo.jpg");
  • Python
src1 = cv.imread(cv.samples.findFile('LinuxLogo.jpg'))
src2 = cv.imread(cv.samples.findFile('WindowsLogo.jpg'))

我们使用了以下图片: LinuxLogo.jpgWindowsLogo.jpg

警告
由于我们添加的是 src1 和 src2,因此它们必须具有相同的大小(宽度和高度)和类型。

现在我们需要生成 g(x) 图像。为此,函数 addWeighted() 非常有用:

  • C++
 beta = ( 1.0 - alpha );
 addWeighted( src1, alpha, src2, beta, 0.0, dst);
  • Java
 beta = ( 1.0 - alpha );
 Core.addWeighted( src1, alpha, src2, beta, 0.0, dst);
  • Python
beta = (1.0 - alpha)
dst = cv.addWeighted(src1, alpha, src2, beta, 0.0)

上面一行的 Numpy 版本(但 cv 函数快 2 倍左右):

dst = np.uint8(alpha*(img1)+beta*(img2))

因为 addWeighted() 会产生:

d s t = α ⋅ s r c 1 + β ⋅ s r c 2 + γ dst=\alpha ⋅src1+\beta ⋅src2+\gamma dst=αsrc1+βsrc2+γ

在本例中,gamma 就是上述代码中的参数 0.0。

创建窗口、显示图像并等待用户结束程序。

  • C++
 imshow( "Linear Blend", dst );
 waitKey(0);
  • Java
 HighGui.imshow("Linear Blend", dst);
 HighGui.waitKey(0);
  • Python
cv.imshow('dst', dst)
cv.waitKey(0)

结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值