圖像傅立葉變換以及中心轉換函數

還是以前學習圖像處理的時候寫的函數呀!

編程環境: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);
	
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章