OpenCV3学习(2.4)——彩色图像读取、灰度图转化、RGB通道分割与合并

下列代码涉及到:

1、彩色图像的读取,图像翻转,转换为灰度图;

2、对彩色图像的RGB三通道进行切分与合并;

涉及到的函数如下:

1、图像的反转采用flip函数实现,该函数能够实现图像在水平方向,垂直方向和水平垂直方向的旋转,函数代码如下:

void cv::flip( InputArray src,OutputArray dst,int flipCode)

其中:

src 是原始图像;

dst 是和原始图像大小,类型相同的目标图像;

flipCode 是旋转类型,0代表x轴旋转,任意正数代表y轴旋转,任意负数代表x和y轴同时旋转

 2、通道分离通过split函数实现,函数原型:

CV_EXPORTS void split(const Mat& src, Mat* mvbegin);
CV_EXPORTS void split(const Mat& m, vector<Mat>& mv );

第一个参数为要进行分离的图像矩阵,第二个参数可以是Mat数组的首地址,或者一个vector<Mat>对象。

注意:opencv中,RGB三个通道是反过来的。

3、merge()函数的功能是split()函数的逆向操作,将多个数组组合合并成一个多通道的数组。它通过组合一些给定的单通道数组,将这些孤立的单通道数组合并成一个多通道的数组,从而创建出一个由多个单通道阵列组成的多通道阵列。基于C++的函数原型:

CV_EXPORTS void merge(const Mat* mv, size_t count, OutputArray dst);
CV_EXPORTS void merge(const vector<Mat>& mv, OutputArray dst );

//! makes multi-channel array out of several single-channel arrays
CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst);

第一个版本:第一个参数是图像矩阵数组,mv参数中所有的矩阵必须有着一样的尺寸和深度。第二个参数是需要合并矩阵的个数,这个参数显然必须大于1,一般是3(R,G,B)。第三个参数是输出矩阵,和mv[0]拥有一样的尺寸和深度,并且通道的数量是矩阵阵列中的通道的总数。

第二个版本:图像矩阵向量容器,第二个参数是输出,这种方法无需说明需要合并的矩阵个数,vector对象自带说明。

函数解析:

第i个输入数组的元素被视为mv[i]。 c一般用其中的Mat::at()方法对某个通道进行存取,也就是这样用channels.at(i)或channels[i]。

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

at()与[]一样,为下标索引。

4、mixChannels主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中,其中的对应关系就由fromTo参数制定;

CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts,
                            const int* fromTo, size_t npairs);
CV_EXPORTS void mixChannels(const vector<Mat>& src, vector<Mat>& dst,
                            const int* fromTo, size_t npairs);
CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputArrayOfArrays dst,
                              const vector<int>& fromTo);

src:输入矩阵,可以为一个也可以为多个,但是矩阵必须有相同的大小和深度

nsrcs:输入矩阵的个数

dst:输出矩阵,可以为一个也可以为多个,但是所有的矩阵必须事先分配空间(如用create),大小和深度须与输入矩阵等

ndsts:输出矩阵的个数。

fromTo: 设置输入矩阵的通道对应输出矩阵的通道,规则如下:首先用数字标记输入矩阵的各个通道。输入矩阵个数可能多于一个并且每个矩阵的通道可能不一样, 第一个输入矩阵的通道标记范围为:0 ~ src[0].channels()-1,第二个输入矩阵的通道标记范围为:src[0].channels() ~ src[0].channels()+src[1].channels()-1,以此类推;其次输出矩阵也用同样的规则标记,第一个输出矩阵的通道标记范围为:0 ~ dst[0].channels()-1,第二个输入矩阵的通道标记范围为:dst[0].channels()~ dst[0].channels()+dst[1].channels()-1,以此类推;最后,数组fromTo的第一个元素即fromTo[0]应该填入输入矩阵的某个通道标记,而fromTo的第二个元素即fromTo[1]应该填入输出矩阵的某个通道标记,这样函数就会把输入矩阵的fromTo[0]通道里面的数据复制给输出矩阵的fromTo[1]通道。fromTo后面的元素也是这个道理,总之就是一个输入矩阵的通道标记后面必须跟着个输出矩阵的通道标记。 

npairs:即参数fromTo中的有几组输入输出通道关系,其实就是参数fromTo的数组元素个数除以2.
原文:https://blog.csdn.net/qq_36092251/article/details/79945123 

实例:

#include<opencv2\opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

void main() {
Mat img = imread("121.jpg", 1);   //如果要直接将彩图读取成灰度图--标志位改为"IMREAD_GRAYSCALE"或"0"
Mat des_img;
imshow("img",img);

flip(img, des_img, 1);//y轴旋转
imshow("des_img", des_img);

int row = img.rows;
int col = img.cols;
Mat grayimg = Mat(row, col, CV_8UC1);//构造mat矩阵单通道用于存放灰度图
Mat grayimg_ptr = Mat(row, col, CV_8UC1);

//彩色图像访问,转换为灰度图
for (int i = 0; i < row; i++)
{
	for (int j = 0; j < col; j++)
	{
		uchar b = img.at<Vec3b>(i, j)[0];//注意rgb的存放顺序
		uchar g = img.at<Vec3b>(i, j)[1];
		uchar r = img.at<Vec3b>(i, j)[2];
		grayimg.at<uchar>(i,j)= r * 0.299 + g * 0.587 + b * 0.114;//公式
	}
}
imshow("grayimg", grayimg);

//ptr访问方式
for (int i = 0; i < row; i++)
{
	Vec3b *p = img.ptr<Vec3b>(i);//彩色图,有rgb所以对应 Vec3b
	uchar *p2 = grayimg_ptr.ptr<uchar>(i);//灰度图,所以对应 uchar
	for (int j = 0; j < col; j++)
	{
		Vec3b &pix = *p++;
		uchar &pix2 = *p2++;
		pix2=pix[0] * 0.114 + pix[1] * 0.587 + pix[2] * 0.299;
	}
}
imshow("grayimg_ptr", grayimg_ptr);

////////提取彩色通道的单个通道/////////

Mat channel[3];//我的理解是,创建了三个Mat矩阵,有点类似 Vec<Mat> channel
split(img, channel);
//imshow("B", channel[0]);
//imshow("G", channel[1]);
//imshow("R", channel[2]);

channel[0] = Mat::zeros(row, col, CV_8UC1);//将B通道赋值为0
Mat RGimg(row, col, CV_8UC3);//构造mat矩阵存放彩色图
merge(channel, 3, RGimg);//将channel中三个通道channel[0],channel[1],channel[2]合并,存放在RGimg
imshow("RGimg",RGimg);


Mat bgr(row, col, CV_8UC3, Scalar(0, 0, 0));
Mat out[] = { bgr };	//??????相当于创建一个引用
for (int i = 0; i < 3; i++)
{
	int from_to[] = { i,i };//定义一种映射,img的第i通道映射bgr的第i通道
	mixChannels(&img, 1, &bgr, 1, from_to, 1);
}
    imshow("3 channel_bgr", bgr);
waitKey(0);
}

 结果:

猜你喜欢

转载自blog.csdn.net/qq_30815237/article/details/86675564