% DoLogGabor: spatial-frequency and/or orientation band-pass filter an % image using a logGabor filter. % % This is a very flexible/useful spatial filter, since you can specify % if it cares about orientation or not, and you can specify if it cares % about spatial frequency or not. % % Using it looks like this: % res = DoLogGabor(im,FreqPeak,FreqSigma,ThetaPeak,ThetaSigma); % % Parameters: % 'im' an image: can be RGB, grayscale or a stack of grayscale images (a movie) % 'Peak' spatial frequency is 'FreqPeak' in cycles per image % 'FreqSigma' specified the spatial-frequency bandwidth. It's the sigma parameter of a log-Gabor specified in octaves (put in 0 to pass all SFs) % 'ThetaPeak' is peak orientation (radians., 0 is vertical) % 'ThetaSigma' is orientation s.d. of a wrapped Gaussian (radians; Inf means orientation broadband) % % Note that FreqPeak and ThetaPeak can be lists and the result will be an image array. % Note that if you provide a second output argument the routine returns the filter FFTs % Note that the routine tries to maintain the original RMS contrast in each % input image component (e.g. within each R-G-B component) % % e.g. [res]=DoLogGabor(randn(512),[8 32 128],[0.5],DegToRad([0:45:135]),DegToRad(15)); imagesc(real(res(:,:,1,1))); colormap(gray(256)); % % This makes a 3 X 4 array of 512X512 pix noise patterns at 8,32 and 128 c/image % with peak orientations of 0, 45, 90 and 135 deg. % % The results will have a real and imaginary component. Run real() and % imaginary() on the result to get the components (you usually just use real()) % Running abs() sum the square of the two components to give the local energy. % % Note extra output arguments return (first) a list of contrast energies % and (second) a list of the filter FFTs. I use these for batch processing. % % % If you use this in published research please cite "Horizontal information drives the % behavioral signatures of face processing" Goffaux & Dakin (2010) Frontiers in Perception % Science v1, 143 % % May 2015, Steven Dakin, s.dakin@auckland.ac.nz % function [resFinal,varargout]=DoLogGabor(im,FreqPeak,FreqSigma,ThetaPeak,ThetaSigma) [n m p]=size(im); for pLoop=1:p % loop on third dimension of image iFT = fft2(im(:,:,pLoop)); % we'll need the fft of the image if length(ThetaSigma)< length(ThetaPeak) % pad parameter lists if necessary so they're all the same length ThetaSigma = ThetaSigma(1)+ 0.*ThetaPeak; end if length(FreqSigma) < length(FreqPeak) % pad parameter lists if necessary so they're all the same length FreqSigma = FreqSigma(1) + 0.*FreqPeak; end [X,Y] = meshgrid((-m/2: (m/2-1))/(m/2),(-n/2 : (n/2 - 1))/(n/2)); % the grid we'll use to make the filter in the Fourier domain CentreDist = sqrt(X.^2 + Y.^2); % distance from centre for computing frequency CentreDist(round(n/2+1),round(m/2+1)) = 1; % Set 0 dist to be one (a hack to avoid 1/0: we fix this later) CentreAng = pi/2+atan2(-Y,X); % angle from centre for computing filter orientation for OrLoop = 1:length(ThetaPeak) % loop on filter orientations % first compute the angular band-pass component of the filter and put it in the variable 'AngSpread' ds = sin(CentreAng) * cos(ThetaPeak(OrLoop)) - cos(CentreAng) * sin(ThetaPeak(OrLoop)); % need this for dtheta calc dc = cos(CentreAng) * cos(ThetaPeak(OrLoop)) + sin(CentreAng) * sin(ThetaPeak(OrLoop)); % need this for dtheta calc dtheta = atan(ds./dc); % angular difference. AngSpread = exp((-dtheta.^2) /(2*ThetaSigma(OrLoop)^2)); % a Fourier-domain filter that is bandpass in the angular domain % now add in the spatial-frequency badpass component for s = 1:length(FreqPeak) % loop on filter SF FreqSdAbsolute = (1/(2.^(FreqSigma(s)))); % compute bandwidth from parameter (which is in octaves) rfo = (FreqPeak(s)./min([m n]))/0.5; % Radius from centre of frequency plane sfSpread = exp((-(log(CentreDist/rfo)).^2) / (2 * log(FreqSdAbsolute)^2)); % a log Gaussian i.e. bandpass in the log-SF domain sfSpread(round(n/2+1),round(m/2+1)) = 0; % Impose zero d.c. on the filter (sorts out the hack above) filter1 = (sfSpread.*AngSpread); % Multiply by angular AngSpread tmp1 = ifft2(iFT.*fftshift(filter1)); % compute result res(:,:,s,OrLoop) = tmp1; % pop the result in an array energy(s,OrLoop) = std(tmp1(:)); % compute RMS contrast and store it end end if nargout>1 % if you give an extra output argument it will return the energy varargout{1}=energy'; end if nargout>2 % if you another output arguments it will return the filters varargout{2}=fftshift(filter1); end if (length(FreqSigma)<2) && (length(ThetaSigma)<2) resFinal(:,:,pLoop)=res; else resFinal=(res); end end