[OpenCV2]执行简单的图像算法

来源:互联网 发布:苏州谢谢网络 编辑:程序博客网 时间:2024/06/10 07:09

图像可以以不同的方式组合.因为他们是有规律的矩阵,他们可以相加,相减,相乘和相除.OpenCV提供了各种各样的图像算法,这节我们会讨论这个.

GetReading...

我们使用第二幅图像,我们会对他进行一个算法操作:和我们的输入图像结合.图像如下:


How to do it...

在这里我们添加两幅图像.当我想创建一些特殊效果或者在一幅图像上覆盖信息时,图像的加操作是很有用的.我们使用cv::add 函数,更多的,使用cv::addWeighted函数,因为我们想加权求和.如下:

   cv::addWeighted(image1,0.7,image2,0.9,0.,result);

这个操作的的结果如下.


How it Works ...

所有的二值处理函数使用相同的工作方式.提供了两个输入参数,第三一般是输出图像的系数.有时候,加权可以使用矩阵和一个数量相乘来实现.实现这些功能有不同的方法.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::subtract,cv::absdiff,cv::multiply,cv::divide.位操作也是可以使用的,如:cv::bitwise_and,cv::bitwise_or,cv::bitwise_xor和cv::bitwise_not. cv::min和cv::max操作会找到像素每个元素的最大值和最小值,非常有用.

在所有的例子中,函数cv::aturate_cast(上一节)总是用来确保结果在定义类型的像素值范围之内.(这避免了上溢和下溢).

图像必须有相同的大小和类型(如果输出图像与输入大小匹配,输出图像会被重新分配).因为这个操作是per-element执行的,所有输入图像也可以用做输出图像.

下面几个操作输入和输出图像也是可以的:cv::sqrt,cv::pow,cv::abs,cv::cuberoot,cv::exp和cv::log.实际上,几乎所有存在的OpenCV函数都可以对图像进行操作.

There's more ...

对cv::Mat对象或其中的一个通道使用c++算术操作是可以的,下面两个小节解释了如何使用.

Overloaded image operators

在OpenCV2中是非常方便的,大多数的算数功能有他们相应的重载操作符.对于cv::addWeighted函数也可以这样写:

result= 0.7*image1+0.9*image2;

这中形式更紧凑,更容易阅读.这两种方法是等价的.特别的,这个函数cv::saturate_cast在两种方式中都会被调用.

大部分的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.这主要是因为,当这么写的时候,这个表达式需要调用两个函数,按位与操作和数量求和(并不是在一个循环中执行的).虽然使用这个编码结果不是最优的,但是使用图像重载操作让编码如此简单,在大多数的情况下使得程序员很有效率,

Spliting the image channels

有时需要处理一个图像的不同通道.例如,你可能只对这个图像的一个通道进行处理.当然,你可以在一个图像循环中处理,但是也可以使用cv::split函数,把一个彩色图像的三个通道分离层三个cv::Mat对象.假设我们只想在我们的蓝色通道添加雨滴.代码如下:

   // create vector of 3 images   std::vector<cv::Mat> 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函数进行了两次操作.把三个单通道图像合并了一个彩色图像.




原创粉丝点击