《Open CV3编程入门》学习笔记3

6访问像素的三种方法以及运行时间计算

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//函数说明
void colorReduce(Mat& inputImage,Mat&outputImage,int div);

int main()
{
	Mat srcImage=imread("1.jpg");
	imshow("原始图像",srcImage);
	Mat dstImage;
	dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());//按原始图的参数规格来创建效果图
	double time0=static_cast<double>(getTickCount());//getTickCount()函数返回CPU自某个事件(如启动电脑)以来走过的时钟周期数;getTickFrequency()函数返回CPU一秒钟所走过的时钟周期数,两者结合起来就能以秒为单位对某运算计时
	colorReduce(srcImage,dstImage,32);
	time0=((double)getTickCount()-time0)/getTickFrequency();
	cout<<"此方法运行时间为: "<<time0<<"秒"<<endl;
	imshow("效果图",dstImage);
	waitKey(0);
}
//方法一:用指针访问像素,速度最快;公有成员变量cols和rows给出了图像的宽和高,而成员函数channels()返回图像的通道数。灰度图像的通道数为1,彩色图的通道数为3.
void colorReduce(Mat& inputImage,Mat& outputImage,int div)
{
	outputImage=inputImage.clone();//复制实参数到临时变量
	int rowNumber=outputImage.rows;//行数
	int colNumber=outputImage.cols*outputImage.channels();//列数乘以通道数等于每一行元素的个数
	//双重循环,遍历所有的像数值
	for(int i=0;i<rowNumber;i++)//行循环
	{
		uchar*data=outputImage.ptr<uchar>(i);//获取第i行的首地址
		for(int j=0;j<colNumber;j++)//列循环
		{
			data[j]=data[j]/div*div+div/2;//处理每个像素除法取整使颜色空间缩减等效于:*data++=*data/div*div+div/2;
		
		}
	}

}


//方法二:用迭代器操作像素,相比于用指针访问可能出现越界问题,迭代器绝对是非常安全的方法
/*void colorReduce(Mat& inputImage,Mat& outputImage,int div)
{
	outputImage=inputImage.clone();
	Mat_<Vec3b>::iterator it=outputImage.begin<Vec3b>();//初始位置的迭代器
	Mat_<Vec3b>::iterator itend=outputImage.end<Vec3b>();//终止位置的迭代器
	//存取彩色图像像素
	for(;it!=itend;++it)
	{
		(*it)[0]=(*it)[0]/div*div+div/2;
	    (*it)[1]=(*it)[1]/div*div+div/2;
		(*it)[2]=(*it)[2]/div*div+div/2;
	}

}
//方法三:动态地址计算;最直观,时间最长
void colorReduce(Mat& inputImage,Mat& outputImage,int div)
{
	outputImage=inputImage.clone();//复制实参数到临时变量
	int rowNumber=outputImage.rows;//行数
	int colNumber=outputImage.cols;//列数
	for(int i=0;i<rowNumber;i++)
	{
		for(int j=0;j<colNumber;j++)
		{
			outputImage.at<Vec3b>(i,j)[0]=
				outputImage.at<Vec3b>(i,j)[0]/div*div+div/2;//蓝色通道
			outputImage.at<Vec3b>(i,j)[1]=
				outputImage.at<Vec3b>(i,j)[1]/div*div+div/2;//蓝色通道
			outputImage.at<Vec3b>(i,j)[2]=
				outputImage.at<Vec3b>(i,j)[2]/div*div+div/2;//红色通道
		//成员函数at(int y,int x)可以用来存取图像元素,但是必须在编译期知道图像的数据类型。需要注意的是,一定要确保指定的数据类型要和矩阵中的数据类型相符合,因为at方法本身不会对
		//任何数据类型进行转换;对于彩色图像,每个像数由BGR组成。因此,对于一个包含彩色图像的Mat,会返回一个由三个8位数组成的向量。OpenCV将此类型的向量定义为Vec3b,即由三个unsigned char
		//组成的向量,索引值channel标明了颜色通道号。
		
		}
	
	}

}
*/

7初级图像融合与图像区域选定

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;


bool  ROI_AddImage();
bool  LinearBlending();
bool  ROI_LinearBlending();
void   ShowHelpText();

//-----------------------------------【main( )函数】--------------------------------------------
//	描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main(   )
{
	system("color 6F");
 
	ShowHelpText();

	if(ROI_AddImage( )&& LinearBlending( )&&ROI_LinearBlending( ))
	{
		cout<<endl<<"\n运行成功,得出了需要的图像~! ";
	}

	waitKey(0);
	return 0;
}


//-----------------------------------【ShowHelpText( )函数】----------------------------------
//		 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
	//输出欢迎信息和OpenCV版本
	printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
	printf("\n\n\t\t\t此为本书OpenCV2版的第25个配套示例程序\n");
	printf("\n\n\t\t\t   当前使用的OpenCV版本为:" CV_VERSION );
	printf("\n\n  ----------------------------------------------------------------------------\n");
}




//----------------------------------【ROI_AddImage( )函数】----------------------------------
// 函数名:ROI_AddImage()
//	描述:利用感兴趣区域ROI实现图像叠加
//----------------------------------------------------------------------------------------------
bool  ROI_AddImage()
{

	// 【1】读入图像
	Mat srcImage1= imread("dota_pa.jpg");
	Mat logoImage= imread("dota_logo.jpg");
	if( !srcImage1.data ) { printf("读取srcImage1错误~! \n"); return false; }
	if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }

	// 【2】定义一个Mat类型并给其设定ROI区域
	//Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));//方法一
    Mat  imageROI=srcImage1(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));//方法二
	// 【3】加载掩模(必须是灰度图)
	Mat mask= imread("dota_logo.jpg",0);//0所以载入该图的灰度图

	//【4】将掩膜拷贝到ROI
	logoImage.copyTo(imageROI,mask);
	//函数srcImage.copyto(dstImage, mask),mask作为一个掩模板,如果
	//在某个像素点(i, j)其值不为0(即不是黑色)(只看第一通道,所以mask单通道即可)则把srcImage.at(i, j)处的值直接赋
	//给dstImage.at(i, j),如果其值为0(黑色)则dstImage.at(i, j)处保留其原始像素值。

	// 【5】显示结果
	namedWindow("<1>利用ROI实现图像叠加示例窗口");
	imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);

	return true;
}


//---------------------------------【LinearBlending()函数】-------------------------------------
// 函数名:LinearBlending()
// 描述:利用cv::addWeighted()函数实现图像线性混合
//--------------------------------------------------------------------------------------------
bool  LinearBlending()
{
	//【0】定义一些局部变量
	double alphaValue = 0.5; 
	double betaValue;
	Mat srcImage2, srcImage3, dstImage;

	// 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
	srcImage2 = imread("mogu.jpg");
	srcImage3 = imread("rain.jpg");

	if( !srcImage2.data ) { printf("读取srcImage2错误! \n"); return false; }
	if( !srcImage3.data ) { printf("读取srcImage3错误! \n"); return false; }

	// 【2】进行图像混合加权操作
	betaValue = ( 1.0 - alphaValue );
	addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
	//第一个参数:src1,表示需要加权的第一个数组,常常填一个Mat;第二个参数double类型alpha,表示第一个数组的权重;第三个参数表示第二个数组,它需要
	//和第一个数组拥有相同的尺寸和通道数;第四个参数double类型的beta,表示第二个数组的权重;第五个参数double类型的gamma,一个加到权重总和上的标量值;
	//第六个参数输出数组;第七个参数有默认值-1.即输出阵列的深度,默认下与输入相同dst=src[1]*alpha+src[2]*beta+gamma;
	//需要注意:当输出数组的深度为CV_32S时,这个函数就不适合了,这时候就会内存溢出或者结果不对

	// 【3】显示原图窗口
	imshow( "<2>线性混合示例窗口【原图】", srcImage2 );
	imshow( "<3>线性混合示例窗口【效果图】", dstImage );

	return true;

}

//---------------------------------【ROI_LinearBlending()】-------------------------------------
// 函数名:ROI_LinearBlending()
// 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
//			  感兴趣区域ROI,实现自定义区域的线性混合
//--------------------------------------------------------------------------------------------
bool  ROI_LinearBlending()
{

	//【1】读取图像
	Mat srcImage4= imread("dota_pa.jpg",1);
	Mat logoImage= imread("dota_logo.jpg");

	if( !srcImage4.data ) { printf("读取srcImage4错误~! \n"); return false; }
	if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }

	//【2】定义一个Mat类型并给其设定ROI区域
	Mat imageROI;
	//方法一
	imageROI= srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
	//方法二
	//imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

	//【3】将logo加到原图上
	addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);

	//【4】显示结果
	imshow("<4>区域线性图像混合示例窗口",srcImage4);

	return true;
}

8颜色通道分离和融合

                                                                               
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

//-----------------------------------【命名空间声明部分】---------------------------------------
//	描述:包含程序所使用的命名空间
//-------------------------------------------------------------------------------------------------   
using namespace cv;
using namespace std;


//-----------------------------------【全局函数声明部分】--------------------------------------
//	描述:全局函数声明
//-----------------------------------------------------------------------------------------------
bool  MultiChannelBlending();
void ShowHelpText();

int main(   )
{
	system("color 9F");

	ShowHelpText( );

	if(MultiChannelBlending( ))
	{
		cout<<endl<<"\n运行成功,得出了需要的图像~! ";
	}

	waitKey(0);
	return 0;
}



//-----------------------------------【ShowHelpText( )函数】----------------------------------
//		 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
	//输出欢迎信息和OpenCV版本
	printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
	printf("\n\n\t\t\t此为本书OpenCV2版的第26个配套示例程序\n");
	printf("\n\n\t\t\t   当前使用的OpenCV版本为:" CV_VERSION );
	printf("\n\n  ----------------------------------------------------------------------------\n");
}

bool  MultiChannelBlending()
{
	//【0】定义相关变量
	Mat srcImage;
	Mat logoImage;
	vector<Mat> channels;
	Mat  imageBlueChannel;

	//=================【蓝色通道部分】=================
	//	描述:多通道混合-蓝色分量部分
	//============================================

	// 【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,注意是引用,相当于两者等价,修改其中一个另一个跟着变
	imageBlueChannel= channels.at(0);
	//【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
	addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
		logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

	//【5】将三个单通道重新合并成一个三通道
	merge(channels,srcImage);

	//【6】显示效果图
	namedWindow(" <1>游戏原画+logo蓝色通道");
	imshow(" <1>游戏原画+logo蓝色通道",srcImage);


	//=================【绿色通道部分】=================
	//	描述:多通道混合-绿色分量部分
	//============================================

	//【0】定义相关变量
	Mat  imageGreenChannel;

	//【1】重新读入图片,重新更新图片,因为该图片已经被修改了
	logoImage= imread("dota_logo.jpg",0);
	srcImage= imread("dota_jugg.jpg");

	if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }
	if( !srcImage.data ) { printf("读取srcImage错误~! \n"); return false; }

	//【2】将一个三通道图像转换成三个单通道图像
	split(srcImage,channels);//分离色彩通道
	/*第一个参数为多通道数组InputArray类型的m或const Mat&类型的src;第二个参数输出数组或vector容器,下一语句为具体引用,B,G,R:0,1,2*/

	//【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
	imageGreenChannel= channels.at(1);
	//【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
	addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
		logoImage,0.5,0.,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

	//【5】将三个独立的单通道重新合并成一个三通道
	merge(channels,srcImage);
	//第一个参数,mv。填需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度;
	//另一基本原型:第二个参数,count。当mv为一个空白的C数组时,代表输入矩阵的个数,这个参数显然必须大于1
	//第三个参数:dst。即输出矩阵,和mv【0】拥有一样的尺寸和深度,并且通道数的数量是矩阵阵列中的通道数的总数
	//【6】显示效果图
	namedWindow("<2>游戏原画+logo绿色通道");
	imshow("<2>游戏原画+logo绿色通道",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】将一个三通道图像转换成三个单通道图像
	split(srcImage,channels);//分离色彩通道

	//【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
	imageRedChannel= channels.at(2);
	//【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
	addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
		logoImage,0.5,0.,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

	//【5】将三个独立的单通道重新合并成一个三通道
	merge(channels,srcImage);

	//【6】显示效果图
	namedWindow("<3>游戏原画+logo红色通道 ");
	imshow("<3>游戏原画+logo红色通道 ",srcImage);

	return true;
}
/*复杂的通道组合,可以使用mixChannels()函数:函数功能:
mixChannels主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中,其中的对应关系就由fromTo参数指定.
参数说明:
src– Input array or vector of matrices. All the matrices must have the same size and the same depth.
输入矩阵,可以为一个也可以为多个,但是矩阵必须有相同的大小和深度.
nsrcs– Number of matrices in src.
输入矩阵的个数。
dst– Output array or vector of matrices. All the matrices must be allocated. Their size and depth must be the same as in src[0].
输出矩阵,可以为一个也可以为多个,但是所有的矩阵必须事先分配空间(如用create),大小和深度须与输入矩阵等同.
ndsts– Number of matrices in dst.
输出矩阵的个数。
fromTo – Array of index pairs specifying which channels are copied and where. fromTo[k*2] is a 0-based index of the input channel in src. fromTo[k*2+1] is an index of the outputchannel in dst. The continuous channel numbering is used: the first input image channels are indexed from 0 to src[0].channels()-1 , the second input image channels areindexed from src[0].channels() to src[0].channels() + src[1].channels()-1, and so on. The same scheme is used for the output image channels. As a special case, whenfromTo[k*2] is negative, the corresponding output channel is filled with zero .
设置输入矩阵的通道对应输出矩阵的通道,规则如下:首先用数字标记输入矩阵的各个通道。输入矩阵个数可能多于一个并且每个矩阵的通道可能不一样,第一个输入矩阵的通道标记范围为: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– Number of index pairs in fromTo.
即参数fromTo中的有几组输入输出通道关系,其实就是参数fromTo的数组元素个数除以2.
示例代码:
Mat rgba(3,4,CV_8UC4,Scalar(1,2,3,4));//1,2,3,4为自己赋值,不代表通道数值
Mat bgr(rgba.rows,rgba.cols,CV_8UC3);
Mat alpha(rgba.rows,rgba.cols,CV_8UC1);
Mat out[]={bgr,alpha};
//rgba[0]->bgr[2],rgba[1]->bgr[1],rgba[2]->bgr[0],rgba[3]->alpha[0]
int from_to[]={0,2,1,1,2,0,3,3};
mixChannels(&rgba,1,out,2,from_to,4);
*/





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值