Prev Tutorial: Operations with images
Next Tutorial: Changing the contrast and brightness of an image!
| |
Original author | Ana Huamán |
Compatibility | OpenCV >= 3.0 |
We will learn how to blend two images!
Goal
In this tutorial you will learn:
- what is linear blending and why it is useful;
- how to add two images using addWeighted()
Theory
- Note
- The explanation below belongs to the book Computer Vision: Algorithms and Applications by Richard Szeliski
From our previous tutorial, we know already a bit of Pixel operators. An interesting dyadic (two-input) operator is the linear blend operator:
\[g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)\]
By varying \(\alpha\) from \(0 \rightarrow 1\) this operator can be used to perform a temporal cross-dissolve between two images or videos, as seen in slide shows and film productions (cool, eh?)
Source Code
C++
Download the source code from here.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main( void )
{
double alpha = 0.5; double beta; double input;
cout << " Simple Linear Blender " << endl;
cout << "-----------------------" << endl;
cout << "* Enter alpha [0.0-1.0]: ";
cin >> input;
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;
}
n-dimensional dense array class
Definition: mat.hpp:811
bool empty() const
Returns true if the array has no elements.
"black box" representation of the file storage associated with a file on disk.
Definition: core.hpp:106
Java
Download the source code from here.
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) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new AddingImagesRun().run();
}
}
Python
Download the source code from here.
from __future__ import print_function
import cv2 as cv
alpha = 0.5
try:
raw_input
except NameError:
raw_input = input
print(''' Simple Linear Blender
-----------------------
* Enter alpha [0.0-1.0]: ''')
input_alpha = float(raw_input().strip())
if 0 <= alpha <= 1:
alpha = input_alpha
if src1 is None:
print("Error loading src1")
exit(-1)
elif src2 is None:
print("Error loading src2")
exit(-1)
beta = (1.0 - alpha)
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)
Calculates the weighted sum of two arrays.
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
Try to find requested data file.
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
int waitKey(int delay=0)
Waits for a pressed key.
void destroyAllWindows()
Destroys all of the HighGUI windows.
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
Loads an image from a file.
Explanation
Since we are going to perform:
\[g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)\]
We need two source images ( \(f_{0}(x)\) and \(f_{1}(x)\)). So, we load them in the usual way:
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
We used the following images: LinuxLogo.jpg and WindowsLogo.jpg
- Warning
- Since we are adding src1 and src2, they both have to be of the same size (width and height) and type.
Now we need to generate the g(x)
image. For this, the function addWeighted() comes quite handy:
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
Numpy version of above line (but cv function is around 2x faster):
dst = np.uint8(alpha*(img1)+beta*(img2))
since addWeighted() produces:
\[dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma\]
In this case, gamma
is the argument \(0.0\) in the code above.
Create windows, show the images and wait for the user to end the program.
C++
imshow( "Linear Blend", dst );
waitKey(0);
Java
HighGui.imshow("Linear Blend", dst);
HighGui.waitKey(0);
Python
Result