还是以前学习图像处理的时候写的函数呀!
编程环境:windows下结合opencv库。
//傅里叶频谱的中心转换
//void ShiftDFT(IplImage* src, IplImage* dst);
void ShiftDFT(CvArr* src, CvArr* dst);
//傅里叶变换的频谱图
void DFTP(IplImage* src, IplImage* dst);
//傅里叶频谱的中心转换
/*
原理解释:利用频谱图像的对称性
源频谱左上角部分->目标频谱右下角部分
源频谱左下角部分->目标频谱右上角部分
源频谱右上角部分->目标频谱左下角部分
源频谱右下角部分->目标频谱左上角部分
利用上述转换生成目标中心对称频谱
*/
void ShiftDFT(CvArr* src, CvArr* dst)
{
if (!src || !dst)
{
return;
}
int nWidth;
int nHeight;
CvMat tmp1;
CvMat tmp2;
//src可能会出现指向CvMat与IplImage两种不同类型的指针,故进行判断后分别执行不同的程序
if (CV_IS_MAT_HDR(src))//src指向CvMat类型指针
{
CvMat* pMatSrc = (CvMat*)src;
nWidth = pMatSrc->width;
nHeight = pMatSrc->height;
//可能会出现src与dst相同的情况,这里保存src以便复制时出现问题
CvMat* pMatSrcTmp = cvCreateMat(nHeight, nWidth, pMatSrc->type);
cvCopy(src, pMatSrcTmp);
//右下角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, 0, nWidth / 2, nHeight / 2));//源图像左上角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));////目标图像右下角
cvCopy(&tmp1, &tmp2);//目标图像右下角设定
//右上角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//源图像左下角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//目标图像右上角
cvCopy(&tmp1, &tmp2);//目标图像右上角设定
//左上角部分装换
cvGetSubRect(pMatSrcTmp, &tmp1, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));//源图像右下角
cvGetSubRect(dst, &tmp2, cvRect(0, 0, nWidth / 2, nHeight / 2));//目标图像左上角
cvCopy(&tmp1, &tmp2);//目标图像左上角设定
//左下角部分装换
cvGetSubRect(pMatSrcTmp, &tmp1, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//源图像右上角
cvGetSubRect(dst, &tmp2, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//目标图像左下角
cvCopy(&tmp1, &tmp2);//目标图像左下角设定
cvReleaseMat(&pMatSrcTmp);
}
else if (CV_IS_IMAGE_HDR(src))//src指向IplImage类型指针
{
IplImage* pImgSrc = (IplImage*)src;
nWidth = pImgSrc->width;
nHeight = pImgSrc->height;
//可能会出现src与dst相同的情况,这里保存src以便复制时出现问题
IplImage* pImgSrcTmp = cvCreateImage(cvGetSize(src), pImgSrc->depth, pImgSrc->nChannels);
cvCopy(src, pImgSrcTmp);
//右下角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, 0, nWidth / 2, nHeight / 2));//源图像左上角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));////目标图像右下角
cvCopy(&tmp1, &tmp2);//目标图像右下角设定
//右上角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//源图像左下角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//目标图像右上角
cvCopy(&tmp1, &tmp2);//目标图像右上角设定
//左上角部分装换
cvGetSubRect(pImgSrcTmp, &tmp1, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));//源图像右下角
cvGetSubRect(dst, &tmp2, cvRect(0, 0, nWidth / 2, nHeight / 2));//目标图像左上角
cvCopy(&tmp1, &tmp2);//目标图像左上角设定
//左下角部分装换
cvGetSubRect(pImgSrcTmp, &tmp1, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//源图像右上角
cvGetSubRect(dst, &tmp2, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//目标图像左下角
cvCopy(&tmp1, &tmp2);//目标图像左下角设定
cvReleaseImage(&pImgSrcTmp);
}
}
/*
void ShiftDFT(IplImage* src, IplImage* dst)
{
//可能会出现src与dst相同的情况,这里保存src以便复制时出现问题
IplImage* pImgSrcTmp = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
int nWidth = src->width;
int nHeight = src->height;
CvMat tmp1;
CvMat tmp2;
cvCopy(src, pImgSrcTmp);
//右下角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, 0, nWidth / 2, nHeight / 2));//源图像左上角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));////目标图像右下角
cvCopy(&tmp1, &tmp2);//目标图像右下角设定
//右上角部分装换
cvGetSubRect(src, &tmp1, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//源图像左下角
cvGetSubRect(dst, &tmp2, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//目标图像右上角
cvCopy(&tmp1, &tmp2);//目标图像右上角设定
//左上角部分装换
cvGetSubRect(pImgSrcTmp, &tmp1, cvRect(nWidth / 2, nHeight / 2, nWidth / 2, nHeight / 2));//源图像右下角
cvGetSubRect(dst, &tmp2, cvRect(0, 0, nWidth / 2, nHeight / 2));//目标图像左上角
cvCopy(&tmp1, &tmp2);//目标图像左上角设定
//左下角部分装换
cvGetSubRect(pImgSrcTmp, &tmp1, cvRect(nWidth / 2, 0, nWidth / 2, nHeight / 2));//源图像右上角
cvGetSubRect(dst, &tmp2, cvRect(0, nHeight / 2, nWidth / 2, nHeight / 2));//目标图像左下角
cvCopy(&tmp1, &tmp2);//目标图像左下角设定
cvReleaseImage(&pImgSrcTmp);
}
*/
//傅里叶变换的频谱图
//频谱图像dst类型为IPL_DEPTH_64F,通道为1,大小与src相同
//dst为频谱图
void DFTP(IplImage* pImgSrc, IplImage* pImgDst)
{
if (!pImgSrc || !pImgDst)
{
return;
}
if (pImgSrc->nChannels == 3)//讲图像转换为灰度图像
{
cvCvtColor(pImgSrc, pImgSrc, CV_BGR2GRAY);
}
//傅里叶变换的最合适大小
int nDFTWidth = cvGetOptimalDFTSize(pImgSrc->width);
int nDFTHeight = cvGetOptimalDFTSize(pImgSrc->height);
CvMat* pMatReal = cvCreateMat(nDFTHeight, nDFTWidth, CV_64FC1);//实部
CvMat* pMatImaginary = cvCreateMat(nDFTHeight, nDFTWidth, CV_64FC1);//虚部
CvMat* pMatDst = cvCreateMat(nDFTHeight, nDFTWidth, CV_64FC1);//结果频谱矩阵
CvMat* pMatDFT = cvCreateMat(nDFTHeight, nDFTWidth, CV_64FC2);//傅里叶变换的矩阵
CvMat tmp;//临时变量
//填充傅里叶变换矩阵
cvZero(pMatReal);
cvGetSubRect(pMatReal, &tmp, cvRect(0, 0, pImgSrc->width, pImgSrc->height));
cvScale(pImgSrc, &tmp, 1.0, 0);//将源图像缩放到实部
cvZero(pMatImaginary);//虚部设置为0
cvMerge(pMatReal, pMatImaginary, NULL, NULL, pMatDFT);//复数通道融合
//傅里叶变换
cvDFT(pMatDFT, pMatDFT, CV_DXT_FORWARD, pImgSrc->height);
//傅里叶变换结果实部,虚部分离
cvSplit(pMatDFT, pMatReal, pMatImaginary, NULL, NULL);
//计算傅里叶频谱 dst = sqrt(real^2 + imaginary^2);
cvPow(pMatReal, pMatReal, 2.0);
cvPow(pMatImaginary, pMatImaginary, 2.0);
cvAdd(pMatReal, pMatImaginary, pMatDst);
cvPow(pMatDst, pMatDst, 0.5);
//频谱的对数变换(对比度拉伸) dst = log(1 + dst);
cvAddS(pMatDst, cvScalar(1.0), pMatDst);
cvLog(pMatDst, pMatDst);
//频谱缩放以便与显示
double min,max;
cvMinMaxLoc(pMatDst, &min, &max, NULL, NULL, NULL);
cvScale(pMatDst, pMatDst, 1.0/(max-min), 1.0*(-min)/(max-min));
//频谱的中心转换
ShiftDFT(pMatDst, pMatDst);
//剪切频谱结果为dst大小,从pMatDst中心剪切出pImgDst大小
cvGetSubRect(pMatDst, &tmp,
cvRect((nDFTWidth - pImgDst->width) / 2, (nDFTHeight - pImgDst->height) / 2
, pImgDst->width, pImgDst->height));
cvCopy(&tmp, pImgDst);
//释放资源
cvReleaseMat(&pMatReal);
cvReleaseMat(&pMatImaginary);
cvReleaseMat(&pMatDst);
cvReleaseMat(&pMatDFT);
}