C++ OpenCV 基本函数(memcpy 内存拷贝、split多通道分离、merge多通道合并函数 )


用实现照片底片化的例子介绍一些基本函数
所谓照片底片化,就是将图像每个像素的RGB三个通道取反,如果是256色,就是R’=255-R, G’=255-G, B’=255-B,如果是0.0-1.0的颜色空间,就是R’=1.0-R, G’=1.0-G, B’=1.0-B。通过上述描述,可得出算法:遍历每个像素点RGB值-重新计算-生成图像

memcpy 内存拷贝

原始图像:
在这里插入图片描述

/#include<iostream>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;


int main()
{

	//设置图片路径
	string path = "./yy.jpg";
	//生成Mat型图像矩阵
	Mat I = imread(path);
	//转化Mat内部数据类型,此处可以不加 1 / 255.0,后面取反的时候用255-像素值
	I.convertTo(I, CV_32FC3, 1 / 255.0);

	//构建像素值数组
	float* img_data = new float[I.cols * I.rows * 3];
	//像素值拷贝
	memcpy(img_data, I.data, I.cols * I.rows * 3 * sizeof(float));
	//遍历像素并计算
	for (int i = 0; i < I.cols * I.rows * 3; i++)
	{
		img_data[i] = 1 - img_data[i];
	}
	//通过像素数组重新生成图像
	Mat result1(I.rows, I.cols, CV_32FC3, img_data);

	//保存图片,由于像素值位0~1,打开后是黑色,显示时需要线性变换到0~255,才能显示图片
	imwrite("./yy_result1.jpg", result1);

	//显示结果
	imshow("result1", result1);
	waitKey(0);
	return 0;
}

结果图:

在这里插入图片描述
函数void *memcpy(void *dest, const void *src, size_t n);
该函数在OpenGL部分文章中有提及,该函数并非OpenCV函数而是C++函数,作用是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中,

参数void *dest:目标指针,文中为新创建空数组img_data

参数const void *src:源内存地址起始位置,Mat型图像起始指针表示为Mat.data,因此文中为I.data

参数size_t n:内存长度,文中为像素个数3通道(图像长宽*3),再乘以数据种类所占空间(sizeof(float)),最终形式为I.cols*I.rows * 3 * sizeof(float)

Mat构造函数
1. Mat(int rows, int cols, int type, const Scalar& s);
2. Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);

Mat类型的构造函数有很多种(20种左右吧),目的是为了满足不同作用矩阵的构造需求。对于图像处理和一般操作来说,主要应用上述两种类型构造函数

参数int rows, int cols:矩阵长宽,文中构造与原图尺寸相同的矩阵以存储结果图像,因此设为I.rows, I.cols

参数int type:设置矩阵内数据类型,虽说该参数为int类型,但是为了直观,通常不用单一的数字表示。如文中需要创建数据为3通道float类型,所以参数设为CV_32FC3

1中参数const Scalar& s:设置矩阵每个数据的初始值。实际上,构造函数1通常用在空白图像的初始化,可将图像设为全白Scalar(1.0f,1.0f,1.0f)或全黑Scalar(0.0f,0.0f,0.0f),当然也可将图像设为其他颜色。三通道时该参数用Scalar(x,x,x)表示,四通道用Scalar(x,x,x,x)表示,单通道直接用数字表示即可

2中参数void* data:设置矩阵内数据,将data数组中的数据作为矩阵元素的值。由于矩阵的长宽通过构造函数设定,数组的长度也是认为设定的,因此只要矩阵尺寸和数组长度相对应即可成功构造矩阵。文中该参数为进行遍历运算之后的像素数组img_data

split多通道分离,merge多通道合并

除了对每个像素进行遍历操作外,OpenCV还提供了分通道对图像进行操作的方法:

	//划分BGR三通道
	vector<Mat> channels;
	split(I, channels);

	//分别处理三通道
	vector<Mat> newChannels;
	newChannels.push_back(1 - channels[0]);  //B通道
	newChannels.push_back(1 - channels[1]);  //G通道
	newChannels.push_back(1 - channels[2]);  //R通道

	//融合BGR三通道
	Mat result2;
	merge(newChannels, result2);
	//显示结果
	imshow("result2", result2);
  • 函数void split(const Mat& m, vector<Mat>& mv )`
    该函数作用是将多通道矩阵m中的每个通道单独提取,分别存入mv中
    参数const Mat& m:多通道Mat型矩阵。文中要将彩色BGR三通道图像I分离通道,因此参数设为I
    参数vector<Mat>& mv: vector <Mat>结构,用来存储分离后的单通道矩阵。文中将彩色图像矩阵I拆分为三个单通道矩阵,这三个矩阵存于未初始化的vector channels中
    注意:参数vector& mv不必初始化,参数const Mat& m有几个通道,mv就有几个,可用[n]来获取某通道的矩阵。如文中Mat I为三通道彩色图像,所以vector channels中共有3个Mat型,其中channels[0]代表I的B通道(蓝色),channels[1]代表I的G通道(绿色),channels[2]代表I的R通道(红色)

  • 函数void merge(const vector<Mat>& mv, OutputArray dst )
    该函数作用和split相反,是将若干个单通道Mat型合成一个多通道矩阵
    参数const vector<Mat>& mv:vector<Mat>型若干个单通道Mat组成的vector。文中将分离的vector channels每个通道进行取反计算,因此该参数设为处理后的channels
    参数OutputArray dst:输出矩阵,OutputArray类型可以用Mat类型表示。文中将分别处理之后的三通道合并回三通道BGR彩色图像,因此该参数设为未初始化的Mat result2以存储结果。
    程序运行结果和之前的一样:
    在这里插入图片描述
    针对该问题,还有一种更为简单的处理方法,直接应用矩阵运算:

	Mat result3 = Scalar(1,1,1) - I;
	imshow("result3", result3);

最终结果和前两种方法相同,并且花费时间最短。第一种方法时间花费在遍历全图像素点;第二种方法时间花费在split和merge两个函数上
完整代码:

#include<iostream>
#include<opencv2\opencv.hpp> 
using namespace cv;
using namespace std;


	void main()
	{
		//设置图片路径
		string path = "./yy.jpg";
		//生成Mat型图像矩阵
		Mat I = imread(path);
		//转化Mat内部数据类型
		I.convertTo(I, CV_32FC3, 1 / 255.0);

		//构建像素值数组
		float* img_data = new float[I.cols * I.rows * 3];
		//像素值拷贝
		memcpy(img_data, I.data, I.cols * I.rows * 3 * sizeof(float));
		//遍历像素并计算
		for (int i = 0; i < I.cols * I.rows * 3; i++)
		{
			img_data[i] = 1 - img_data[i];
		}
		//通过像素数组重新生成图像
		Mat result1(I.rows, I.cols, CV_32FC3, img_data);
		//显示结果
		imshow("result1", result1);

		//划分BGR三通道
		vector<Mat> channels;
		split(I, channels);

		//分别处理三通道
		channels[0] = 1 - channels[0];
		channels[1] = 1 - channels[1];
		channels[2] = 1 - channels[2];

		//融合BGR三通道
		Mat result2;
		merge(channels, result2);
		//显示结果
		imshow("result2", result2);

		Mat result3 = Scalar(1, 1, 1) - I;
		imshow("result3", result3);

		//图像显示
		imshow("ori", I);
		//程序挂起等待
		waitKey();
	
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值