理论公式
#include
#include
#include
using namespace std;
using namespace cv;
static void on_ConstrasAndBright(int, void *);
//---------------------------【全局变量声明部分】--------
// 描述:全局变量声明
//---------------------------------------------------
int g_nContrastValue; //对比度值
int g_nBrightValue; //亮度值
Mat g_srcImage, g_dstImage;
int main()
{
//读取输入图像
g_srcImage = imread("1.jpg");
if (!g_srcImage.data)
{
printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~!");
return false;
}
g_dstImage = Mat::zeros(g_srcImage.size(), g_srcImage.type());
//设定对比度和亮度的初值
g_nContrastValue = 80;
g_nBrightValue = 80;
//创建效果窗口
namedWindow("【效果图窗口】", 1);
//创建轨迹条
createTrackbar("对比度:", "【效果图窗口】", &g_nContrastValue, 300, on_ConstrasAndBright);
createTrackbar("亮 度:", "【效果图窗口】", &g_nBrightValue, 200, on_ConstrasAndBright);
// 进行回调函数初始化
on_ConstrasAndBright(g_nContrastValue, 0);
on_ConstrasAndBright(g_nBrightValue, 0);
//按下q,程序退出
while (char(waitKey(1)) != 'q') {}
return 0;
}
static void on_ConstrasAndBright(int, void *)
{
//创建窗口
namedWindow("【原始图窗口】", 1);
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);
}
离散傅里叶变换(Discrete Fourier Transform ,DFT)是指傅里叶变换在时域和频域上都呈现出离散的形式,将时域信息的采样变换为离散时间傅里叶变换频域采样
将图像从空间域转换到频域
理论基础:任一函数都可以表示为无数个正弦和余弦函数的和的形式
高频部分代表了图像的细节,纹理信息.低频部分代表图像的轮廓信息.
用途:图像的增强与图像去噪,图像分割之边缘检测,图像特征提取,图像压缩
void dft(InputArray src, OutputArray dst,int flags = 0,int nonzeroRows = 0)
返回给定向量尺寸的傅里叶最优尺寸大小
int getOptimalDFTSize(int vecsize)
void copyMakeBorder(InputArray src, OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar & value = Scalar())
void magnitude(InputArray x,InputArray y,OutputArray magnitude)
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())
//--------------------------【头文件、命名空间包含部分】-----------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//----------------------------【main函数】----------------------------
// 描述:程序入口
//------------------------------------------------------------------
int main()
{
Mat srcImage = imread("1.jpg", 0);
if (!srcImage.data)
{
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~!\n");
return false;
}
imshow("【原始图像】", srcImage);
// 将输入图像延扩到最佳的尺寸,边界用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));
// 为傅里叶变换的结果分配存储空间
// 将planes数组组合成一个多通道的数组complexI
Mat planes[] = { Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
//进行就地离散傅里叶变换
dft(complexI, complexI);
//将复数转化为幅值
split(complexI, planes);
magnitude(planes[0], planes[1], planes[0]);
Mat magnitudeImage = planes[0];
// 进行对数尺度(logarithmic scale)缩放
magnitudeImage += Scalar::all(1);
log(magnitudeImage, magnitudeImage); //求自然对数
// 剪切和重分布幅度图像象限
// 若有奇数行奇数列,进行频谱剪切
magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols&-1, 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 temp;
q0.copyTo(temp);
q3.copyTo(q0);
temp.copyTo(q3);
//交换象限 右上左下
q1.copyTo(temp);
q2.copyTo(q1);
temp.copyTo(q2);
//归一化,用0到1之间的浮点数将矩阵变换为可视的图像格式
normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);
//显示效果图
imshow("频谱幅值", magnitudeImage);
waitKey();
return 0;
}