comparison toolboxes/MIRtoolbox1.3.2/MIRToolbox/convolve2.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e9a9cd732c1e
1 function y = convolve2(x, m, shape, tol)
2 %CONVOLVE2 Two dimensional convolution.
3 % Y = CONVOLVE2(X, M) performs the 2-D convolution of matrices X and
4 % M. If [mx,nx] = size(X) and [mm,nm] = size(M), then size(Y) =
5 % [mx+mm-1,nx+nm-1]. Values near the boundaries of the output array are
6 % calculated as if X was surrounded by a border of zero values.
7 %
8 % Y = CONVOLVE2(X, M, SHAPE) where SHAPE is a string returns a
9 % subsection of the 2-D convolution with size specified by SHAPE:
10 %
11 % 'full' - (default) returns the full 2-D convolution,
12 % 'same' - returns the central part of the convolution
13 % that is the same size as A (using zero padding),
14 % 'valid' - returns only those parts of the convolution
15 % that are computed without the zero-padded
16 % edges, size(Y) = [mx-mm+1,nx-nm+1] when
17 % size(X) > size(M),
18 % 'wrap' - as for 'same' except that instead of using
19 % zero-padding the input A is taken to wrap round as
20 % on a toroid.
21 % 'reflect' - as for 'same' except that instead of using
22 % zero-padding the input A is taken to be reflected
23 % at its boundaries.
24 %
25 % CONVOLVE2 is fastest when mx > mm and nx > nm - i.e. the first
26 % argument is the input and the second is the mask.
27 %
28 % If the rank of the mask M is low, CONVOLVE2 will decompose it into a
29 % sum of outer product masks, each of which is applied efficiently as
30 % convolution with a row vector and a column vector, by calling CONV2.
31 % The function will often be faster than CONV2 or FILTER2 (in some
32 % cases much faster) and will produce the same results as CONV2 to
33 % within a small tolerance.
34 %
35 % Y = CONVOLVE2(... , TOL) where TOL is a number in the range 0.0 to
36 % 1.0 computes the convolution using a reduced-rank approximation to
37 % M, provided this will speed up the computation. TOL limits the
38 % relative sum-squared error in the effective mask; that is, if the
39 % effective mask is E, the error is controlled such that
40 %
41 % sum(sum( (M-E) .* (M-E) ))
42 % -------------------------- <= TOL
43 % sum(sum( M .* M ))
44 %
45 % See also CONV2, FILTER2.
46
47 % David Young, Department of Informatics, University of Sussex, February 2002,
48 % revised January 2005.
49
50 % Deal with optional arguments
51 error(nargchk(2,4,nargin));
52 if nargin < 3
53 shape = 'full'; % shape default as for CONV2
54 tol = 0;
55 elseif nargin < 4
56 if isnumeric(shape)
57 tol = shape;
58 shape = 'full';
59 else
60 tol = 0;
61 end
62 end;
63
64 % Set up to do the wrap & reflect operations, not handled by conv2
65 if strcmp(shape, 'wrap')
66 x = wraparound(x, m);
67 shape = 'valid';
68 elseif strcmp(shape, 'reflect')
69 x = reflectborders(x, m);
70 shape = 'valid';
71 end
72
73 % do the convolution itself
74 y = doconv(x, m, shape, tol);
75
76 %-----------------------------------------------------------------------
77
78 function y = doconv(x, m, shape, tol);
79 % Carry out convolution
80 [mx, nx] = size(x);
81 [mm, nm] = size(m);
82
83 % If the mask is bigger than the input, or it is 1-D already,
84 % just let CONV2 handle it.
85 if mm > mx | nm > nx | mm == 1 | nm == 1
86 y = conv2(x, m, shape);
87 else
88 % Get svd of mask
89 if mm < nm; m = m'; end % svd(..,0) wants m > n
90 [u,s,v] = svd(m, 0);
91 s = diag(s);
92 rank = trank(m, s, tol);
93 if rank*(mm+nm) < mm*nm % take advantage of low rank
94 if mm < nm; t = u; u = v; v = t; end % reverse earlier transpose
95 vp = v';
96 % For some reason, CONV2(H,C,X) is very slow, so use the normal call
97 y = conv2(conv2(x, u(:,1)*s(1), shape), vp(1,:), shape);
98 for r = 2:rank
99 y = y + conv2(conv2(x, u(:,r)*s(r), shape), vp(r,:), shape);
100 end
101 else
102 if mm < nm; m = m'; end % reverse earlier transpose
103 y = conv2(x, m, shape);
104 end
105 end
106
107 %-----------------------------------------------------------------------
108
109 function r = trank(m, s, tol)
110 % Approximate rank function - returns rank of matrix that fits given
111 % matrix to within given relative rms error. Expects original matrix
112 % and vector of singular values.
113 if tol < 0 | tol > 1
114 error('Tolerance must be in range 0 to 1');
115 end
116 if tol == 0 % return estimate of actual rank
117 tol = length(m) * max(s) * eps;
118 r = sum(s > tol);
119 else
120 ss = s .* s;
121 t = (1 - tol) * sum(ss);
122 r = 0;
123 sm = 0;
124 while sm < t
125 r = r + 1;
126 sm = sm + ss(r);
127 end
128 end
129
130 %-----------------------------------------------------------------------
131
132 function y = wraparound(x, m)
133 % Extend x so as to wrap around on both axes, sufficient to allow a
134 % "valid" convolution with m to return the cyclical convolution.
135 % We assume mask origin near centre of mask for compatibility with
136 % "same" option.
137 [mx, nx] = size(x);
138 [mm, nm] = size(m);
139 if mm > mx | nm > nx
140 error('Mask does not fit inside array')
141 end
142
143 mo = floor((1+mm)/2); no = floor((1+nm)/2); % reflected mask origin
144 ml = mo-1; nl = no-1; % mask left/above origin
145 mr = mm-mo; nr = nm-no; % mask right/below origin
146 me = mx-ml+1; ne = nx-nl+1; % reflected margin in input
147 mt = mx+ml; nt = nx+nl; % top of image in output
148 my = mx+mm-1; ny = nx+nm-1; % output size
149
150 y = zeros(my, ny);
151 y(mo:mt, no:nt) = x; % central region
152 if ml > 0
153 y(1:ml, no:nt) = x(me:mx, :); % top side
154 if nl > 0
155 y(1:ml, 1:nl) = x(me:mx, ne:nx); % top left corner
156 end
157 if nr > 0
158 y(1:ml, nt+1:ny) = x(me:mx, 1:nr); % top right corner
159 end
160 end
161 if mr > 0
162 y(mt+1:my, no:nt) = x(1:mr, :); % bottom side
163 if nl > 0
164 y(mt+1:my, 1:nl) = x(1:mr, ne:nx); % bottom left corner
165 end
166 if nr > 0
167 y(mt+1:my, nt+1:ny) = x(1:mr, 1:nr); % bottom right corner
168 end
169 end
170 if nl > 0
171 y(mo:mt, 1:nl) = x(:, ne:nx); % left side
172 end
173 if nr > 0
174 y(mo:mt, nt+1:ny) = x(:, 1:nr); % right side
175 end
176
177 %-----------------------------------------------------------------------
178
179 function y = reflectborders(x, m)
180 % Extend x so as to reflect at each boundary, sufficient to allow a
181 % "valid" convolution with m to return a matrix the same size as
182 % the orginal.
183 % We assume mask origin near centre of mask for compatibility with
184 % "same" option.
185 [mx, nx] = size(x);
186 [mm, nm] = size(m);
187 if mm > mx | nm > nx
188 error('Mask does not fit inside array')
189 end
190
191 mo = floor((1+mm)/2); no = floor((1+nm)/2); % reflected mask origin
192 ml = mo-1; nl = no-1; % mask left/above origin
193 mr = mm-mo; nr = nm-no; % mask right/below origin
194 me = mx-mr+1; ne = nx-nr+1; % translated margin in input
195 mt = mx+ml; nt = nx+nl; % top/right of image in output
196 my = mx+mm-1; ny = nx+nm-1; % output size
197
198 y = zeros(my, ny);
199 y(mo:mt, no:nt) = x; % central region
200 if ml > 0
201 y(1:ml, no:nt) = x(ml:-1:1, :); % top side
202 if nl > 0
203 y(1:ml, 1:nl) = x(ml:-1:1, nl:-1:1); % top left corner
204 end
205 if nr > 0
206 y(1:ml, nt+1:ny) = x(ml:-1:1, nx:-1:ne); % top right corner
207 end
208 end
209 if mr > 0
210 y(mt+1:my, no:nt) = x(mx:-1:me, :); % bottom side
211 if nl > 0
212 y(mt+1:my, 1:nl) = x(mx:-1:me, nl:-1:1); % bottom left corner
213 end
214 if nr > 0
215 y(mt+1:my, nt+1:ny) = x(mx:-1:me, nx:-1:ne); % bottom right corner
216 end
217 end
218 if nl > 0
219 y(mo:mt, 1:nl) = x(:, nl:-1:1); % left side
220 end
221 if nr > 0
222 y(mo:mt, nt+1:ny) = x(:, nx:-1:ne); % right side
223 end