還是以前學習圖像處理的時候寫的函數呀!
編程環境: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);
}