Image convolution: Difference between revisions

Added MATLAB Example
m (i can't upload files, so have some links!)
(Added MATLAB Example)
Line 903:
ImageConvolve[img, GaussianMatrix[35] ]
ImageConvolve[img, BoxMatrix[1] ]</lang>
 
=={{header|MATLAB}}==
The built-in function [http://www.mathworks.com/help/matlab/ref/conv2.html conv2] handles the basic convolution. Below is a program that has several more options that may be useful in different image processing applications (see comments under convImage for specifics).
<lang MATLAB>function testConvImage
Im = [1 2 1 5 5 ; ...
1 2 7 9 9 ; ...
5 5 5 5 5 ; ...
5 2 2 2 2 ; ...
1 1 1 1 1 ]; % Sample image for example illustration only
Ker = [1 2 1 ; ...
2 4 2 ; ...
1 2 1 ]; % Gaussian smoothing (without normalizing)
fprintf('Original image:\n')
disp(Im)
fprintf('Original kernal:\n')
disp(Ker)
fprintf('Padding with zeroes:\n')
disp(convImage(Im, Ker, 'zeros'))
fprintf('Padding with fives:\n')
disp(convImage(Im, Ker, 'value', 5))
fprintf('Duplicating border pixels to pad image:\n')
disp(convImage(Im, Ker, 'extend'))
fprintf('Renormalizing kernal and using only values within image:\n')
disp(convImage(Im, Ker, 'partial'))
fprintf('Only processing inner (non-border) pixels:\n')
disp(convImage(Im, Ker, 'none'))
% Ker = [1 2 1 ; ...
% 2 4 2 ; ...
% 1 2 1 ]./16;
% Im = imread('testConvImageTestImage.png', 'png');
% figure
% imshow(imresize(Im, 10))
% title('Original image')
% figure
% imshow(imresize(convImage(Im, Ker, 'zeros'), 10))
% title('Padding with zeroes')
% figure
% imshow(imresize(convImage(Im, Ker, 'value', 50), 10))
% title('Padding with fifty: 50')
% figure
% imshow(imresize(convImage(Im, Ker, 'extend'), 10))
% title('Duplicating border pixels to pad image')
% figure
% imshow(imresize(convImage(Im, Ker, 'partial'), 10))
% title('Renormalizing kernal and using only values within image')
% figure
% imshow(imresize(convImage(Im, Ker, 'none'), 10))
% title('Only processing inner (non-border) pixels')
end
 
function ImOut = convImage(Im, Ker, varargin)
% ImOut = convImage(Im, Ker)
% Filters an image using sliding-window kernal convolution.
% Convolution is done layer-by-layer. Use rgb2gray if single-layer needed.
% Zero-padding convolution will be used if no border handling is specified.
% Im - Array containing image data (output from imread)
% Ker - 2-D array to convolve image, needs odd number of rows and columns
% ImOut - Filtered image, same dimensions and datatype as Im
%
% ImOut = convImage(Im, Ker, 'zeros')
% Image will be padded with zeros when calculating convolution
% (useful for magnitude calculations).
%
% ImOut = convImage(Im, Ker, 'value', padVal)
% Image will be padded with padVal when calculating convolution
% (possibly useful for emphasizing certain data with unusual kernal)
%
% ImOut = convImage(Im, Ker, 'extend')
% Image will be padded with the value of the closest image pixel
% (useful for smoothing or blurring filters).
%
% ImOut = convImage(Im, Ker, 'partial')
% Image will not be padded. Borders will be convoluted with only valid pixels,
% and convolution matrix will be renormalized counting only the pixels within
% the image (also useful for smoothing or blurring filters).
%
% ImOut = convImage(Im, Ker, 'none')
% Image will not be padded. Convolution will only be applied to inner pixels
% (useful for edge and corner detection filters)
% Handle input
if mod(size(Ker, 1), 2) ~= 1 || mod(size(Ker, 2), 2) ~= 1
eid = sprintf('%s:evenRowsCols', mfilename);
error(eid,'''Ker'' parameter must have odd number of rows and columns.')
elseif nargin > 4
eid = sprintf('%s:maxrhs', mfilename);
error(eid, 'Too many input arguments.');
elseif nargin == 4 && ~strcmp(varargin{1}, 'value')
eid = sprintf('%s:invalidParameterCombination', mfilename);
error(eid, ['The ''padVal'' parameter is only valid with the ' ...
'''value'' option.'])
elseif nargin < 4 && strcmp(varargin{1}, 'value')
eid = sprintf('%s:minrhs', mfilename);
error(eid, 'Not enough input arguments.')
elseif nargin < 3
method = 'zeros';
else
method = lower(varargin{1});
if ~any(strcmp(method, {'zeros' 'value' 'extend' 'partial' 'none'}))
eid = sprintf('%s:invalidParameter', mfilename);
error(eid, 'Invalid option parameter. Must be one of:%s', ...
sprintf('\n\t\t%s', ...
'zeros', 'value', 'extend', 'partial', 'none'))
end
end
% Gather information and prepare for convolution
[nImRows, nImCols, nImLayers] = size(Im);
classIm = class(Im);
Im = double(Im);
ImOut = zeros(nImRows, nImCols, nImLayers);
[nKerRows, nKerCols] = size(Ker);
nPadRows = nImRows+nKerRows-1;
nPadCols = nImCols+nKerCols-1;
padH = (nKerRows-1)/2;
padW = (nKerCols-1)/2;
% Convolute on a layer-by-layer basis
for k = 1:nImLayers
if strcmp(method, 'zeros')
ImOut(:, :, k) = conv2(Im(:, :, k), Ker, 'same');
elseif strcmp(method, 'value')
padding = varargin{2}.*ones(nPadRows, nPadCols);
padding(padH+1:end-padH, padW+1:end-padW) = Im(:, :, k);
ImOut(:, :, k) = conv2(padding, Ker, 'valid');
elseif strcmp(method, 'extend')
padding = zeros(nPadRows, nPadCols);
padding(padH+1:end-padH, padW+1:end-padW) = Im(:, :, k); % Middle
padding(1:padH, 1:padW) = Im(1, 1, k); % TopLeft
padding(end-padH+1:end, 1:padW) = Im(end, 1, k); % BotLeft
padding(1:padH, end-padW+1:end) = Im(1, end, k); % TopRight
padding(end-padH+1:end, end-padW+1:end) = Im(end, end, k);% BotRight
padding(padH+1:end-padH, 1:padW) = ...
repmat(Im(:, 1, k), 1, padW); % Left
padding(padH+1:end-padH, end-padW+1:end) = ...
repmat(Im(:, end, k), 1, padW); % Right
padding(1:padH, padW+1:end-padW) = ...
repmat(Im(1, :, k), padH, 1); % Top
padding(end-padH+1:end, padW+1:end-padW) = ...
repmat(Im(end, :, k), padH, 1); % Bottom
ImOut(:, :, k) = conv2(padding, Ker, 'valid');
elseif strcmp(method, 'partial')
ImOut(padH+1:end-padH, padW+1:end-padW, k) = ...
conv2(Im(:, :, k), Ker, 'valid'); % Middle
unprocessed = true(nImRows, nImCols);
unprocessed(padH+1:end-padH, padW+1:end-padW) = false; % Border
for r = 1:nImRows
for c = 1:nImCols
if unprocessed(r, c)
limitedIm = Im(max(1, r-padH):min(nImRows, r+padH), ...
max(1, c-padW):min(nImCols, c+padW), k);
limitedKer = Ker(max(1, 2-r+padH): ...
min(nKerRows, nKerRows+nImRows-r-padH), ...
max(1, 2-c+padW):...
min(nKerCols, nKerCols+nImCols-c-padW));
limitedKer = limitedKer.*sum(Ker(:))./ ...
sum(limitedKer(:));
ImOut(r, c, k) = sum(sum(limitedIm.*limitedKer));
end
end
end
else % method is 'none'
ImOut(:, :, k) = Im(:, :, k);
ImOut(padH+1:end-padH, padW+1:end-padW, k) = ...
conv2(Im(:, :, k), Ker, 'valid');
end
end
% Convert back to former image data type
ImOut = cast(ImOut, classIm);
end</lang>
{{out}}
<pre>Original image:
1 2 1 5 5
1 2 7 9 9
5 5 5 5 5
5 2 2 2 2
1 1 1 1 1
 
Original kernal:
1 2 1
2 4 2
1 2 1
 
Padding with zeroes:
12 24 43 66 57
27 50 79 104 84
46 63 73 82 63
42 46 40 40 30
18 19 16 16 12
 
Padding with fives:
47 44 63 86 92
47 50 79 104 104
66 63 73 82 83
62 46 40 40 50
53 39 36 36 47
 
Duplicating border pixels to pad image:
20 30 52 82 96
35 50 79 104 112
62 63 73 82 84
58 46 40 40 40
29 23 20 20 20
 
Renormalizing kernal and using only values within image:
21.3333 32.0000 57.3333 88.0000 101.3333
36.0000 50.0000 79.0000 104.0000 112.0000
61.3333 63.0000 73.0000 82.0000 84.0000
56.0000 46.0000 40.0000 40.0000 40.0000
32.0000 25.3333 21.3333 21.3333 21.3333
 
Only processing inner (non-border) pixels:
1 2 1 5 5
1 50 79 104 9
5 63 73 82 5
5 46 40 40 2
1 1 1 1 1</pre>
 
=={{header|OCaml}}==
Anonymous user