收入囊中
下面我进入Sample文件夹下的ImgProc子目录,首先研究下AddingImages.cpp,下面是源代码
#include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; int main( void ) { double alpha = 0.5; double beta; double input; Mat src1, src2, dst; /// Ask the user enter alpha std::cout<<" Simple Linear Blender "<<std::endl; std::cout<<"-----------------------"<<std::endl; std::cout<<"* Enter alpha [0-1]: "; std::cin>>input; // We use the alpha provided by the user iff it is between 0 and 1 if( alpha >= 0 && alpha <= 1 ) { alpha = input; } /// Read image ( same size, same type ) src1 = imread("../images/LinuxLogo.jpg"); src2 = imread("../images/WindowsLogo.jpg"); if( !src1.data ) { std::cout<< "Error loading src1"<<std::endl; return -1; } if( !src2.data ) { std::cout<< "Error loading src2"<<std::endl; return -1; } /// Create Windows namedWindow("Linear Blend", 1); beta = ( 1.0 - alpha ); addWeighted( src1, alpha, src2, beta, 0.0, dst); imshow( "Linear Blend", dst ); waitKey(0); return 0; }
代码很简单,第一幅图像占的比例是alpha,第二幅是1-alpha
dst = src1[I]*alpha+ src2[I]*beta + gamma;
下面我们看下addWeighted的源代码,在arithm.cpp中
void cv::addWeighted( InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype ) { double scalars[] = {alpha, beta, gamma}; arithm_op(src1, src2, dst, noArray(), dtype, getAddWeightedTab(), true, scalars); }
static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, InputArray _mask, int dtype, BinaryFunc* tab, bool muldiv=false, void* usrdata=0)
static BinaryFunc* getAddWeightedTab() { static BinaryFunc addWeightedTab[] = { (BinaryFunc)GET_OPTIMIZED(addWeighted8u), (BinaryFunc)GET_OPTIMIZED(addWeighted8s), (BinaryFunc)GET_OPTIMIZED(addWeighted16u), (BinaryFunc)GET_OPTIMIZED(addWeighted16s), (BinaryFunc)GET_OPTIMIZED(addWeighted32s), (BinaryFunc)addWeighted32f, (BinaryFunc)addWeighted64f, 0 }; return addWeightedTab; }看样子这些事函数指针的数组,那么GET_OPTIMIZED又是什么呢
#define GET_OPTIMIZED(func) (func)很多定义都来不及细看,下次有需要再细细研究,这些addWeighted8u等函数都在同个cpp下面定义了,我们的tab就是一系列函数指针。在arithm_op有一行函数是这样的,
BinaryFunc func = tab[CV_MAT_DEPTH(wtype)];根据数据类型拿到相应的加权函数
template<typename T, typename WT> static void addWeighted_( const T* src1, size_t step1, const T* src2, size_t step2, T* dst, size_t step, Size size, void* _scalars ) { const double* scalars = (const double*)_scalars; WT alpha = (WT)scalars[0], beta = (WT)scalars[1], gamma = (WT)scalars[2]; step1 /= sizeof(src1[0]); step2 /= sizeof(src2[0]); step /= sizeof(dst[0]); for( ; size.height--; src1 += step1, src2 += step2, dst += step ) { int x = 0; #if CV_ENABLE_UNROLLED for( ; x <= size.width - 4; x += 4 ) { T t0 = saturate_cast<T>(src1[x]*alpha + src2[x]*beta + gamma); T t1 = saturate_cast<T>(src1[x+1]*alpha + src2[x+1]*beta + gamma); dst[x] = t0; dst[x+1] = t1; t0 = saturate_cast<T>(src1[x+2]*alpha + src2[x+2]*beta + gamma); t1 = saturate_cast<T>(src1[x+3]*alpha + src2[x+3]*beta + gamma); dst[x+2] = t0; dst[x+3] = t1; } #endif for( ; x < size.width; x++ ) dst[x] = saturate_cast<T>(src1[x]*alpha + src2[x]*beta + gamma); } }这个函数就是我们的算法所在,可以很清晰看到
举一反三
addWeighted函数要求我们两个矩阵大小必须相同,那如果我想要不一样怎么办?
其实非常非常简单,要知道在OpenCV2中,只有clone和copyto两个函数才是复制数据的,其他的都是只是新建Mat的Header(包括行列等信息),数据却还是指向原来的地方,ref count增加了1次.
因此,只要我们能取到矩阵的一部分,进行混合不就可以了么。
假设src1是1000*1000,而src是100*100的小人头,我们想把小人头和src1的(500,500)坐标处进行混合
方法1:blendimg = src1(Range(500, 500 + src2.rows), Range(500, 500 + src2.cols));
方法2:blendimg = src1(Rect(500, 500, src2.cols, src2.rows));
再使用addWeighted函数即可