OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)

颜色空间缩减算法:

第1步遍历图像矩阵的每一个像素;

第2步对像素应用公式:

int divideWith=10;
uchar table[256];
for (int i=0;i<256;i++)
    table[i]=divideWith*(i/divideWith);

LUT函数:

Look up table操作------批量进行图像元素查找、扫描与操作图像。

Mat lookUpTable(1,256,CV_8U);//Mat型用于查表
uchar* p = lookUpTable.data;
for(int i=0;i<256;i++)
    p[i]=table[i];
for(itn i=0;i

计时函数:getTickCount()和getTickFrequency()函数

                getTickCount()函数---------返回CPU自某个事件以来走过的时针周期数。

                getTickFrequency()函数--------返回CPU一秒所走的时针周期数。

double time0=static_cast(getTickCount());//记录起始时间
time0=((double)getTickCount()-time0)/getTickFrequency();
count<<"此方法运行时间为:"<

ROI区域图像叠加&图像混合

先指定ROI再用addWeighted函数对指定的ROI区域的图像进行混合操作。

定义ROI区域有两种方法:①使用表示矩形区域的Rect:指定矩形的左上角坐标和矩形长宽(4个参数)

Mat imageRoI;
imageROI=image(Rect(500,250,logo.cols,logo.rows));

②指定感兴趣行或列的范围Range-----从开始索引到终止索引的一段连续序列。

imageROI=image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

计算数组加权和:addWeighted()函数

计算两个数组的加权和(图像阵列)

void (InputArray src1,double alpha,InputArray src2,double beta,double gamma,OutputArrat dat,int dtype=-1);

参数一:需要加权的第一个数组

参数二:表示第一个数组的权重

参数三:第二个数组,它需要与第一个数组拥有相同的尺寸和通道数。

参数四:表示第二个数组的权重

参数五:一个加到权重总和上的标量值

参数六:输出数组,与输入的两个数组拥有相同的尺寸和通道数

参数七:输出阵列的可选深度(默认-1---相同深度)

初级图像混合示例:

#include 
#include 
#include 

using namespace cv;
using namespace std;


//--------------【全局函数声明部分】------------
bool ROI_AddImage();
bool LinearBlending();
bool ROI_LinearBlending();


//--------------【ROI_AddImage()函数】---------------
//描述:利用感兴趣区域ROI实现图像叠加
//----------------------------------------------------
bool ROI_AddImage() {
	
	//【1】读入图像
	Mat srcImage1 = imread("k.jpg");
	Mat logoImage = imread("1.png");
	if (!srcImage1.data) { printf("读取srcImage1错误~!\n"); return false; }
	if (!logoImage.data) { printf("读取logoImage2错误~!\n"); return false; }
	
	//【2】定义一个Mat类型并给其设定ROI区域
	Mat imageROI = srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));

	//【3】加载掩模(必须是灰度图)
	Mat mask = imread("1.png",0);

	//【4】将掩模复制到ROI
	logoImage.copyTo(imageROI,mask);

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

	return true;

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

	//【1】读入图像(两幅图片需要同样的类型和尺寸)
	srcImage2 = imread("102.jpg");
	srcImage3 = imread("103.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);

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

	return true;
}
//--------------【ROI_LinearBlending()函数】---------------
//描述:线性混合实现函数,指定区域线性图像混合。利用cv::addWeighted()函数结合定义。
//感兴趣区域ROI实现自定义区域的线性混合
//----------------------------------------------------
bool ROI_LinearBlending() {
	//【1】读取图像
	Mat srcImage4 = imread("lenna.jpg",1);
	Mat logoImage = imread("1.png");
	if (!srcImage4.data) { printf("读取srcImage1错误~!\n"); return false; }
	if (!logoImage.data) { printf("读取logoImage2错误~!\n"); return false; }

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

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

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

	return true;
}
//---------------【main()函数】---------------------
//描述:控制台应用程序的入口函数,我们的程序从这里开始
//----------------------------------------------------
int main(){
	system("color 5E");
	if (ROI_AddImage()&&LinearBlending()&&ROI_LinearBlending()) {
		cout << endl << "运行成功,得出了你需要的图像~!:"  ;
	}
	waitKey(0);
	return 0;
}

运行结果:

OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第1张图片

 

图像对比度、亮度值调整

代码示例:

//--------------【图像对比度、亮度值调整】---------------
#include 
#include 
#include 
 
using namespace cv;
using namespace std;


//----------------【全局函数声明部分】------------

static void on_ContrastAndBright(int,void*);
static void ShowHelpText();


//------------【全局变量声明部分】-------------

int g_nContrastValue;//对比度值
int g_nBrightValue;//亮度值
Mat g_srcImage, g_dstImage;


//----------【on_ContrastAndBright()函数】----------
//描述:改变图像对比度和亮度值的回调函数
//--------------------------------------------------

static void on_ContrastAndBright(int,void*) {
	//创建窗口
	namedWindow("【原始窗口】",WINDOW_NORMAL);
	//三个for循环,执行运算g_dstImage(i,j)=a*g_srcImage(i,j)+b
	for (int y = 0; y < g_srcImage.rows; y++) {
		for (int x = 0; x < g_srcImage.cols;x++) {
			for (int c = 0; c < 3;c++) {
				g_dstImage.at(y, x)[c] = 
					saturate_cast((g_nContrastValue*0.01)*(g_srcImage.at
						(y,x)[c])+g_nBrightValue);
			}
		}
	}
	//显示图像
	imshow("【原始图窗口】",g_srcImage);
	imshow("【效果图窗口】",g_dstImage);
}
int main() {
	//【1】读取输入图像
	g_srcImage = imread("lenna.jpg");
	if (!g_srcImage.data) { 
		printf("读取图片错误,请确认目录下是否有imread函数指定图片的存在~!");
	    return false;
	}
	g_dstImage = Mat::zeros(g_srcImage.size(),g_srcImage.type());

	//【2】设定对比度和亮度的初值
	g_nContrastValue = 80;
	g_nBrightValue = 80;

	//【3】创建效果窗口
	namedWindow("【效果图窗口】",WINDOW_NORMAL);

	//【4】创建轨迹条
	createTrackbar("对比度:", "【效果图窗口】", &g_nContrastValue, 300, on_ContrastAndBright);
	createTrackbar("亮  度:", "【效果图窗口】", &g_nBrightValue, 200, on_ContrastAndBright);

	//【5】进行回调函数初始化
	on_ContrastAndBright(g_nContrastValue,0);
	on_ContrastAndBright(g_nBrightValue,0);

	//【6】按下“q”键时,程序退出
	while (char(waitKey(1)) != 'q') {}
	return 0;

}

运行结果如下:

OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第2张图片          OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第3张图片

分离颜色通道之多通道图像混合

①通道分离:split()函数-------将一个多通道数组分离成几个单通道数组。

函数原型:void split(const Mat& src,Mat*mvbegin);

                  void split(InputArray m,OutputArrayOfArrays mv);

                  参数一:我们需要进行分离的多通道数组

                  参数二:填函数的输出数组或者输出的vector容器。

②通道合作:merge()函数-------将多个数组合并成一个多通道的数组。

函数原型:void merge(const Mat* mv,size_tcount,OutputAray dst);

                  void merge(InputArrayOfArrays mv,OutputArray dst);

                  参数一:mv,填需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度。

                  参数二:代表输入矩阵的个数,必须大于1

                  参数三:输出矩阵,尺寸和深度同mv[0],并且通道的数量是矩阵阵列中的通道的总数。

代码示例:

//------------------------【分离颜色通道&多通道图像混合】-----------------
  
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;


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

//--------------------【main( )函数】----------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------

int main()
{
	system("color 5E");

	if (MultiChannelBlending())
	{
		cout << endl << "程序运行成功~!";
	}

	waitKey(0);
	return 0;
}

//-----------------------------【MultiChannelBlending( )函数】--------------------------------
//     描述:多通道混合的实现函数
//-----------------------------------------------------------------------------------------------
bool MultiChannelBlending()
{
	//【0】定义相关变量
	Mat srcImage;
	Mat logoImage;
	vectorchannels;
	Mat  imageBlueChannel;
	Mat  imageGreenChannel;
	Mat  imageRedChannel;

	//--------------------【蓝色通道部分】---------------------

	//【1】读入图片
	logoImage = imread("1.png",0);
	srcImage = imread("k.jpg");

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

	//【2】把一个3通道图像转换成3个单通道图像
	split(srcImage, channels);           //分离色彩通道

	//【3】将原图的蓝色通道引用返回给imageBlueChannel
	imageBlueChannel = channels.at(0);
	//【4】将原图的蓝色通道的(250,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
	addWeighted(imageBlueChannel(Rect(250, 250, logoImage.cols, logoImage.rows)), 1.0,
		logoImage, 0.5, 0, imageBlueChannel(Rect(250, 250, logoImage.cols, logoImage.rows)));

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

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

	//-----------------【绿色通道部分】-------------------

	//【1】重新读入图片
	logoImage = imread("1.png", 0);
	srcImage = imread("k.jpg");

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

	//【2】将一个三通道图像转换成三个单通道图像
	split(srcImage, channels);//分离色彩通道

	//【3】将原图的绿色通道的引用返回给imageBlueChannel
	imageGreenChannel = channels.at(1);
	//【4】将原图的绿色通道的(250,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
	addWeighted(imageGreenChannel(Rect(250, 250, logoImage.cols, logoImage.rows)), 1.0,
		logoImage, 0.5, 0., imageGreenChannel(Rect(250, 250, logoImage.cols, logoImage.rows)));

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

	//【6】显示效果图
	namedWindow("<2>原图logo绿色通道");
	imshow("<2>原图logo绿色通道", srcImage);

	//-----------------【红色通道部分】-----------------

	//【1】重新读入图片
	logoImage = imread("1.png", 0);
	srcImage = imread("k.jpg");

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

	//【2】将一个三通道图像转换成三个单通道图像
	split(srcImage, channels);//分离色彩通道

	//【3】将原图的红色通道引用返回给imageBlueChannel
	imageRedChannel = channels.at(2);
	//【4】将原图的红色通道的(250,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
	addWeighted(imageRedChannel(Rect(250, 250, logoImage.cols, logoImage.rows)), 1.0,
		logoImage, 0.5, 0., imageRedChannel(Rect(250, 250, logoImage.cols, logoImage.rows)));

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

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

	return true;
}

运行结果:

OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第4张图片     OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第5张图片    OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第6张图片

离散傅里叶变换(DFT)

          Discrete Fourier Transform是指傅里叶变换在时域和频域上都呈现离散的形式,将时域信号的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。
         傅里叶变换将图像从空间域转换到频域。频域中,对于一副图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。对一副精细的图像使用低通滤波结果就剩下轮廓了。(类信号处理)如果图像受到的噪声恰好位于某个特定的频率范围内,则可以通过滤波器来恢复原来的图像。傅里叶变换在图像处理中可以做到图像增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩。

①dft()函数----是对一维或二维浮点数数组进行正向或反向离散傅里叶变换


函数原型:void dft(InputArray src,OutputArray dst,int flags=0,int nonzeroRows=0);
                  参数一:输入矩阵(可实数可虚数)
                  参数二:函数调用后运算结果存储位置,其尺寸和类型取决于标识符
                  参数三:转换标识符(默认0).。。。。参照表
                 参数四:最好取值为想要处理的某一行的值(C.rows)

②getOptimalDFTSize()函数-----返回DFT最优尺寸大小


函数原型:int getOptimalDFTSize(int vecsize)参数:向量尺寸即图片的rows、cols。

③copyMakeBorder()函数----扩充图像边界


函数原型:void coptMakeBorder(InputArray src,OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar&value=Scalar());

            参数一:输入图像

           参数二:函数调用后的运算结果存储

           参数三-六:原图像4个方向扩充多少像素

           参数七:边界类型(常见:BORDER_CONSTANT)

          参数八:边界值

④magnitude()函数-----计算二维矢量的幅值

 

函数原型:void magnitude(InputArray x,InputArray y,OutputArray magnitude);

              参数一:表示矢量的浮点型X坐标值(实部)

             参数二:表示矢量的浮点型Y坐标值(虚部)

             参数三:输出幅值,与第一个参数x有相同的尺寸和类型

⑤log()函数----计算自然对数

 

函数原型:void log(InputArray src,OutputArray dst);

              参数一:输入图像

             参数二:得到的对数值

⑥mormalize()函数----矩阵归一化

 

函数原型:void normalize(InputArray src,OutputArray dst,double alpha=1,double beta=0,

int norm_type=NORM_L2,int dtype=-1,InputArray mask=noArray());

             参数一:输入图像

             参数二:运算结果

             参数三:归一化后的最大值(默认1)

             参数四:归一化的最小值(默认0)

             参数五:归一化类型(默认NORM_L2)

             参数六:(默认-1)取负值时输出矩阵和src有同样类型。否则与src有同样通道数,且此时图像深度为CV_MAT_DEPTH()dtype

            参数七:可选的操作掩模(默认noArray())

示例程序如下:

//-------------------【离散傅里叶变换--DFT】-------------------
//描述:Discrete Fourier Transform是指傅里叶变换在时域和频域上都呈现离散的形式,
//将时域信号的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。
//傅里叶变换将图像从空间域转换到频域。频域中,对于一副图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。
//对一副精细的图像使用低通滤波结果就剩下轮廓了。(类信号处理)如果图像受到的噪声恰好位于某个特定的频率范围内,则可以通过滤波器来恢复原来的图像
//傅里叶变换在图像处理中可以做到图像增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩。
//--------------------------------------------------------


#include 
#include
#include 
#include 

using namespace cv;

//--------------------【main()函数】-----------------
//描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------

int main() {

	//【1】以灰度模式读取原始图像并显示
	Mat srcImage = imread("lenna.jpg",0);
	if(!srcImage.data) { printf("读取srcImage错误~!\n"); return false; }
	imshow("原始图像",srcImage);
	//ShowHelpText();

	//【2】将输入图像延扩到最佳尺寸,边界用0补充
	int m = getOptimalDFTSize(srcImage.rows);
	int n = getOptimalDFTSize(srcImage.cols);

	//将添加的像素初始化为0
	Mat padded;
	copyMakeBorder(srcImage,padded,0,m-srcImage.rows,0,n-srcImage.cols,BORDER_CONSTANT,Scalar::all(0));

	//【3】为傅里叶变换的结果(实部和虚部)分配存储空间
	//将planes数组组合合并成一个多通道的数组complexI
	Mat planes[] = { Mat_(padded),Mat::zeros(padded.size(),CV_32F) };
	Mat complexI;
	merge(planes,2,complexI);

	//【4】进行就地离散傅里叶变换
	dft(complexI,complexI);

	//【5】将复数转换为幅值,即=>log(1+sqrt(Re(DFT(I))^2+Im(DFT(I))^2))
	split(complexI,planes);//将多通道数组copmplexI分离成几个单通道数组planes[0] = Re(DFT(I), planes[1] = Im(DFT(I));
	magnitude(planes[0], planes[1], planes[0]);//planes[0]=magnitude
	Mat magnitudeImage = planes[0];

	//【6】进行对数尺度(logarithmic scale)缩放
	magnitudeImage += Scalar::all(1);
	log(magnitudeImage,magnitudeImage);//求自然对数

	//【7】剪切和重分布幅度图像限,若有奇数行或奇数列,进行频谱剪裁
	magnitudeImage = magnitudeImage(Rect(0,0,magnitudeImage.cols&-2,
		magnitudeImage.rows&-2));
	//重新排列傅里叶图像中的象限,是的原点位于图像中心
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	Mat q0(magnitudeImage, Rect(0,0,cx,cy));     //ROI区域的左上
	Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));//ROI区域的右上
	Mat q2(magnitudeImage, Rect(0, cy, cx, cy));//ROI区域的左下
	Mat q3(magnitudeImage, Rect(cx,cy, cx, cy));//ROI区域的右下
	//交换象限(左上与右下进行交换)
	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	//交换象限(右上与左下进行交换)
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
	//normalize(magnitudeImage,magnitudeImage,0,1,CV_MINMAX);//opencv2版本
	normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);

	//【9】显示效果图
	imshow("频谱幅值",magnitudeImage);
	waitKey();
	return 0;
}

运行结果:

OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第7张图片                OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT)_第8张图片

你可能感兴趣的:(OpenCV3学习笔记(五)-----初级图像混合、图像对比度和亮度值调整、分离颜色通道之多通道图像混合、离散傅里叶变换(DFT))