第1步遍历图像矩阵的每一个像素;
第2步对像素应用公式:
int divideWith=10;
uchar table[256];
for (int i=0;i<256;i++)
table[i]=divideWith*(i/divideWith);
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()函数---------返回CPU自某个事件以来走过的时针周期数。
getTickFrequency()函数--------返回CPU一秒所走的时针周期数。
double time0=static_cast(getTickCount());//记录起始时间
time0=((double)getTickCount()-time0)/getTickFrequency();
count<<"此方法运行时间为:"<
先指定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));
计算两个数组的加权和(图像阵列)
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;
}
运行结果:
代码示例:
//--------------【图像对比度、亮度值调整】---------------
#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;
}
运行结果如下:
函数原型:void split(const Mat& src,Mat*mvbegin);
void split(InputArray m,OutputArrayOfArrays mv);
参数一:我们需要进行分离的多通道数组
参数二:填函数的输出数组或者输出的vector容器。
函数原型: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;
}
运行结果:
Discrete Fourier Transform是指傅里叶变换在时域和频域上都呈现离散的形式,将时域信号的采样变换为在离散时间傅里叶变换(DTFT)频域的采样。
傅里叶变换将图像从空间域转换到频域。频域中,对于一副图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。对一副精细的图像使用低通滤波结果就剩下轮廓了。(类信号处理)如果图像受到的噪声恰好位于某个特定的频率范围内,则可以通过滤波器来恢复原来的图像。傅里叶变换在图像处理中可以做到图像增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩。
函数原型:void dft(InputArray src,OutputArray dst,int flags=0,int nonzeroRows=0);
参数一:输入矩阵(可实数可虚数)
参数二:函数调用后运算结果存储位置,其尺寸和类型取决于标识符
参数三:转换标识符(默认0).。。。。参照表
参数四:最好取值为想要处理的某一行的值(C.rows)
函数原型:int getOptimalDFTSize(int vecsize)参数:向量尺寸即图片的rows、cols。
函数原型:void coptMakeBorder(InputArray src,OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar&value=Scalar());
参数一:输入图像
参数二:函数调用后的运算结果存储
参数三-六:原图像4个方向扩充多少像素
参数七:边界类型(常见:BORDER_CONSTANT)
参数八:边界值
函数原型:void magnitude(InputArray x,InputArray y,OutputArray magnitude);
参数一:表示矢量的浮点型X坐标值(实部)
参数二:表示矢量的浮点型Y坐标值(虚部)
参数三:输出幅值,与第一个参数x有相同的尺寸和类型
函数原型:void log(InputArray src,OutputArray dst);
参数一:输入图像
参数二:得到的对数值
函数原型: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;
}
运行结果: