学习 opencv---(4) 分离颜色通道 && 多通道混合
上篇文章中我们讲到了使用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) 分离颜色通道 && 多通道混合的更多相关文章
- opencv3.2.0 分离颜色通道&多通道图像混合
##名称:分离颜色通道&多通道图像混合 ##平台:QT5.7.1+OpenCV3.2.0 ##时间:2017年12月11日 /***************创建QT控制台程序********* ...
- opencv 3 core组件进阶(2 ROI区域图像叠加&图像混合;分离颜色通道、多通道图像混合;图像对比度,亮度值调整)
ROI区域图像叠加&图像混合 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp&g ...
- <学习opencv>绘画和注释
/*=========================================================================*/ // 绘画 和 注释 /*========= ...
- 深入学习OpenCV检测及分割图像的目标区域
准备1:OpenCV常用图片转换技巧 在进行计算机视觉模型训练前,我们经常会用到图像增强的技巧来获取更多的样本,但是有些深度学习框架中的方法对图像的变换方式可能并不满足我们的需求,所以掌握OpenCV ...
- 《学习OpenCV》练习题第四章第三题b
#include <highgui.h> #include <cv.h> #include "opencv_libs.h" /* *<学习OpenCV ...
- 学习opencv中文版教程——第二章
学习opencv中文版教程——第二章 所有案例,跑起来~~~然而并没有都跑起来...我只把我能跑的都尽量跑了,毕竟看书还是很生硬,能运行能出结果,才比较好. 越着急,心越慌,越是着急,越要慢,越是陌生 ...
- Photoshop颜色通道实例
PHOTOSHOP学到这会儿,我们不得不来学学枯燥乏味的颜色理论了,因为如果再不学,就难以学下去了.眼下我们就遇到了难点:颜色通道.前面在初识通道的时候,我已经说过:当你打开一张照片(RGB模式)的时 ...
- <学习opencv>图像和大型阵列类型
OPenCV /*=========================================================================*/ // 图像和大型阵列类型 /* ...
- 《学习OpenCV》中求给定点位置公式
假设有10个三维的点,使用数组存放它们有四种常见的形式: ①一个二维数组,数组的类型是CV32FC1,有n行,3列(n×3) ②类似①,也可以用一个3行n列(3×n)的二维数组 ③④用一个n行1列(n ...
随机推荐
- 台式机装原版Win2008R2
台式机装原版Win2008R2 坑了老半天,总结出几点 1,系统os下载: http://msdn.itellyou.cn/ 注:其他地方下载的,装后发现不是起不来就是驱动装不了. 2,u盘里放个压缩 ...
- [LeetCode] LFU Cache 最近最不常用页面置换缓存器
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...
- [LeetCode] Fizz Buzz 嘶嘶嗡嗡
Write a program that outputs the string representation of numbers from 1 to n. But for multiples of ...
- IT培训行业揭秘(五)
前面说了一大堆,简单揭露了一些目前培训行业鱼龙混在的情况,那么今天我就站在一个即将毕业的大学生角度来谈谈如何选择一个靠谱的培训机构. 你即将大学毕业了,在大学里面浑浑噩噩的混了几年,马上就要离开校园, ...
- 【C#】透屏幕,屏幕扩展
if (!SCREEN_STATE) { ) { System.Windows.Forms.Screen s2 = System.Windows.Forms.Screen.AllScreens[]; ...
- [转]ExtJs基础--Html DOM、Ext Element及Component三者之间的区别
要学习及应用好Ext框架,必须需要理解Html DOM.Ext Element及Component三者之间的区别. 每一个HTML页面都有一个层次分明的DOM树模型,浏览器中的所有内容都有相应的DOM ...
- [WP8.1开发]RSA 使用BouncyCastle 公钥解密
写应用的时候遇到个服务器返回私钥加密过的数据 ,然后要在客户端用公钥解密的需求 ,一直没找到方法,应用搁置了一个学期,多方搜索,结论就是.net没有实现公钥解密的方法,要自己实现,于是硬着头皮开始看B ...
- ASE周会记录
本周Sprint Master Atma Hou 一. 本周会议概要 本次会议的主要任务是明确和老师讨论后的数据库设计定稿,同时为我们接下来的连接工作确定包含实现细节的story和接口. 二. 会议内 ...
- PHP 进程间通信——消息队列(msg_queue)
PHP 进程间通信--消息队列 本文不涉及PHP基础库安装.详细安装说明,请参考官网,或期待后续博客分享. 1.消息队列函数准备 <?php//生成一个消息队列的key$msg_key = ft ...
- ES6入门笔记
ES6入门笔记 02 Let&Const.md 增加了块级作用域. 常量 避免了变量提升 03 变量的解构赋值.md var [a, b, c] = [1, 2, 3]; var [[a,d] ...