使用openCV来完成图像的叠加

在openCV中我们可以使用以下函数来进行图像的叠加:

addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst);

接下来让我们来好好分析一下这个函数:

src1:需要叠加的第一个图像

alpha:src1图像在叠加时所占的权重

src2:需要叠加的另一个图像

beta:src2图像在叠加式所占的权重

gamma:叠加完后加的常数,你可以增加gamma的值让图片更亮

dst:叠加完后输出的图像

示例

#include<opencv2/opencv.hpp>
#include<stdc++.h>
using namespace cv;
using namespace std;

int main() {

  Mat a,b,c;
  /*读取图片*/
  a = imread("D:\\壁纸\\带带大师兄.jpg");
  if (!a.data) {
    printf("没有找到图片");
    return -1;
  }
  b = imread("D:\\壁纸\\星空.jpg");
  if (!b.data) {
    printf("没有找到图片");
    return -1;
  }	
  /*当大小一致时直接进行叠加*/
  if (a.size() == b.size()) {
    addWeighted(a, 0.4, b, 0.6,0, c);
    imshow("jun", c);
  }
  /*当大小不一致时先改变大小至一致再进行叠加*/
  else 
  {
    Mat bnew;
    int row, col;
    row = a.rows;
    col = a.cols;
    resize(b, bnew, Size(col, row));			
    addWeighted(a, 0.2, bnew, 0.8, 0, c);
    imshow("jun", c);		
  }
  
  waitKey(0);
  return 0;
}

在使用addWeighted()函数时要注意两张图片的大小必须相等,所以我们在进行叠加图片前要判断两者大小是否相等。这里介绍下resize()函数:

resize( InputArray src, OutputArray dst,Size dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR )

我们来分析一下这个函数:

src:输入图像

dst:输出图像

dsize:改变后图像的大小,如果选择填写此参数那么我们就要填写精确的数值,如Size(30,30),这就代表改变后的图像大小为30*30。如果你不选择填写此参数你可以填写0,那么你就需要填写fx、fy参数。

fx、fy:如果你无法确定被改变大小的图像要改变的确切数值你可以填写此参数,此参数会根据你填写的数值进行放大或缩小,如:

resize(jun,bian,Size(),2,2,INTER_LINEAR);

这样我们就能把jun这个图像按x轴放到2倍,按y轴放大2倍,并得到新的图像bian。

interpolation:此参数是用来选择使用什么插值法来进行变换图片大小。不论是放大或是缩小图像都需要插值运算,缩小图像时,目标图像的像素会映射为源图像中的多个像素,放大图像时,目标图形上的像素可能无法在源图像中找到精确对应的像素,都需要进行插值运算。

当然了,你可以将此参数空着,这样就会选择默认的双线性插值法。

以下为你可以选择的插值法:

1)INTER_NEAREST – 最近邻插值法
2)INTER_LINEAR – 双线性插值法(默认)
3)INTER_AREA – 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
4)INTER_CUBIC – 基于4×4像素邻域的3次插值法
5)INTER_LANCZOS4 – 基于8×8像素邻域的Lanczos插值

使用resize()函数我们就能让a图像和b图像大小一致了,接下来就是使用addWeighted()函数进行叠加操作了。

让我们来运行一下试试:

我们可以看到两幅图片叠加到一起了!是不是觉得很儒雅随和呢?

 

openCV:Mat对象详解和使用

Mat对象

Mat是OpenCV中用来存储图像信息的内存对象,可以理解为一个包含所有强度值的像素点矩阵,另外包含其他信息(宽,高,类型,纬度,大小,深度等)。

当你使用Mat对象时会自动为你分配内存空间,不用再像openCV2.x.x版本之前一样使用IplImage还要自己分配内存空间。

Mat对象使用

首先是最简单的使用:

Mat a;
a = imread("...");

定义一个Mat对象a后使用imread函数读取一张图片。

我们还能这样使用Mat:

Mat a,b;
a=imread("...");
b=Mat(a.size(),a.type());

首先定义一个Mat对象a并读取一张图片后定义一个Mat对象b,并且这个对象b的大小和格式与a是一样的。

Mat a,b;
a=imread("...");
b=Mat(a.size(),a.type());
b=Scalar(255,255,255);

因为我们刚才只是定义了一个Mat对象b的框架所以我们可以使用Scalar函数来让b这个对象生成一张图片,图片的颜色为白色(因为三原色的值都为255所以是白色)。

Mat a,b;
a=imread("...");
b=a.clon();

如果我们想要完全复制一张照片要怎么办呢?这时我们就可以使用clon()这个函数了,clon()是全复制你不需要担心因为改变了对象a的数值而会导致对象b的数值随着a改变而改变。

Mat a,b;
a = imread("..");
a.copyTo(b);

copyTo()函数和clon()函数也是一样的效果,你可以根据自己的喜好去使用。

Mat a,b;
a = imread("..");
cvtColor(a,b,COLOR_BGR2GRAY);

cvtColor()函数可以将a复制到b并且以COLOR_BGR2GRAY的形式展现给你,在这里COLOR_BGR2GRAY是参数名称灰度图的意思。你可以根据需要使用其它参数。

Mat a(3,3,CV_8UC3,Scalar(50,100,200);
cout<<a<<endl;
namedWindow("test",CV_WINDOW_AUTOSIZE);
imshow("test",a);

我们同样可以使用Mat对象创建一个x*x的矩阵,并根据参数CV_8UC3来为它每个像素点来设置数值为(50,100,200)。需要解释一下的是C3代表的是Channel 3,意味着我们这张图片每个像素点有3个通道分别对应的是三原色(RGB),而后面的数值(50,100,200)就是三原色的数值(当然你可以根据需要自己变)。

除了三通道还有一通道,也就是灰度图(还记得上文哪有提到过🐎?)

Mat a = Mat::eye(5, 5, CV_8UC1);

我们可以通过上面这种形式来对对象a进行初始化,这里的eye代表最后出现的矩阵是以对角线形式出现的

你可以修改参数为zeros,这样它就会把矩阵通通初始化为0:

 

Mat对象差不多就讲到这儿了,光看没有用建议打开电脑自己也来操作一遍这样印象才深刻嗷!

如何在openCV中使用掩膜来完成对图像的处理

什么是掩膜?

在本篇文章开始前我们需要先来了解一下什么是掩膜,掩膜就是用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。用于覆盖的特定图像或物体称为掩模或模板。

掩膜通常是个n*n的矩阵,我们可以通过掩膜来更好地处理图像。

代码解析

首先贴上源码,关于代码的解析我已经写好了注释:

#include<opencv2/opencv.hpp>
#include<stdc++.h>

using namespace std;
using namespace cv;
int main() {
  Mat jun = imread("D:\\壁纸\\jun.png");//读取图片
  namedWindow("junbian", CV_WINDOW_AUTOSIZE);//创建窗口
  imshow("junbian", jun);//在窗口上显示图片

  Mat bian;
/* 创建一个掩膜 */
  Mat kernel = (Mat_<char>(3,3)<<0, -1,  0,
                              -1, 5, -1, 
                               0,-1, 0);
/* 使用filter2D来对图像进行处理 */
  filter2D(jun, bian, -1, kernel);

  namedWindow("cool jun", CV_WINDOW_AUTOSIZE);
  imshow("cool jun", bian);

  waitKey(0);
  return 0;
}

让我们来看看结果:

我们会发现处理过后的图像相较于原图对比度增强了。

接下来让我们来换一个掩膜试试看:

#include<opencv2/opencv.hpp>
#include<stdc++.h>

using namespace std;
using namespace cv;
int main() {
  Mat jun = imread("D:\\壁纸\\jun.png");//读取图片
  namedWindow("junbian", CV_WINDOW_AUTOSIZE);//创建窗口
  imshow("junbian", jun);//在窗口上显示图片

  Mat bian;
/* 创建一个掩膜 */
  Mat kernel = (Mat_<char>(3,3)<<-1, 0, -1,
                                  0, 4, 0, 
                                  -1,0,-1);
/* 使用filter2D来对图像进行处理 */
  filter2D(jun, bian, -1, kernel);

  namedWindow("cool jun", CV_WINDOW_AUTOSIZE);
  imshow("cool jun", bian);

  waitKey(0);
  return 0;
}

运行后的结果:

我们可以看到图像的轮廓被描绘了出来,在这里我们使用的掩膜是拉普拉斯滤波器,它可以将画面轮廓清晰地描绘出来。