学习 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] Lexicographical Numbers 字典顺序的数字
Given an integer n, return 1 - n in lexicographical order. For example, given 13, return: [1,10,11,1 ...
- Goodbye 2016 总结与展望
今天居然是2016年的最后一天了,写点什么回忆吧. 2016开始的时候我刚拿到普及组一等奖,还只是压线,水平很差.学校并不知道这有多差,于是狠狠宣传这所谓的"光荣事迹".那段时间我 ...
- go database/sql sql-driver/mysql 操作
这里使用的是github.com/Go-SQL-Driver/MySQL, 所以需要下载一个github.com/Go-SQL-Driver/MySQL 引入 database/sql 和 githu ...
- 测试对于list的sort与sorted的效率
sorted from time import clock from random import randint start = clock() a = [randint(0,1000000) for ...
- Python学习--Python简介
Python 简介 Python是一种解释型.编译性.面向对象.动态数据类型的高级程序设计语言.Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年. P ...
- 错误400-The request sent by the client was syntactically incorrect
springMVC中,某个页面提交时报400错误,如下图. 解决方法: 1.在网上找了一下,答案是通常遇到这个错误是因为前端jsp页面的控件名称和controller中接收的参数名称不一致.但 ...
- windows下安装kibana出 "EPERM: operation not permitted
D:\kibana-\bin>kibana-plugin install file:///x-pack-5.0.0.zip Attempting to transfer from file:// ...
- js杂项
css是 下划线命名法:table_sub ;javascript ,net ,sql 全部是camel命名法 找临界点 1.elem.checked 有两个值,true,false . 页面中< ...
- lightbox使用
使用方法: 1.在页面头部包含 lightbox.js 文件并加载 lightbox.css 样式表文件 <script type="text/javascript" src ...
- web前端基础知识-(七)Django进阶
通过上节课的学习,我们已经对Django有了简单的了解,现在来深入了解下~ 1. 路由系统 1.1 单一路由对应 url(r'^index$', views.index), 1.2 基于正则的路由 u ...