0

I am trying to create a very simple C++ program that given an argument in range [0-100] applies a low-pass filter to a grayscale image that should "compress" it proprotionally to the value of the given argument. I am using the FFTW library.

I have some doubts about how I define the frequency threshold, cut. Is there any more effective way to define such value?

//fftw_complex *fft
//double[] magnitude
// . . . 

int percent = 100;
    if (percent < 0 || percent > 100) {
        cerr << "Compression rate must be a value between 0 and 100." << endl;
        return -1;
    }

double cut =(double)(w*h) * ((double)percent / (double)100);
    for (i = 0; i < (w * h); i++) {
        magnitude[i] = sqrt(pow(fft[i][0], 2.0) + pow(fft[i][1], 2.0));
        if (magnitude[i] < cut) {
            fft[i][0] = 0.0;
            fft[i][1] = 0.0;
        }
    }

Update1:

I've changed my code to this, but again I'm not sure this is a proper way to filter frequencies. The image is surely compressed, but non-square images are messed up and setting compression to 100% isn't the real maximum compression available (I can go up to ~140%). Here you can find an image of what I see now.

int cX = w/2;
int cY = h/2;
cout<<"TEST "<<((double)percent/(double)100)*h<<endl;
for(i = 0; i<(w*h);i++){
    int row = i/s;
    int col = i%s;
    int distance = sqrt((col-cX)*(col-cX)+(row-cY)*(row-cY));
    if(distance<((double)percent/(double)100)*min(cX,cY)){
        fft[i][0] = 0.0;
        fft[i][1] = 0.0;
    }
}
Vektor88
  • 4,841
  • 11
  • 59
  • 111
  • 1
    `abs(sqrt(foo))` - do you expect `sqrt` to return negative values?? – MSalters Jun 04 '14 at 06:47
  • @MSalters that's what happens when you copy a formula from some powerpoint slides :) – Vektor88 Jun 04 '14 at 06:49
  • 2
    ot note: pow(x, 2.0) is usually much slower than x*x. pow is there to permit floating point exponents. would be even better to if (fft[i][0]*fft[i][0] + fft[i][1]*fft[i][1] < cut*cut) – Exceptyon Jun 04 '14 at 06:55
  • This is not a low pass filter at all, as others have mentioned - all it does is remove energy at bins where the energy is below a certain threshold. You should change the terminology in your question and title to avoid further confusion. – Paul R Jun 04 '14 at 08:45
  • @PaulR even the updated code? I took this question as reference: http://stackoverflow.com/questions/22740632/high-pass-filter-using-fftw-in-c?rq=1 and it seems quite similar to my code.. – Vektor88 Jun 04 '14 at 08:59
  • OK - you shouldn't really change your question fundamentally once people have started to answer it - it results in answers which are "out of sync" with the question, which is confusing and unhelpful for future visitors to the question. Having said that, you really need to decide what you are trying to achieve - if you simply want to decimate the image then use a simple gaussian filter in the spatial domain - it's a lot simpler than doing this in the frequency domain. Frequency domain filtering is really only appropriate for large filter kernels. – Paul R Jun 04 '14 at 09:26
  • @PaulR I want to implement a low-pass filter. I had no idea what I was doing, then I read some documentation and improved my code. The goal remains the same. I'll keep updating the question with each progress I make, and this seems to me the right thing to do. – Vektor88 Jun 04 '14 at 09:34
  • OK - please note my comments above re filtering in the frequency domain - your approach will be overly complex and inefficient unless you want to apply large decimation factors. Note also that "brick wall" filtering in the frequency domain (which is what you are trying to do in the latest version of your code) is inherently flawed and will produce nasty artefacts - you need to use a window function rather than a step function. – Paul R Jun 04 '14 at 09:52

1 Answers1

4

This is not a low-pass filter at all. A low-pass filter passes low frequencies, i.e. it removes fine details (blurring). You obviously need a 2D FFT for that.

This code just removes random bits, essentially.

[edit] The new code looks a lot more like a low-pass filter. The 141% setting is expected: the diagonal of a square is sqrt(2)=1.41 times its side. Converting an index into a row/column pair should use the image width, not some random unexplained s.

I don't know where your zero frequency is located. That should be easy to spot (largest value) but it might be in (0,0) instead of (w/2,h/2)

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • How should I convert that code to perform a 2D FFT? My fft is defined this way: `fwd = fftw_plan_dft_2d(w, h, data_in, fft,FFTW_FORWARD,FFTW_ESTIMATE);` and I thought I was doing a 2d transform. – Vektor88 Jun 04 '14 at 07:01
  • @Vektor88: Oh, I didn't say you weren't doing a 2D FFT, you didn't show it so I just wanted to make sure you did. But you realize the result is also 2D? – MSalters Jun 04 '14 at 07:54
  • Yes, I realize it and after reading some documents I've made some changes to my code and updated my question. The problem still remains, how to properly set the frequency threshold? I also have some problems with images that are not square. – Vektor88 Jun 04 '14 at 08:28
  • `s` is the `cv::Mat().step` value, which corresponds to the image width. – Vektor88 Jun 04 '14 at 11:45