上篇文章中我们讲到了使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。

而为了更好地观察一些图像材料的特征,有时需要对RGB三个颜色通道的分量进行 分割显示和调整 。通过Opencv 的split和merge 方法很方便 达到的目的。

一、分离颜色通道

先讲讲这俩个互为冤家的函数。首先讲进行通道分离的split 函数

<1>split函数详解

将一个多通道数组分离成几个单通道数组。  PS:这里的array按语境译为 数组或阵列。

这里的split 函数的C++版本有俩个原型,他们分别是:

 void split(const Mat& src,Mat *mvbegin);
void split(InputArray m, OutputArrayOfArrays mv);

变量介绍:

----第一个参数:InputArray类型的m或者const Mat&类型的src,填我们需要进行分离的多通道数组。

----第二个参数,OutputArrayOfArrays类型的mv,填函数的输出数组或者输出的vector容器。

这里的OutputArrayOfArrays我们通过【转到定义】大法,可以查到它是_OutputArray的引用,那么我们在源代码中再次通过【转到定义】看到_OutputArray类的原型,即是OutputArrayOfArrays的原型:

 class CV_EXPORTS _OutputArray : public_InputArray
{
public:
_OutputArray(); _OutputArray(Mat& m);
template<typename _Tp> _OutputArray(vector<_Tp>& vec);
template<typename _Tp> _OutputArray(vector<vector<_Tp>>& vec);
_OutputArray(vector<Mat>& vec);
template<typename _Tp> _OutputArray(vector<Mat_<_Tp>>& vec);
template<typename _Tp> _OutputArray(Mat_<_Tp>& m);
template<typename _Tp, int m, int n> _OutputArray(Matx<_Tp, m,n>& matx);
template<typename _Tp> _OutputArray(_Tp* vec, int n);
_OutputArray(gpu::GpuMat& d_mat);
_OutputArray(ogl::Buffer& buf);
_OutputArray(ogl::Texture2D& tex); _OutputArray(constMat& m);
template<typename _Tp> _OutputArray(const vector<_Tp>&vec);
template<typename _Tp> _OutputArray(constvector<vector<_Tp> >& vec);
_OutputArray(const vector<Mat>& vec);
template<typename _Tp> _OutputArray(const vector<Mat_<_Tp>>& vec);
template<typename _Tp> _OutputArray(const Mat_<_Tp>& m);
template<typename _Tp, int m, int n> _OutputArray(constMatx<_Tp, m, n>& matx);
template<typename _Tp> _OutputArray(const _Tp* vec, int n);
_OutputArray(const gpu::GpuMat& d_mat);
_OutputArray(const ogl::Buffer& buf);
_OutputArray(const ogl::Texture2D& tex); virtual bool fixedSize() const;
virtual bool fixedType() const;
virtual bool needed() const;
virtual Mat& getMatRef(int i=-) const;
/*virtual*/ gpu::GpuMat& getGpuMatRef() const;
/*virtual*/ ogl::Buffer& getOGlBufferRef() const;
/*virtual*/ ogl::Texture2D& getOGlTexture2DRef() const;
virtual void create(Size sz, int type, int i=-, bool allowTransposed=false,int fixedDepthMask=) const;
virtual void create(int rows, int cols, int type, int i=-, boolallowTransposed=false, int fixedDepthMask=) const;
virtual void create(int dims, const int* size, int type, int i=-, boolallowTransposed=false, int fixedDepthMask=) const;
virtual void release() const;
virtual void clear() const; #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY
virtual ~_OutputArray();
#endif
};

类体中还是有不少内容的,其实注意到里面是定义的各种模板,重载的各种构造函数就可以了。

好了,穿越完OutputArrayOfArrays的介绍,我们继续讲解split。

split函数分割多通道数组转换成独立的单通道数组,按公式来看就是这样:

<2>merge函数详解

merge()函数的功能是split()函数的逆向操作,将多个数组组合合并成一个多通道的数组

它通过组合一些给定的单通道数组,将这些孤立的单通道数组合并成一个多通道的数组,从而创建出一个由多个单通道阵列组成的多通道阵列。它有两个基于C++的函数原型:

void merge(const Mat* mv, size_tcount,OutputArray dst);
void merge(InputArrayOfArrays mv, OutputArray dst);
  • 第一个参数,mv,填需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度。
  • 第二个参数,count,当mv为一个空白的C数组时,代表输入矩阵的个数,这个参数显然必须大于1.
  • 第三个参数,dst,即输出矩阵,和mv[0]拥有一样的尺寸和深度,并且通道的数量是矩阵阵列中的通道的总数。

函数解析:

merge函数的功能是将一些数组合并成一个多通道的数组。关于组合的细节,输出矩阵中的每个元素都将是输出数组的串接,其中,第i个输入数组的元素被视为mv[i]。 c一般用其中的Mat::at()方法对某个通道进行存取,也就是这样用channels.at(0)。

PS: Mat::at()方法,返回一个引用到指定的数组元素。注意是引用,相当于两者等价,修改其中一个另一个跟着变。

一对做相反操作的plit()函数和merge()函数和用法就是这些了。另外提一点,如果我们需要从多通道数组中提取出特定的单通道数组,或者说实现一些复杂的通道组合,可以使用mixChannels()函数。

二、多通道图像混合示例程序

我们把多通道图像混合的实现代码封装在了名为MultiChannelBlending()的函数中

 #include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> using namespace cv;
using namespace std; bool MultiChannelBlending(); /*-------------------------------------------------------------
多通道混合的实现函数
---------------------------------------------------------------*/
bool MultiChannelBlending()
{
Mat srcImage;
Mat logoImage;
vector<Mat> channels; /*-----------------蓝色通道部分----------------------------
描述:多通道混合--蓝色部分
-----------------------------------------------------------*/
//【0】定义相关变量
Mat imageBlueChannel; //【1】读入图片
logoImage = imread("dota_logo.jpg",);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data)
{
printf("Oh,no,读取logoImage错误~! \n");
return false;
}
if (!srcImage.data)
{
printf("Oh,no,读取srcImage错误~! \n");
return false;
} //【2】把一个3通道图像转换成3个单通道图像
split(srcImage,channels); //【3】将原图的蓝色通道引用返回给 imageBlueChannel,注意是引用,相当于两者等价,修改一个另一个也跟着变
imageBlueChannel = channels.at(); //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo 图进行加权操作,将得到的混合结果存到imageBlueChannel中
addWeighted(imageBlueChannel(Rect(,,logoImage.cols,logoImage.rows)),1.0,logoImage,0.5,,
imageBlueChannel(Rect(,,logoImage.cols,logoImage.rows))); //【5】将3个单通道重新合并成1个3通道
merge(channels,srcImage); //【6】显示效果图
namedWindow("1 游戏原画+(logo+原画蓝色通道) byhehheh");
imshow("1 游戏原画+(logo+原画蓝色通道) byhehheh",srcImage); /*-----------------绿色通道部分----------------------------
描述:多通道混合--绿色部分
-----------------------------------------------------------*/
//【0】定义相关变量
//Mat imageGreenChannel;
/*
//【1】读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data)
{
printf("Oh,no,读取logoImage错误~! \n");
return false;
}
if (!srcImage.data)
{
printf("Oh,no,读取srcImage错误~! \n");
return false;
}
*/
/*
//【2】把一个3通道图像转换成3个单通道图像
split(srcImage, channels); //【3】将原图的绿色通道引用返回给 imageBlueChannel,注意是引用,相当于两者等价,修改一个另一个也跟着变
imageGreenChannel = channels.at(0); //【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo 图进行加权操作,将得到的混合结果存到imageBlueChannel中
addWeighted(imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0, logoImage, 0.5, 0,
imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows))); //【5】将3个单通道重新合并成1个3通道
merge(channels, srcImage); //【6】显示效果图
namedWindow("2 游戏原画+(logo+原画绿色通道) byhehheh");
imshow("2 游戏原画+(logo+原画绿色通道) byhehheh", srcImage);
*/ /*-----------------红色通道部分----------------------------
描述:多通道混合--红色部分
-----------------------------------------------------------*/
//【0】定义相关变量
//Mat imageRedChannel;
/*
//【1】读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data)
{
printf("Oh,no,读取logoImage错误~! \n");
return false;
}
if (!srcImage.data)
{
printf("Oh,no,读取srcImage错误~! \n");
return false;
}
*/
/*
//【2】把一个3通道图像转换成3个单通道图像
split(srcImage, channels); //【3】将原图的红色通道引用返回给 imageBlueChannel,注意是引用,相当于两者等价,修改一个另一个也跟着变
imageRedChannel = channels.at(0); //【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo 图进行加权操作,将得到的混合结果存到imageBlueChannel中
addWeighted(imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0, logoImage, 0.5, 0,
imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows))); //【5】将3个单通道重新合并成1个3通道
merge(channels, srcImage); //【6】显示效果图
namedWindow("3 游戏原画+(logo+原画红色通道) byhehheh");
imshow("3 游戏原画+(logo+原画红色通道) byhehheh", srcImage);
*/
return true;
} /*分离颜色通道&多通道图像混合*/
int main()
{
system("color 6E"); if (MultiChannelBlending())
{
cout << "得出了需要的图像" << endl;
} waitKey();
return ;
}

学习 opencv---(4) 分离颜色通道 && 多通道混合的更多相关文章

  1. opencv3.2.0 分离颜色通道&多通道图像混合

    ##名称:分离颜色通道&多通道图像混合 ##平台:QT5.7.1+OpenCV3.2.0 ##时间:2017年12月11日 /***************创建QT控制台程序********* ...

  2. opencv 3 core组件进阶(2 ROI区域图像叠加&图像混合;分离颜色通道、多通道图像混合;图像对比度,亮度值调整)

    ROI区域图像叠加&图像混合 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp&g ...

  3. <学习opencv>绘画和注释

    /*=========================================================================*/ // 绘画 和 注释 /*========= ...

  4. 深入学习OpenCV检测及分割图像的目标区域

    准备1:OpenCV常用图片转换技巧 在进行计算机视觉模型训练前,我们经常会用到图像增强的技巧来获取更多的样本,但是有些深度学习框架中的方法对图像的变换方式可能并不满足我们的需求,所以掌握OpenCV ...

  5. 《学习OpenCV》练习题第四章第三题b

    #include <highgui.h> #include <cv.h> #include "opencv_libs.h" /* *<学习OpenCV ...

  6. 学习opencv中文版教程——第二章

    学习opencv中文版教程——第二章 所有案例,跑起来~~~然而并没有都跑起来...我只把我能跑的都尽量跑了,毕竟看书还是很生硬,能运行能出结果,才比较好. 越着急,心越慌,越是着急,越要慢,越是陌生 ...

  7. Photoshop颜色通道实例

    PHOTOSHOP学到这会儿,我们不得不来学学枯燥乏味的颜色理论了,因为如果再不学,就难以学下去了.眼下我们就遇到了难点:颜色通道.前面在初识通道的时候,我已经说过:当你打开一张照片(RGB模式)的时 ...

  8. <学习opencv>图像和大型阵列类型

    OPenCV /*=========================================================================*/ // 图像和大型阵列类型 /* ...

  9. 《学习OpenCV》中求给定点位置公式

    假设有10个三维的点,使用数组存放它们有四种常见的形式: ①一个二维数组,数组的类型是CV32FC1,有n行,3列(n×3) ②类似①,也可以用一个3行n列(3×n)的二维数组 ③④用一个n行1列(n ...

随机推荐

  1. [LeetCode] Reverse Words in a String II 翻转字符串中的单词之二

    Given an input string, reverse the string word by word. A word is defined as a sequence of non-space ...

  2. [LeetCode] Merge Intervals 合并区间

    Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8, ...

  3. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...

  4. JavaScript模板引擎artTemplate.js——是否编码输出html字符

    template.config(name, value)方法用于更改引擎的默认配置. 其中字段escape,类型为boolean,默认为true. 首先,我们不修改配置信息输出一段带有html标签的字 ...

  5. [板子]ISAP

    ISAP求最大流,敲了一发板子,无压行,教程略去.转载请随意. #include <cstdio> #include <cstring> #include <algori ...

  6. Socket通信综合示例

    1用户注册客户单选择'用户注册',提示要输入用户名,密码,确认密码,校验成功后将用户信息保存到数据库,并提示数据库注册成功,请登录2用户登录客户端选择'登录以后'后,提示输入用户名和密码,验证成功则提 ...

  7. archlinux安裝手记(Win10+Arch、GPT+UEFI、lvm)

    准备工具和设置制作启动盘连接网络硬盘分区规划分区LVM方案创建文件系统分区挂载激活lvm2钩子基础安装和配置配置镜像源基础系统安装fstab进入系统initramfs引导程序网络搭建使用环境用户管理用 ...

  8. DeepMind背后的人工智能:深度学习原理初探

    去年11月,一篇名为<Playing Atari with Deep Reinforcement Learning>的文章被初创人工智能公司DeepMind的员工上传到了arXiv网站.两 ...

  9. SSM整合(二):Spring4与Mybatis3整合

    上一节测试好了Mybatis3,接下来整合Spring4! 一.添加spring上下文配置 在src/main/resources/目录下的spring新建spring上下文配置文件applicati ...

  10. CSS display:inline-block

    CSS display:inline-block 在css布局里,我们经常看到代码 「display:inline-block; *display:inline; zoom:1; 」,大多人会说上面的 ...