I'll illustrate my problem on an example
I have a 3x100 matrix and I want to slide a 3x3 filter over it.
However, I do not want any of the padding that imfilter would use, such as X, symmetric, replicate, etc., which would yield a 3x100 output.
I rather want the sliding window to be only applied when there is real data, such that my output would be 1x (100 - 4).
What would be the most elegant (loopless) way to do this in matlab?
You can use the built-in conv2 function with 'Valid' as the shape parameter which will only provide results when there is a complete overlap between the filter and the data.
filtered = conv2(data, filter, 'valid');
Related
I have an 3D matrix 512*512*100. I want to apply fftshift on each page of it using the GPU. What I am doing right now is:
G = rand(512,512,100, 'gpuArray');
for i=1:100
G(:,:,i) = fftshift(G(:,:,i));
end
Is there a faster way to apply fftshift without doing it in a loop? For example, fft2 can be applied directly to an 3D array performing the operation on each page separately. However, fftshift does not work like that. Furthermore, fftshift is not supported by pageFun.
fftshift has an optional second input argument that selects along which dimension to apply the shift. Unfortunately, it is not possible to provide two dimensions, so fftshift(G,[1,2]) will not work. You'll have to call fftshift twice:
G = fftshift(fftshift(G,1),2);
Hopefully this is faster than calling it 100 times for a single page.
function out = findWaldo(im, filter)
% convert image (and filter) to grayscale
im_input = im;
im = rgb2gray(im);
im = double(im);
filter = rgb2gray(filter);
filter = double(filter);
filter = filter/sqrt(sum(sum(filter.^2)));
out = normxcorr2(filter, im);
Question1: Why we first do rgb2gray on im and filter?
Question2: What does the last second line actually do? Namely,
filter = filter/sqrt(sum(sum(filter.^2)));
Question 1: Why apply rgb2gray first?
normxcorr2 standing for "Normalized 2-D cross-correlation" works on a 2D signal (see doc). A RGB image is a 3D signal: width x height x color (e.g. 1024 x 1024 x 3, 3 since it's three colors). That is why you flatten it first to one color channel. Applying the filter to the image on each color separately would be the alternative, but then you also need to process three correlations (average them or something...).
Question 2: What does filter = filter/sqrt(sum(sum(filter.^2)));do?
It squares the filter image, then sums over rows and columns (basically all squared gray values of the filters) to get a single number that the squareroot is applied to and then is used to divide all filter image values.
I'd say it is some sort of normalization to handle specific input signals, maybe an attempt to get values from 0 - 1. But since normalized cross correlation (normxcorr2) does normalization itself, this step is definitely not needed for it. Unless you don't do something other than cross correlation with the filter variable, I'd consider this an artifact that should be deleted.
General explanation of the function
This function receives two inputs: an image file and a template.
For example, the image file may be a large scene of findings Waldo game and the template can be a picture of Waldo himself.
The output is a matrix called 'out' with same size as the image file. s.t. each pixel holds a "matching results". The higher the value - the higher the chances that the patch centered around the pixel holds a similar pattern such as the template.
The maximal value should be on the pixel in which Waldo is.
Question 1
rgb2gray function receives an rgb image with 3 channels and transorm it into gray image.
It is done on im and on filter because normxcorr2 function only works with grayscale images.
Question 2
The last perform normalization of the pattern: it divides it by it's norm, thus changing it to 1. In fact, this line is not required and should be deleted. Normalization stage is already performed inside normxcorr2 function.
I have two equally-sized data-arrays (mainly zeros, and sparsely filled with ones), and make the conv of it. As a result I get this.
Now one can see a peak around -10^{-5}. My question is, how can I do the convolution such that I only get a small region around that peak?
I know that the convolution is defined from minus infinity to infinity. Mathematically I would want to change those limits to (in my example) [-1.5*10^5,-0.5*10^-5].
Thanks alot for your help!
edit
I found the solution: One can use xcorr(a,fliplr(b)) instead of conv(a,b). Now xcorr has the option "maxlags", which is exactly the thing I was searching for.
You can reduce the number of output values of conv, but not arbitrarily. Try 'same' or 'valid' options:
C = CONV(A, B, SHAPE) returns a subsection of the convolution with size specified by SHAPE:
'full' - (default) returns the full convolution,
'same' - returns the central part of the convolution
that is the same size as A.
'valid' - returns only those parts of the convolution
that are computed without the zero-padded edges.
LENGTH(C)is MAX(LENGTH(A)-MAX(0,LENGTH(B)-1),0).
To specify arbitrary output limits, you probably need to do the convolution manually with a user-defined function. But it may be more efficient to use conv and then trim the output.
I have a window of size 5*5.An image of size 360*300.When i convolve the two using the function.I am working on matlab.
conv2(image,window,'same');
the values of the pixel goes above 255.I used the code below to restrict the value below 255.
( conv2(image,window,'same')/sum(sum(window));
I have 3 questions which are listed below.
Is it the right way to proceed??
Does the function take care of this constraint also?
Any alternate method?
To specify what is said in the comments:
The overall sum of your window
ws = sum(window(:))
is like an amplification. If ws>1, then your image tends to get brighter. If 0 < ws < 1 your image will get darker. If ws = 0, then you will receive an image, that will average at about zero. This is often the case in edge detection scenarios. For example, the Sobel Operator has a sum of zero.
Often, the convolution is executed with an amplification equal to 1, to separate the amplification from the convolution. As convolution is a linear operator, it does not matter whether you divide the window by ws or the resulting image.
To answer questions 1 and 3 in particular: The usual way is to normalize the window. That is:
window = window ./ sum(window(:)); % Normalize convolution kernel
conv2(image,window,'same');
Is there a 3D eqivalent of imfilter available for MATLAB? I wish to apply Gaussian filtering to a 3D histogram. I was going to implement it myself, by creating a (3D) Gaussian filter, then looping over each element in my histogram, and summing up the corresponding data entries.
However, I didn't want to implement it myself in a slow and inefficient way if there's something already out there, or a cleverer way of doing it.
There are two ways to solve this in order to do the filtering in an efficient manner:
(1) Use CONVN three times to filter your data with three 1D Gaussians, one x-by-1-by-1, one 1-by-y-by-1, and one 1-by-1-by-z.
(2) If you have the signal processing toolbox, use FFTFILT to perform filtering in inverse space (or use any one of the fft-convolution algorithms on the file exchange).
[(3) Send me an email and I'll send you my fftFilterImage, which does 3D Gauss filtering.]
imfilter can already do 3D filtering, as long as the data matrix and the filter you give it are 3D. See the imfilter page.
This task can be handled with the new (as of R2015a) imgaussfilt3 function.
The basic syntax is as follows:
B = imgaussfilt3(A,sigma)
There are also a number of name-value pair arguments:
'FilterSize': Size of the Gaussian filter, defaulting to a cube of size 2*ceil(2*sigma)+1.
'Padding': Type of padding ('replicate' (default) | 'circular' | 'symmetric').
'FilterDomain': Perform convolution in domain: 'frequency' or 'spatial' (default auto).