学习 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 ...
随机推荐
- [LeetCode] Boom Enemy 炸弹人
Given a 2D grid, each cell is either a wall 'W', an enemy 'E' or empty '0' (the number zero), return ...
- JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面
前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...
- [网站公告]数据库服务器IOPS跑满造成网站不能正常访问
今年下午13:20-14:20左右,突增的访问量引发数据库服务器(阿里云RDS)IOPS跑满,造成大量请求执行缓慢,从而严重影响了网站的正常访问,给大家带来很大的麻烦,望大家谅解! 在出现故障时,当我 ...
- yii2使用小知识(连续补充)
1,打印ar或者query的原始sql: $query = (new \yii\db\Query())->select(['a.username','b.item_name'])->fro ...
- 分分钟搞定IOS远程消息推送
一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...
- CentOS下配置java环境变量classpath
一. 需要配置的环境变量1. PATH环境变量.作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序.我们需要把 jdk安装目录下的bin ...
- git 命令学习
last-update: 2016年10月27日 1. git stash 简短描述 当你正在进行项目中某一部分的工作,但是里面的东西处于一个比较杂乱的状态,但是却想要切换到其他分支.问题是,你不想提 ...
- JavaScript备忘录
提取字符串substring(start,end)substr(start [, length ])JavaScript substr() 方法 --
- SQL Server存储过程创建和修改
create proc Get_Data( @Del_ID varchar(36))asselect * from Depts where DeptId=@Del_ID select * from D ...
- 通过设置CSS属性让DIV水平居中
通过设置CSS属性让DIV水平居中 ---------------------- <html> <head> <title></title> <m ...