數字視頻處理(五)——頻率域陷波濾波

  1. 編程實現2-d DFT正變換和反變換
  2. 頻率域陷波濾波

在這裏插入圖片描述
在這裏插入圖片描述

實驗代碼

  解決方案資源管理器如下:
在這裏插入圖片描述

FFT.h

#pragma once
void compute_W(int n, double* W_re, double* W_im);
void permute_bitrev(int n, double* A_re, double* A_im);
int  bitrev(int inp, int numbits);
int  log_2(int n);
void fft_butterfly(int n, double* A_re, double* A_im, double* W_re, double* W_im);

void fft_1d(int N, double* A_re, double* A_im);
void Notch(unsigned char* IYmoon, double* IYNotch,int moonheight, int moonwidth);
void Notch_2(double* IYmoon, double* IYNotch, int moonheight, int moonwidth);
void Notch_2(double* NY, double* IYNotch, int moonheight, int moonwidth);
void Change_Y(double* IYNotch, double* FFT2D_IM, double* FFT2D_RE, int moonheight, int moonwidth, int FFTheight,int FFTwidth);
void FFT_Column(double* FFT2D_RE, double* FFT2D_IM, int FFTheight, int FFTwidth);
void FFT_Row(double* FFT2D_RE, double* FFT2D_IM, int FFTheight, int FFTwidth);
void CreateH(double* H, int FFTheight, int FFTwidth);
void Filter(double* FFT2D_IM, double* FFT2D_RE, double* H, int FFTheight, int FFTwidth);
void Conjugate(double* FFT2D_IM, int FFTsize);
void Delete_zero(double* FFT2D_RE, double* NY, int FFTheight, int FFTwidth, int moonheight, int moonwidth);

fft.cpp

#include <stdio.h> 
#include <stdlib.h>
#include <math.h>   
#include <assert.h>
#include <iostream>
#include <cstdio>
#include <fstream>
#include <cmath>
#include "FFT.h"


#define  M_PI 3.1415926

/*頻率陷波*/
void Notch(unsigned char* IYmoon, double* IYNotch, int moonheight, int moonwidth)
{
	for (int i = 0; i < moonheight; i++)
	{
		for (int j = 0; j < moonwidth; j++)
		{
			IYNotch[i * moonwidth + j] = pow(-1,i+j) * double(IYmoon[i * moonwidth + j]);
		}
	}
}
void Notch_2(double* NY, double* IYNotch, int moonheight, int moonwidth)
{
	for (int i = 0; i < moonheight; i++)
	{
		for (int j = 0; j < moonwidth; j++)
		{
			IYNotch[i * moonwidth + j] = pow(-1, i + j) * NY[i * moonwidth + j];
		}
	}
}
void Delete_zero(double* FFT2D_RE, double* NY, int FFTheight, int FFTwidth, int moonheight, int moonwidth)
{
	for (int i = 0; i < moonheight; i++)
	{
		for (int j = 0; j < moonwidth; j++)
		{
			NY[i * moonwidth + j] = FFT2D_RE[i * FFTwidth + j]/((double)FFTheight*FFTwidth);
		}
	}
}
void Change_Y(double* IYNotch, double* FFT2D_IM, double* FFT2D_RE, int moonheight, int moonwidth, int FFTheight, int FFTwidth)
{
	for (int i = 0; i < FFTheight; i++)
	{
		for (int j = 0; j < FFTwidth; j++)
		{
			if (i < moonheight && j < moonwidth)
			{
				FFT2D_RE[i * FFTwidth + j] = IYNotch[i * moonwidth + j];
			}
			else
				FFT2D_RE[i * FFTwidth + j] = 0;
		}
	}
}
void FFT_Column(double* FFT2D_RE, double* FFT2D_IM, int FFTheight, int FFTwidth)
{
	for (int i = 0; i < FFTwidth; i++)//對每列做FFT_1D變換
	{
		double* A_re = new double[sizeof(double) * FFTheight];
		double* A_im = new double[sizeof(double) * FFTheight];
		for (int k = 0; k < FFTheight; k++)
		{
			A_re[k] = FFT2D_RE[k * FFTwidth + i];
			A_im[k] = FFT2D_IM[k * FFTwidth + i];
		}
		fft_1d(FFTheight, A_re, A_im);
		for (int k = 0; k < FFTheight; k++)
		{
			FFT2D_RE[k * FFTwidth + i] = A_re[k];
			FFT2D_IM[k * FFTwidth + i] = A_im[k];
		}
		delete[]A_re;
		delete[]A_im;
	}
}

void FFT_Row(double* FFT2D_RE, double* FFT2D_IM, int FFTheight, int FFTwidth)
{
	for (int i = 0; i < FFTheight; i++)//對每行做FFT_1D變換
	{
		double* A_re = new double[sizeof(double) * FFTwidth];
		double* A_im = new double[sizeof(double) * FFTwidth];
		for (int k = 0; k < FFTwidth; k++)
		{
			A_re[k] = FFT2D_RE[i * FFTwidth + k];
			A_im[k] = FFT2D_IM[i * FFTwidth + k];
		}
		fft_1d(FFTwidth, A_re, A_im);
		for (int k = 0; k < FFTwidth; k++)
		{
			FFT2D_RE[i * FFTwidth + k] = A_re[k];
			FFT2D_IM[i * FFTwidth + k] = A_im[k];
		}
		delete[]A_re;
		delete[]A_im;
	}
}

void Filter(double* FFT2D_IM, double* FFT2D_RE, double* H, int FFTheight, int FFTwidth)
{
	for (int i = 0; i < FFTheight; i++)
	{
		for (int j = 0; j < FFTwidth; j++)
		{
			FFT2D_IM[i * FFTwidth + j] = FFT2D_IM[i * FFTwidth + j] * H[i * FFTwidth + j];
		}
	}
}

void CreateH(double* H, int FFTheight, int FFTwidth)
{
	for (int i = 0; i < FFTheight; i++)
	{
		for (int j = 0; j < FFTwidth; j++)
		{
			H[i * FFTwidth + j] = 1.5;
			if ((i == FFTheight / 2) && (j == FFTwidth / 2))
			{
				H[i * FFTwidth + j] = 0.5;
			}
		}
	}
}

void Conjugate(double* FFT2D_IM, int FFTsize)
{
	for (int i = 0; i < FFTsize; i++)
	{
		FFT2D_IM[i] = -FFT2D_IM[i];
	}
}
/*********************************************************************************************
對N點序列進行fft變換:
1. A_re爲該序列的實部,A_im爲該序列的虛部;
2. 運算結果仍然存放在A_re和A_im
3. 輸入輸出都是自然順序

Note:
N必須爲2的整數次冪
**********************************************************************************************/
void fft_1d(int N, double* A_re, double* A_im)
{
	double* W_re, * W_im;

	W_re = (double*)malloc(sizeof(double) * N / 2);
	W_im = (double*)malloc(sizeof(double) * N / 2);
	assert(W_re != NULL && W_im != NULL);

	compute_W(N, W_re, W_im);
	fft_butterfly(N, A_re, A_im, W_re, W_im);
	permute_bitrev(N, A_re, A_im);

	free(W_re);
	free(W_im);
}


/* W will contain roots of unity so that W[bitrev(i,log2n-1)] = e^(2*pi*i/n)
* n should be a power of 2
* Note: W is bit-reversal permuted because fft(..) goes faster if this is done.
*       see that function for more details on why we treat 'i' as a (log2n-1) bit number.
*/
void compute_W(int n, double* W_re, double* W_im)
{
	int i, br;
	int log2n = log_2(n);

	for (i = 0; i < (n / 2); i++)
	{
		br = bitrev(i, log2n - 1);
		W_re[br] = cos(((double)i * 2.0 * M_PI) / ((double)n));
		W_im[br] = -sin(((double)i * 2.0 * M_PI) / ((double)n));
	}

}


/* permutes the array using a bit-reversal permutation */
void permute_bitrev(int n, double* A_re, double* A_im)
{
	int i, bri, log2n;
	double t_re, t_im;

	log2n = log_2(n);

	for (i = 0; i < n; i++)
	{
		bri = bitrev(i, log2n);

		/* skip already swapped elements */
		if (bri <= i) continue;

		t_re = A_re[i];
		t_im = A_im[i];
		A_re[i] = A_re[bri];
		A_im[i] = A_im[bri];
		A_re[bri] = t_re;
		A_im[bri] = t_im;
	}
}


/* treats inp as a numbits number and bitreverses it.
* inp < 2^(numbits) for meaningful bit-reversal
*/
int bitrev(int inp, int numbits)
{
	int i, rev = 0;
	for (i = 0; i < numbits; i++)
	{
		rev = (rev << 1) | (inp & 1);
		inp >>= 1;
	}
	return rev;
}


/* returns log n (to the base 2), if n is positive and power of 2 */
int log_2(int n)
{
	int res;
	for (res = 0; n >= 2; res++)
		n = n >> 1;
	return res;
}

/* fft on a set of n points given by A_re and A_im. Bit-reversal permuted roots-of-unity lookup table
* is given by W_re and W_im. More specifically,  W is the array of first n/2 nth roots of unity stored
* in a permuted bitreversal order.
*
* FFT - Decimation In Time FFT with input array in correct order and output array in bit-reversed order.
*
* REQ: n should be a power of 2 to work.
*
* Note: - See www.cs.berkeley.edu/~randit for her thesis on VIRAM FFTs and other details about VHALF section of the algo
*         (thesis link - http://www.cs.berkeley.edu/~randit/papers/csd-00-1106.pdf)
*       - See the foll. CS267 website for details of the Decimation In Time FFT implemented here.
*         (www.cs.berkeley.edu/~demmel/cs267/lecture24/lecture24.html)
*       - Also, look "Cormen Leicester Rivest [CLR] - Introduction to Algorithms" book for another variant of Iterative-FFT
*/
void fft_butterfly(int n, double* A_re, double* A_im, double* W_re, double* W_im)
{
	double w_re, w_im, u_re, u_im, t_re, t_im;
	int m, g, b;
	int mt, k;

	/* for each stage */
	for (m = n; m >= 2; m = m >> 1)
	{
		/* m = n/2^s; mt = m/2; */
		mt = m >> 1;

		/* for each group of butterfly */
		for (g = 0, k = 0; g < n; g += m, k++)
		{
			/* each butterfly group uses only one root of unity. actually, it is the bitrev of this group's number k.
			* BUT 'bitrev' it as a log2n-1 bit number because we are using a lookup array of nth root of unity and
			* using cancellation lemma to scale nth root to n/2, n/4,... th root.
			*
			* It turns out like the foll.
			*   w.re = W[bitrev(k, log2n-1)].re;
			*   w.im = W[bitrev(k, log2n-1)].im;
			* Still, we just use k, because the lookup array itself is bit-reversal permuted.
			*/
			w_re = W_re[k];
			w_im = W_im[k];

			/* for each butterfly */
			for (b = g; b < (g + mt); b++)
			{
				/* t = w * A[b+mt] */
				t_re = w_re * A_re[b + mt] - w_im * A_im[b + mt];
				t_im = w_re * A_im[b + mt] + w_im * A_re[b + mt];

				/* u = A[b]; in[b] = u + t; in[b+mt] = u - t; */
				u_re = A_re[b];
				u_im = A_im[b];
				A_re[b] = u_re + t_re;
				A_im[b] = u_im + t_im;
				A_re[b + mt] = u_re - t_re;
				A_im[b + mt] = u_im - t_im;

			}
		}
	}
}

main.cpp

#include <iostream>
#include <cstdio>
#include <fstream>
#include "FFT.h"

using namespace std;
int main()
{
	int moonwidth = 464;
	int moonheight = 538;
	int FFTwidth = 512;
	int FFTheight = 1024;
	int FFTsize = FFTheight * FFTwidth;
	int moonsize = moonheight * moonwidth * 3;
	int moonYsize = moonheight * moonwidth;
	int moonEsize = moonheight * moonwidth * 2;

	ifstream Imoonfile("moon.yuv", ios::binary);
	ofstream Omoonfile("outmoon.yuv", ios::binary);
	if (!Imoonfile) { cout << "error to open moonfile!" << endl; }
	if (!Omoonfile) { cout << "error to create moonfile!" << endl; }
	
	unsigned char* IYmoon = new unsigned char[moonYsize];//moon的Y分量
	unsigned char* IEmoon = new unsigned char[moonEsize];//moon的其他分量
	unsigned char* OYmoon = new unsigned char[moonYsize];
	double* IYNotch = new double[moonYsize];//中心化後的Y分量
	double* FFT2D_RE = new double[FFTsize];//FFT以後的矩陣實部
	double* FFT2D_IM = new double[FFTsize];//FFT以後的矩陣虛部
	double* NY = new double[moonYsize];//反變換以後的Y分量

	Imoonfile.read((char*)IYmoon, moonYsize);
	Imoonfile.read((char*)IEmoon, moonEsize);
	
	Notch(IYmoon,IYNotch, moonheight,moonwidth);
	
	//補零
	Change_Y(IYNotch, FFT2D_IM, FFT2D_RE,moonheight,moonwidth,FFTheight,FFTwidth);
	//進行每列的FFT_1D變換
	FFT_Column(FFT2D_RE,FFT2D_IM, FFTheight, FFTwidth);
	FFT_Row(FFT2D_RE, FFT2D_IM, FFTheight, FFTwidth);

	//用濾波器函數H(u, v)乘以F(u, v)
	double* H = new double[FFTsize];
	CreateH(H,FFTheight,FFTwidth);
	Filter(FFT2D_IM, FFT2D_RE, H, FFTheight, FFTwidth);

	//虛部取共軛
	Conjugate(FFT2D_IM, FFTsize);
	FFT_Column(FFT2D_RE, FFT2D_IM, FFTheight, FFTwidth);
	FFT_Row(FFT2D_RE, FFT2D_IM, FFTheight, FFTwidth);
	Conjugate(FFT2D_IM, FFTsize);

	//去零
	Delete_zero(FFT2D_RE, NY, FFTheight, FFTwidth, moonheight, moonwidth);

	//去中心化
	Notch_2(NY, IYNotch, moonheight, moonwidth);

	//強制類型轉換
	for (int i = 0; i < moonheight; i++)
	{
		for (int j = 0; j < moonwidth; j++)
		{
			if (IYNotch[i * moonwidth + j] > 255)
			{
				IYNotch[i * moonwidth + j] = 255;
			}
			else if (IYNotch[i * moonwidth + j] < 0)
			{
				IYNotch[i * moonwidth + j] = 0;
			}
			OYmoon[i * moonwidth + j] = unsigned char(IYNotch[i * moonwidth + j]);
		}
	}
	//寫文件
	Omoonfile.write((char*)OYmoon, moonYsize);
	Omoonfile.write((char*)IEmoon, moonEsize);

	delete[]IYmoon;
	delete[]IEmoon;
	delete[]IYNotch;
	delete[]FFT2D_IM;
	delete[]FFT2D_RE;
	delete[]NY;
	delete[]H;
	Imoonfile.close();
	Omoonfile.close();
	return 0;
}

實驗結果

在這裏插入圖片描述
  至此,實驗結束。

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