影象處理 二維小波變換

蔣_X_X發表於2015-06-04

程式設計環境:windows下結合opencv庫

//二維影象小波變換
/*
nLayer:變換尺度
type:小波型別
*/
void ImageDWT(IplImage* src, IplImage* dst, int nLayer, char* type);

//通用的二維小波變換
/*
nLayer:小波變換的層數
type:選取的小波名稱
   可用為: "haar","db4","sym4"
使用Mallat演算法,並利用傅立葉變換來快速執行卷積運算
src與dst深度均為IPL_DEPTH_8U
*/
void ImageDWT(IplImage* src, IplImage* dst, int nLayer, char* type)
{
	if (!src || !dst)
	{
		return;
	}
	//判斷src與dst的長度寬度是否為2的倍數
	if (((dst->width >> nLayer) << nLayer != dst->width) 
		|| ((dst->height >> nLayer) << nLayer != dst->height)
		|| (src->nChannels != 1)
		|| (dst->nChannels != 1)
		|| (nLayer <= 0))
	{
		return;
	}

	CvMat* pMatData = NULL;//用於儲存計算過程中的向量
	CvMat* pMatCA = NULL;
	CvMat* pMatCD = NULL;
	CvMat* pMatDst = cvCreateMat(dst->height, dst->width, CV_64FC1);//結果矩陣
	CvMat tmp;
	int nWidth = dst->width;
	int nHeight = dst->height;
	int nHalfW = nWidth / 2;
	int nHalfH = nHeight / 2;
	int i, x, y;
	double* *pfDst = (double**)(malloc(sizeof(double*) * pMatDst->height));//pMatDst資料的起始地址
	double* pfCA;//CA資料起始地址
	double* pfCD;//CD資料起始地址
	double* pfData;//Data資料起始地址

	//儲存影象資料每行的起始地址
	for (y = 0; y < nHeight; y++)
	{
		pfDst[y] = (double*)(pMatDst->data.ptr + y * pMatDst->step);
	}

	//預先填充pMatDst
	cvZero(pMatDst);
	cvGetSubRect(pMatDst, &tmp, cvRect(0, 0, src->width, src->height));
	cvScale(src, &tmp);

	while (nLayer > 0)
	{
		//行變換
		pMatData = cvCreateMat(1, nWidth, CV_64FC1);
		pMatCA =  cvCreateMat(1, nHalfW, CV_64FC1);
		pMatCD =  cvCreateMat(1, nHalfW, CV_64FC1);
		y = 0;
		for (y = 0; y < nHeight; y++)
		{
			pfCA = (double*)(pMatCA->data.ptr);
			pfCD = (double*)(pMatCD->data.ptr);
			pfData = (double*)(pMatData->data.ptr);
			//獲取每一行資料
			for (i = 0; i < nWidth; i++)
			{
				pfData[i] = pfDst[y][i];
			}
			cvDWT(pMatData, pMatCA, pMatCD, type);//對每一行資料進行一維快速小波變換
			//將小波變換結果拼接到一起並設定到pMatDst中
			for (i = 0; i < nWidth; i++)
			{
				if (i < nHalfW)
				{
					pfDst[y][i] = pfCA[i];
				}
				else
				{
					pfDst[y][i] = pfCD[i - nHalfW];
				}
			}
		}
		cvReleaseMat(&pMatData);
		cvReleaseMat(&pMatCA);
		cvReleaseMat(&pMatCD);
		
		//列變換
		pMatData = cvCreateMat(1, nHeight, CV_64FC1);
		pMatCA =  cvCreateMat(1, nHalfH, CV_64FC1);
		pMatCD =  cvCreateMat(1, nHalfH, CV_64FC1);
		y = 0;
		for (x = 0; x < nWidth; x++)
		{
			pfCA = (double*)(pMatCA->data.ptr);
			pfCD = (double*)(pMatCD->data.ptr);
			pfData = (double*)(pMatData->data.ptr);
			//獲取每一列資料
			for (i = 0; i < nHeight; i++)
			{
				pfData[i] = pfDst[i][x];
			}
			cvDWT(pMatData, pMatCA, pMatCD, type);//對每一列資料進行一維快速小波變換
			//將小波變換結果拼接到一起並設定到dst中
			for (i = 0; i < nHeight; i++)
			{
				if (i < nHalfH)
				{
					pfDst[i][x] = pfCA[i];
				}
				else
				{
					pfDst[i][x] = pfCD[i - nHalfH];
				}
			}
		}
		cvReleaseMat(&pMatData);
		cvReleaseMat(&pMatCA);
		cvReleaseMat(&pMatCD);
		
		//一層變換後的寬度長度縮小
		nWidth = nHalfW;
		nHeight = nHalfH;
		nHalfW = nHalfW / 2;
		nHalfH = nHalfH / 2;
		nLayer--;
	}
	//縮放以便顯示
    cvScale(pMatDst, dst);
}


相關文章