利用频率陷波滤波处理图像

  1. 编程实现2-d DFT正变换和反变换
    测试图像:moon.yuv (宽464,高538,4:4:4取样)
    要求:(1) 调用1-D FFT模块实现2-D FFT
    (2) 封装2-D FFT函数,通过调用2-D FFT实现2-D IDFT
  2. 频率域陷波滤波
    测试图像:moon.yuv (宽464 高538)
    实验平台:Visual C++
    实验方法:频率域陷波滤波。具体要求如下:
    • 陷波滤波:
      f ( x ) = { x = 0 , ( u , v ) = ( M 2 , N 2 ) y = 1 , e l s e f(x)=\left\{ \begin{aligned} x & = 0, (u,v) = (\frac{M}{2}, \frac{N}{2}) \\ y & = 1, else\\ \end{aligned} \right. f(x)=xy=0,(u,v)=(2M,2N)=1,else
      在滤波器中加入一个常量,以避免F(0,0)被完全消除,即:
      H e ( u , v ) = k H ( u , v ) + c H_e(u,v)=kH(u,v)+c He(u,v)=kH(u,v)+c,为了方便,取k=1。
    • 只需要对Y分量进行频率域高通滤波。Cb、Cr分量直接置为128即可。
    • 频域滤波的具体步骤:
      • ( − 1 ) x + y (-1)^{x+y} (1)x+y乘以输入图像进行频率中心变换
      • 计算1中的DFT F(u, v)
      • 用滤波器函数H(u, v)乘以F(u, v)
      • 计算(3)中结果的反DFT
      • 得到(4)中结果的实部
      • ( − 1 ) x + y (-1)^{x+y} (1)x+y乘以5中的结果,取消输入图像的乘数
代码实现:

fft.h

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 ifft_2d(double* Real, double* Imag, int width, int height);
void fft_2d(double* Real, double* Imag, int width, int height);

fft.cpp

#include <stdio.h> 
#include <stdlib.h>
#include <math.h>   
#include <assert.h>

#include "fft.h"

#define  M_PI 3.1415926


/*********************************************************************************************
对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;

			}
		}
	}
}

void fft_2d(double* Real, double* Imag, int width, int height)
{
	double* reLine, * imLine, * reRow, * imRow;
	reRow = new double[height]; imRow = new double[height];
	for (int i = 0; i < height; ++i)
		fft_1d(width, Real + i * width, Imag + i * width);

	for (int num = 0; num < width; ++num)
	{
		for (int i = 0; i < height; ++i)
		{
			reRow[i] = Real[i * width + num];
			imRow[i] = Imag[i * width + num];
		}
		fft_1d(height, reRow, imRow);
		for (int i = 0; i < height; ++i)
		{
			Real[i * width + num] = reRow[i];
			Imag[i * width + num] = imRow[i];
		}
	};
}
void ifft_2d(double* Real, double* Imag, int width, int height)
{
	for (int i = 0; i < width * height; ++i) Imag[i] = -Imag[i];
	fft_2d(Real, Imag, width, height);
}

main.cpp

#include <cstdio> 
#include <cstdlib>
#include <cmath>   
#include <cassert>
#include <iostream>
#include <fstream>
#include "fft.h"
#include <cstring>
using namespace std;

unsigned char filter(double x)
{
	if (x > 255) x = 255;
	if (x < 0) x = 0;
	return x;
}
int main(int argc, char* argv[])
{
	const string inPath = "moon.yuv";
	const string outPath = "monn_filted.yuv";
	int width = 464, height = 538;
	ifstream in( inPath, ios::binary );
	unsigned char* yBuffer, * uBuffer, * vBuffer;
	int size = width * height;
	for (auto i : { &yBuffer, &uBuffer, &vBuffer }) *i = new unsigned char[size];
	for (auto i : { &yBuffer, &uBuffer, &vBuffer }) in.read((char*)(*i), size);
	
	double* Real, * Imag;
	int newWidth = 1 << (log_2(width) + 1), newHeight = 1 << (log_2(height) + 1);
	int newSize = newWidth * newHeight;
	Real = new double[newSize]; Imag = new double[newSize];
	for (int i = 0; i < newSize; ++i) Imag[i] = Real[i] = 0;
	for (int i = 0; i < height; ++i)
		for (int j = 0; j < width; ++j)
			Real[i * newWidth + j] =  ((i+j)&1 ? -1.0 : 1) * yBuffer[i * width + j];
	
	fft_2d(Real, Imag, newWidth, newHeight);
	for (int i = 0; i < newSize; ++i)
	{
		Real[i] *= 1 + 0.5;
	}
	Real[newWidth / 2] = Imag[newHeight / 2] = 0;
	ifft_2d(Real, Imag, newWidth, newHeight);
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
			yBuffer[i * width + j]  = filter(((i + j) & 1 ? -1.0 : 1) * Real[i * newWidth + j] / newSize  );
	}
	ofstream out(outPath, ios::binary);
	for (auto i : { &yBuffer, &uBuffer, &vBuffer }) out.write((char*)(*i), size);
}
实验结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值