图像傅立叶变换以及中心转换函数

还是以前学习图像处理的时候写的函数呀!

编程环境: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);
	
}


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