Mercurial > hg > camir-aes2014
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 |