Search code examples
image-processingedge-detectiondct

Edge Detection in Frequency Domain


How to apply filter to detect edges in Frequency Domain? I have applied the Discrete Cosine Transform to the input image.

I don't know how to apply filter to detect the edges. Can anyone please help to detect the edges?


Solution

  • There are a number of methods out there for this, and one in particular I'll mention is the concentration factor method for detecting edges in spectral signals.

    However, these methods are typically used on continuous frequency signals and there's no reason to use this on images. It's slower than convolution kernel based approaches, like Sobel filters for Canny edge detection, and the literature is far more specialized for fields where only frequency based information is given, like in reconstruction from radar or MRI signals.

    Images contain local information, like where features (e.g. edges) are located. The spectral representations give global information, like how often certain patterns in the image repeat. Reconstructing local information from global patterns is necessary in some fields, but is not at all necessary to use when you already have the local data (i.e. the image). In other words, you're basically throwing out information by transforming the image first.


    Either way, to apply a filter in the frequency domain, you just multiply the Fourier coefficients (values of your transformed image). For instance, say you had a Fourier transform of a signal in a vector with increasing wavenumber from 0, i.e. a vector [f0, f1, ..., fn-1] where each fi is the ith Fourier coefficient. A high-pass filter is a filter which lets the high frequencies pass, and removes the low frequencies. So if you imagine this same vector but now multiplied so that the lower frequencies are suppressed, it might look like [f0/10000, f1/1000, f2/100, f3/10, f4]. If you simply inverse transform back into image space with these Fourier coefficients, you will have suppressed the lower frequencies in the image.

    The same idea applies to any low-pass, band-pass, high-pass, etc filter. You simply multiply the Fourier coefficients by some scale or you take some window of Fourier coefficients and neglect or scale the rest. You can try using linear scaling, logarithmic scaling, or just a shelf and see the differences in the image.


    For example in OpenCV with Python, this code is minimal and shows the idea. Here's the image:

    >>> import numpy as np
    >>> import cv2
    >>> img = np.zeros((8, 8), dtype=np.float32)
    >>> img[2:6, 2:6] = 1
    >>> img
    array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
           [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
           [ 0.,  0.,  1.,  1.,  1.,  1.,  0.,  0.],
           [ 0.,  0.,  1.,  1.,  1.,  1.,  0.,  0.],
           [ 0.,  0.,  1.,  1.,  1.,  1.,  0.,  0.],
           [ 0.,  0.,  1.,  1.,  1.,  1.,  0.,  0.],
           [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
           [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]], dtype=float32)
    

    So it's just a black image with the white square in the center. If you want to detect the edges, the bare-bones basic way is a high-pass filter. So you can take the Fourier transform or the DCT, and then remove the low frequencies (with the way most libraries compute the DCT, the center values are the low-frequencies, and the values closer to the borders of the DCT image are the higher frequencies---this is true of OpenCV too, so we'll just set the values in the center of the DCT to zero)

    >>> dct_coeff = cv2.dct(img)
    >>> dct_coeff[2:6, 2:6] = 0
    

    All that's left to do is to take the inverse transform and threshold to see where the edges are:

    >>> hp_img = cv2.idct(dct_coeff)
    >>> hp_img > 0.75
    array([[False, False, False, False, False, False, False, False],
           [False, False, False, False, False, False, False, False],
           [False, False,  True,  True,  True,  True, False, False],
           [False, False,  True, False, False,  True, False, False],
           [False, False,  True, False, False,  True, False, False],
           [False, False,  True,  True,  True,  True, False, False],
           [False, False, False, False, False, False, False, False],
           [False, False, False, False, False, False, False, False]], dtype=bool)
    

    Now, this is a very basic approach and noise kills high-pass filtering approaches quickly (as noise is generally high frequency). And that's when you need to move to advanced methods, such as the concentration factor. But even then, this method is not super useful to use on images compared to the power and simplicity of Canny/Sobel edge detection.