图像可以以不同的方式组合.因为他们是有规律的矩阵,他们可以相加,相减,相乘和相除.OpenCV提供了各种各样的图像算法,这节我们会讨论这个.
我们使用第二幅图像,我们会对他进行一个算法操作:和我们的输入图像结合.图像如下:
在这里我们添加两幅图像.当我想创建一些特殊效果或者在一幅图像上覆盖信息时,图像的加操作是很有用的.我们使用cv::add 函数,更多的,使用cv::addWeighted函数,因为我们想加权求和.如下:
cv::addWeighted(image1,0.7,image2,0.9,0.,result);
所有的二值处理函数使用相同的工作方式.提供了两个输入参数,第三一般是输出图像的系数.有时候,加权可以使用矩阵和一个数量相乘来实现.实现这些功能有不同的方法.cv::add 是一个很好的例子,展示了大部分的函数如何使用.
// c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC);
// c[i]= a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
// c[i]= k1*a[1]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,imageB,k2,k3,resultC);
// c[i]= k*a[1]+b[i];
cv::scaleAdd(imageA,k,imageB,resultC);
// if (mask[i]) c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC,mask);
在所有的例子中,函数cv::aturate_cast(上一节)总是用来确保结果在定义类型的像素值范围之内.(这避免了上溢和下溢).
图像必须有相同的大小和类型(如果输出图像与输入大小匹配,输出图像会被重新分配).因为这个操作是per-element执行的,所有输入图像也可以用做输出图像.
下面几个操作输入和输出图像也是可以的:cv::sqrt,cv::pow,cv::abs,cv::cuberoot,cv::exp和cv::log.实际上,几乎所有存在的OpenCV函数都可以对图像进行操作.
对cv::Mat对象或其中的一个通道使用c++算术操作是可以的,下面两个小节解释了如何使用.
在OpenCV2中是非常方便的,大多数的算数功能有他们相应的重载操作符.对于cv::addWeighted函数也可以这样写:
result= 0.7*image1+0.9*image2;
大部分的C++操作符都被重载了.包含为运算符&,|,^,~,min,max和abs函数,比较运算符 < ,<=,==,!=,>,>=.最后这一组会返回一个8位二值图像.你可以可以对矩阵进行乘法操作 m1*m2(m1和m2都是cv::Mat对象),矩阵转置 m1.inv(),转置阵m1.t(),行列式m1.determiant(),单位矢量 v1.norm(),向量积v1.cross(v2),点积v1.dot(v2)等等.为了更直观,你也可以使用op= 操作符定义(例如+=);
在编写高效的图像循环一节,我们实现了一个颜色减少函数,我们使用循环,并在循环中对对像素进行操作实现.这个功能可以用算术操作符简单的写出来:
image=(image&cv::Scalar(mask,mask,mask))
+cv::Scalar(div/2,div/2,div/2);
使用cv::Scalar是由于我们处理的是一幅彩色图像.对它进行了效率测试,我们发现花费了89ms.这主要是因为,当这么写的时候,这个表达式需要调用两个函数,按位与操作和数量求和(并不是在一个循环中执行的).虽然使用这个编码结果不是最优的,但是使用图像重载操作让编码如此简单,在大多数的情况下使得程序员很有效率,
有时需要处理一个图像的不同通道.例如,你可能只对这个图像的一个通道进行处理.当然,你可以在一个图像循环中处理,但是也可以使用cv::split函数,把一个彩色图像的三个通道分离层三个cv::Mat对象.假设我们只想在我们的蓝色通道添加雨滴.代码如下:
// create vector of 3 images
std::vector planes;
// split 1 3-channel image into 3 1-channel images
cv::split(image1,planes);
// add to blue channel
planes[0]+= image2;
// merge the 3 1-channel images into 1 3-channel image
cv::merge(planes,result);
这个cv::merge函数进行了两次操作.把三个单通道图像合并了一个彩色图像.