I’m working on spatial frequency filtering using code from this site.
https://www.djmannion.net/psych_programming/vision/sf_filt/sf_filt.html
There is similar code here on stack exchange. What I was wondering though is how to convert the cutoff used in the Butterworth filter, which is a number from 0 to 1, to cycles / degree in the image when I report it. I feel like I’m missing something obvious. I’m imagining it has to do with the visual angle the image subtends and the resolution.
Advertisement
Answer
The Butterworth filter commonly used in psychology software to filter spatial frequencies from images is typically used as a low pass or high pass filter with a value given between 0 and 1 for the cutoff. That value will be the 50% cut point for the filter. For example, if it’s low pass 50% or more of the frequencies below the cutoff will remain in the image and 50% or fewer above the cutoff will remain. The opposite is true for the high pass setting. It does have a steep rise to the function near the cutoff so it’s good to use the cutoff to describe your filtered image.
So, what is the cutoff value and what does it mean? It’s just a proportion of the max frequency in cycles/pixel. Once you know that max it’s easy to derive, and it turns out the max is a constant. Suppose your image is 128×128. In 128 pixels you could have a maximum frequency of 64 cycles, or 0.5 cycles/pixel. Looking at fftfreq function in numpy or matlab reveals the max is always a 0.5 cycles/pixel. That makes sense because you need two pixels for a period. This means that a cutoff of 0.2 is going to be 0.1 cycles/pixel. Whatever cutoff you pick you can just divide in half and that’s the cycles/pixel. Than all you need to do is scale that to cycles/degree.
Cycles / pixel can be converted to cycles / degree of visual angle once you know the size of the image presented in degrees of visual angle. For example, if someone’s eye is d
distance from the image of h
height then the image will span 2 * atan( (h/2) / d)
degrees of visual angle (assuming your atan function reports degrees and not radians, you may have to convert). Take the number of pixels in your image and divide it by the total span in degrees to get pixels / degree. Then multiply frequency (cycles / pixel) by pixels / degree to get cycles / degree.
Pseudo code equation version below:
cycles/pixel = cutoff * 0.5 d = distance_from_image_in_cm h = height_of_image_in_cm degrees_of_visual_angle = 2 * atan( (h/2) / d) pixels/degree = total_pixels / degrees_of_visual_angle cycles/degree = cycles/pixel * pixels/degree