I need to filter an image using a bank of filters in Matlab. My first attempt was to use a开发者_如何转开发 simple for loop to repeatedly call the "imfilter" function for each filter in the bank.
I will need to repeat this process many times for my application, so I need to this step to be as efficient as possible. Therefore, I was wondering if there was any way this operation could be vectorized to speed up the process. In an effort to simplify things, all of my filter kernels are the same size (9x9).
As an example of what I am going for, my filters are set up in a 9x9x32 element block, which needs to be applied to my image. I thought about replicating the image into a block (e.g. 100x100x32), but I'm not sure if there's a way to apply an operation like convolution without resorting to loops. Does anyone have suggestions for a good way of tackling this problem?
Other than pre allocating the space, there is not a faster way to arrive at an exact solution. If approximations are ok, then you might be able to decompose the 32 filters into a set of linear combinations of a smaller number of filters, say eight. See for instance Steerable filters.
http://people.csail.mit.edu/billf/papers/steerpaper91FreemanAdelson.pdf
edit: here is a tool to help apply filters to images.
function FiltIm = ApplyFilterBank(im,filters)
%#function FiltIm = ApplyFilterBank(im,filters)
%#
%#assume im is a single layer image, and filters is a cell array
nFilt = length(filters);
maxsz = 0;
for i = 1:nFilt
maxsz = max(maxsz,max(size(filters{i})));
end
FiltIm = zeros(size(im,1), size(im,2), nFilt);
im = padimage(im,maxsz,'symmetric');
for i = 1:nFilt
FiltIm(:,:,i) = unpadimage(imfilter(im,filters{i}),maxsz);
end
function o = padimage(i,amnt,method)
%#function o = padimage(i,amnt,method)
%#
%#padarray which operates on only the first 2 dimensions of a 3 dimensional
%#image. (of arbitrary number of layers);
%#
%#String values for METHOD
%# 'circular' Pads with circular repetion of elements.
%# 'replicate' Repeats border elements of A.
%# 'symmetric' Pads array with mirror reflections of itself.
%#
%#if(amnt) is length 1, then pad all sides same amount
%#
%#if(amnt) is length 2, then pad y direction amnt(1), and x direction amnt(2)
%#
%#if(amnt) is length 4, then pad sides unequally with order LTRB, left top right bottom
if(nargin < 3)
method = 'replicate';
end
if(length(amnt) == 1)
o = zeros(size(i,1) + 2 * amnt, size(i,2) + 2* amnt, size(i,3));
for n = 1:size(i,3)
o(:,:,n) = padarray(i(:,:,n),[amnt,amnt],method,'both');
end
end
if(length(amnt) == 2)
o = zeros(size(i,1) + 2 * amnt(1), size(i,2) + 2* amnt(2), size(i,3));
for n = 1:size(i,3)
o(:,:,n) = padarray(i(:,:,n),amnt,method,'both');
end
end
if(length(amnt) == 4)
o = zeros(size(i,1) + amnt(2) + amnt(4), size(i,2) + amnt(1) + amnt(3), size(i,3));
for n = 1:size(i,3)
o(:,:,n) = padarray(padarray(i(:,:,n),[amnt(2), amnt(1)],method,'pre'),[amnt(4), amnt(3)],method,'post');
end
end
function o = unpadimage(i,amnt)
%#un does padimage
%#if length(amnt == 1), unpad equal on each side
%#if length(amnt == 2), first amnt is left right, second up down
%#if length(amnt == 4), then [left top right bottom];
switch(length(amnt))
case 1
sx = size(i,2) - 2 * amnt;
sy = size(i,1) - 2 * amnt;
l = amnt + 1;
r = size(i,2) - amnt;
t = amnt + 1;
b = size(i,1) - amnt;
case 2
sx = size(i,2) - 2 * amnt(1);
sy = size(i,1) - 2 * amnt(2);
l = amnt(1) + 1;
r = size(i,2) - amnt(1);
t = amnt(2) + 1;
b = size(i,1) - amnt(2);
case 4
sx = size(i,2) - (amnt(1) + amnt(3));
sy = size(i,1) - (amnt(2) + amnt(4));
l = amnt(1) + 1;
r = size(i,2) - amnt(3);
t = amnt(2) + 1;
b = size(i,1) - amnt(4);
otherwise
error('illegal unpad amount\n');
end
if(any([sx,sy] < 1))
fprintf('unpadimage newsize < 0, returning []\n');
o = [];
return;
end
o = zeros(sy, sx, size(i,3));
for n = 1:size(i,3)
o(:,:,n) = i(t:b,l:r,n);
end
New Answer: Use colfilt() or block filtering style. Matlab can transform your image into large matrix where each distinct 9x9 pixel area is a single column (81 elements). Make it using im2col() method. If your image is N by M the result matrix would be 81 X (N-8)*(M-8).
Then you can concatenate all your filters to single matrix (each filter is a row) and multiply those huge matrices. This will give you the result of all filters. Now you have to reconstruct back 32 result images from the result matrix. use col2im() method. For more information type 'doc colfilt'
This method works almost as fast as mex file and doesnt require any 'for' loop
Old answer:
Do you want to get different 32 results or single result for combination of filters? If it is a sungle result than there is an easy way. If you use linear filters (like convolutions) then apply filters one on another. Finally apply the resulting filter on the image. Thus image will be convolved only once. If you filters are symmetric (x and y direction) then instead of applying the 9x9 filter apply 9x1 on y direction and 1x9 on x direction. Works a bit faster. Finally, you can try using Mex file
精彩评论