上篇文章中我们讲到了使用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. PIC10F200/202/204/206/220/222/320/322芯片解密程序复制多少钱?

    PIC10F200/202/204/206/220/222/320/322芯片解密程序复制多少钱? PIC10F单片机芯片解密型号: PIC10F200解密 | PIC10F202解密 | PIC10 ...

  2. 解读ASP.NET 5 & MVC6系列(17):MVC中的其他新特性

    (GlobalImport全局导入功能) 默认新建立的MVC程序中,在Views目录下,新增加了一个_GlobalImport.cshtml文件和_ViewStart.cshtml平级,该文件的功能类 ...

  3. 【第一篇】ASP.NET MVC快速入门之数据库操作(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  4. minHash最小哈希原理

    minHash最小哈希原理 收藏 初雪之音 发表于 9个月前 阅读 208 收藏 9 点赞 1 评论 0 摘要: 在数据挖掘中,一个最基本的问题就是比较两个集合的相似度.通常通过遍历这两个集合中的所有 ...

  5. c++局域网多播

    转自http://www.51cto.com/specbook/17/35216.htm Visual C++实现局域网IP多播 在局域网中,管理员常常需要将某条信息发送给一组用户.如果使用一对一的发 ...

  6. git详解

    Git使用教程   source: http://www.cnblogs.com/tugenhua0707/p/4050072.html 一:Git是什么? Git是目前世界上最先进的分布式版本控制系 ...

  7. jquery网页可见区域宽

    网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWid ...

  8. wm_concat

    select to_char(wm_concat(ssss)) from (select replace(C_CELL_CONTENT ,'=$','') ssss ,rownum ss from ( ...

  9. win7下安装mysql后修改密码

    mysql的安装教程网上很多,此处不过多介绍,个人觉得下面这篇教程是比较好的,一步到位.MySQL 5.7.9 ZIP 免安装版本配置过程_百度经验  http://jingyan.baidu.com ...

  10. 记录在linux下的wine生活

    记录在linux下的windows生活 本篇内容涉及QQ.微信.Office的安装配置 QQ: 到deepin下载轻聊版. 如果安装了crossover,那么将其中opt/cxoffice/suppo ...