1. 程式人生 > >特徵變換(2)沃爾什-哈達瑪變換

特徵變換(2)沃爾什-哈達瑪變換

筆記->印象筆記(沃爾什變換篇)

MATLAB 原始碼:

clear all;
I=zeros(2.^8);
I(2.^7-2.^4+1:2.^7+2.^4,2.^7-2.^4+1:2.^7+2.^4)=ones(2*2.^4);  %讀入資料
subplot(1,2,1);
colormap(gray(128));imagesc(I);
title('顯示原始影象');
[m,n]=size(I);
for k=1:n
    wht(:,k)=hadamard(m)*I(:,k)/m;  %對每一列作walah-Hadamard變換
end
for j=1:m
%對進行列的walah-Hadamard變換後的係數進行walah-Hadamard變換
    wh(:,j)=hadamard(n)*wht(j,:)'/n;
end
wh=wh';
subplot(1,2,2);colormap(gray(128));imagesc(wh);
title('walah-Hadamard變換系數');


C++原始碼:
/*************************************************************************
 *
 * 函式名稱:
 *   WALSH()
 *
 * 引數:
 *   double * dpf				- 指向時域值的指標
 *   double * dpF				- 指向頻域值的指標
 *   r						-2的冪數
 *
 * 返回值:
 *   無。
 *
 * 說明:
 *   該函式用來實現一維快速沃爾什-哈達瑪變換。
 *
 ***********************************************************************
*/

VOID WINAPI WALSH(double *dpf, double *dpF, int r)
{
	// 沃爾什-哈達瑪變換點數
	LONG	lNum;
	
	// 快速沃爾什變換點數
	lNum = 1 << r;

	// 迴圈變數
	int		i,j,k;
	
	// 中間變數
	int		nTemp,m;
	
	double *X1,*X2,*X;
			
	// 分配運算所需的陣列
	X1 = new double[lNum];
	X2 = new double[lNum];
	
	// 將時域點寫入陣列X1
	memcpy(X1, dpf, sizeof(double) * lNum);
		
	for(k = 0; k < r; k++)
	{
		for(j = 0; j < 1<<k; j++)
		{	
			// 按照蝶形運算圖進行運算
			nTemp = 1 << (r-k);
			for(i = 0; i < nTemp / 2; i++)
			{
				m = j * nTemp;
				X2[i + m] = X1[i + m] + X1[i + m + nTemp / 2];
				X2[i + m + nTemp / 2] = X1[i + m] - X1[i + m + nTemp / 2];
			}
		}
		
		// 互換  
		X = X2;
		X2 = X1;
		X1 = X;
	}
	
	// 對係數做調整
	for(j = 0; j < lNum; j++)
	{
		m = 0;
		for(i = 0; i < r; i++)
		{
			if (j & (1<<i))
			{
				m += 1 << (r-i-1);
			}
		}

		dpF[j] = X1[m] / lNum;
	}
	
	// 釋放記憶體
	delete X1;
	delete X2;
}

/*************************************************************************
 *
 * 函式名稱:
 *   IWALSH()
 *
 * 引數:
 *   double * dpF				- 指向頻域值的指標
 *   double * dpf				- 指向時域值的指標
 *   n						-2的冪數
 *
 * 返回值:
 *   無。
 *
 * 說明:
 *   該函式用來實現一維快速沃爾什-哈達瑪反變換。
 *
 ***********************************************************************
 */

VOID WINAPI IWALSH(double *dpF, double *dpf, int n)
{
	// 變換點數
	LONG	lNum;
	
	// 迴圈變數
	int		i;
	
	// 計算變換點數
	lNum = 1 << n;
	
	// 用快速沃爾什-哈達瑪變換進行反變換
	WALSH(dpF, dpf, n);
	
	// 對係數進行調整
	for(i = 0; i < lNum; i++)
	{
		dpf[i] *= lNum;
	}
}

/*************************************************************************
 *
 * 函式名稱:
 *   DIBWalsh()
 *
 * 引數:
 *   CDib  *pDib       - 指向CDib類的指標
 *
 * 返回值:
 *   BOOL               - 成功返回TRUE,否則返回FALSE。
 *
 * 說明:
 *   該函式用來對影象進行二維快速沃爾什-哈達瑪變換。
 *
 ***********************************************************************
 */

BOOL WINAPI DIBWalsh(CDib * pDib)
{
	// 指向源影象的指標
	unsigned char *lpSrc;		
	
	//圖象的寬度和高度
	LONG    lWidth;
	LONG    lHeight;

	// 迴圈變數
	LONG	i;
	LONG	j;
	
	// 實際進行付立葉變換的寬度和高度
	LONG	lW = 1;
	LONG	lH = 1;
	
	int		wp = 0;
	int		hp = 0;
	
	// 中間變數
	double	dTemp;	

	//得到圖象的寬度和高度
	CSize   SizeDim;
	SizeDim = pDib->GetDimensions();
	lWidth = SizeDim.cx;
	lHeight = SizeDim.cy;	
	
	//得到實際的圖象儲存大小
	CSize   SizeRealDim;
	SizeRealDim = pDib->GetDibSaveDim();

	// 影象每行的位元組數
	LONG	lLineBytes;
	
	// 計算影象每行的位元組數
	lLineBytes = SizeRealDim.cx;

	//影象資料的指標
	LPBYTE  lpDIBBits = pDib->m_lpImage;
		
	// 保證離散餘弦變換的寬度和高度為2的整數次方
	while(lW * 2 <= lWidth)
	{
		lW = lW * 2;
		wp++;
	}
	
	while(lH * 2 <= lHeight)
	{
		lH = lH * 2;
		hp++;
	}
	
	// 分配記憶體
	double *dpf = new double[lW * lH];
	double *dpF = new double[lW * lH];
	
	// 時域賦值
	for(i = 0; i < lH; i++)
	{
		// 列
		for(j = 0; j < lW; j++)
		{
			// 指向DIBi行j列象素的指標
			lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 將象素值賦值給時域陣列
			dpf[j + i * lW] = *(lpSrc);
		}
	}
	
	for(i = 0; i < lH; i++)
		// 對y方向進行沃爾什-哈達瑪變換
		WALSH(dpf + lW * i, dpF + lW * i, wp);
		
	// 儲存計算結果
	for(i = 0; i < lH; i++)
	{
		for(j = 0; j < lW; j++)
		{
			dpf[j * lH + i] = dpF[j + lW * i];
		}
	}
	
	for(j = 0; j < lW; j++)
		// 對x方向進行沃爾什-哈達瑪變換
		WALSH(dpf + j * lH, dpF + j * lH, hp);
	
	// 行
	for(i = 0; i < lH; i++)
	{
		// 列
		for(j = 0; j < lW; j++)
		{
			// 計算頻譜
			dTemp = fabs(dpF[j * lH + i] * 1000);
			
			if (dTemp > 255)
			{
				// 超過255直接設定為255
				dTemp = 255;
			}
			
			// 指向DIBi行j列象素的指標
			lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
			
			// 更新源影象
			* (lpSrc) = (BYTE)(dTemp);
		}
	}
	
	//釋放記憶體
	delete dpf;
	delete dpF;

	// 返回
	return TRUE;
}