comparison main/image/inst/imtransform.m @ 11662:fbd81057dab0 octave-forge

image: new spatial transformation functions * maketform: accept input/output control points as second and third argument * imtransform: new function * findsbounds: new function * private/istform: add comment on what function does * NEWS/INDEX: update list of new functions
author carandraug
date Sun, 28 Apr 2013 02:31:13 +0000
parents
children 0f16ee5611b8
comparison
equal deleted inserted replaced
11661:1b4e81051b66 11662:fbd81057dab0
1 ## Copyright (C) 2012 Pantxo Diribarne
2 ##
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 3 of the License, or
6 ## (at your option) any later version.
7 ##
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ## GNU General Public License for more details.
12 ##
13 ## You should have received a copy of the GNU General Public License
14 ## along with Octave; see the file COPYING. If not, see
15 ## <http://www.gnu.org/licenses/>.
16
17 ## -*- texinfo -*-
18 ## @deftypefn {Function File} {@var{B} =} imtransform (@var{A}, @var{T})
19 ## @deftypefnx {Function File} {@var{B} =} imtransform (@var{A}, @var{T}, @var{interp})
20 ## @deftypefnx {Function File} {@var{B} =} imtransform (@dots{}, @var{prop}, @var{val})
21 ## Transform image.
22 ##
23 ## Given an image @var{A} in one space, returns an image @var{B}
24 ## resulting from the forward transform defined in the transformation
25 ## structure @var{T}. An additionnal input argument @var{interp},
26 ## 'bicubic', 'bilinear' (default) or 'nearest',
27 ## specifies the interpolation method to be used. Finally, the
28 ## transformation can be tuned using @var{prop}/@var{val} pairs. The
29 ## following properties are supported:
30 ##
31 ## @table @asis
32 ## @item "udata"
33 ## Specifies the input space horizontal limits. Value must be a two
34 ## elements vector [minval maxval]. Default: [1 columns(@var{A})]
35 ##
36 ## @item "vdata"
37 ## Specifies the input space vertical limits. Value must be a two
38 ## elements vector [minval maxval]. Default: [1 rows(@var{A})]
39 ##
40 ## @item "xdata"
41 ## Specifies the requiered output space horizontal limits. Value must
42 ## be a two elements vector [minval maxval]. Default: estimated using
43 ## udata, vdata and findbounds function.
44 ##
45 ## @item "ydata"
46 ## Specifies the requiered output space vertical limits. Value must
47 ## be a two elements vector [minval maxval]. Default: estimated using
48 ## udata, vdata and findbounds function.
49 ##
50 ## @item "xyscale"
51 ## Specifies the output scale in outputspace_units/pixel. If a scalar
52 ## is provided, both vertical and horizontal dimensions are scaled the
53 ## same way. If @var{val} is a two element vector, it must indicate
54 ## consecutively horizontal and vertical scales. Default value is
55 ## computed using the input space scale provided
56 ## that the number of pixel of any dimension of the output image does
57 ## not exceed 20000.
58 ##
59 ## @item "size"
60 ## Size of the output image (1-by-2 vector). Overrides the effect of
61 ## "xyscale" property.
62 ##
63 ## @item "fillvalues"
64 ## Color of the areas where no interpolation where possible, e.g. when
65 ## coorfinates of points in the output space are out of the limits of
66 ## the input space. @var{val} must be coherent with the input image
67 ## format: for grayscale and indexed images (2D) @var{val} must be
68 ## scalar, for RGB (n-by-m-by-3) @var{val} must be a 3 element vector.
69 ## e.g.:
70 ##
71 ## @end table
72 ##
73 ## @seealso{maketform, cp2tform, tforminv, tformfwd, findbounds}
74 ## @end deftypefn
75
76 ## Author: Pantxo Diribarne <pantxo@dibona>
77
78 function [varargout] = imtransform (im, T, varargin)
79
80 if (nargin < 2)
81 print_usage ();
82 elseif (! istform (T))
83 error ("imtransform: T must be a transformation structure (see `maketform')");
84 endif
85
86 ## Parameters
87 interp = "linear";
88 imdepth = size (im, 3);
89 maximsize = [20000 20000];
90
91 udata = [1; columns(im)];
92 vdata = [1; rows(im)];
93 xdata = ydata = [];
94 xyscale = [];
95 imsize = [];
96 fillvalues = ones (1, imdepth) * NaN;
97
98 if (isempty (varargin))
99 xydata = findbounds (T, [udata vdata]);
100 xdata = xydata(:,1);
101 ydata = xydata(:,2);
102 else
103 ## interp
104 if (floor (numel (varargin)/2) != numel (varargin)/2)
105 allowed = {"bicubic", "bilinear", "nearest"};
106 tst = strcmp (varargin{1}, allowed);
107 if (!any (tst))
108 error ("imtransform: expect one of %s as interp method", disp (allowed));
109 else
110 interp = {"pchip", "linear", "nearest"}{find (tst)};
111 endif
112 varargin = varargin(2:end);
113 endif
114
115 ## options
116 allowed = {"udata", "vdata", "xdata", "ydata", ...
117 "xyscale", "size", "fillvalues"};
118 props = varargin(1:2:end);
119 vals = varargin(2:2:end);
120 np = numel (props);
121 if (!all (cellfun (@ischar, props)))
122 error ("imtransform: expect property/value pairs.");
123 endif
124
125 props = tolower (props);
126 tst = cellfun (@(x) any (strcmp (x, allowed)), props);
127 if (!all (tst))
128 error ("imtransform: unknown property %s", disp (props{!tst}));
129 endif
130
131 ## u(vxy)data
132 iolims = allowed(1:4);
133 for ii = 1:numel (iolims)
134 tst = cellfun (@(x) any (strcmp (x, iolims{ii})), props);
135 if (any (tst))
136 prop = props{find (tst)(1)};
137 val = vals{find (tst)(1)};
138 if (isnumeric (val) && numel (val) == 2)
139 if (isrow (val))
140 val = val';
141 endif
142 eval (sprintf ("%s = val;", prop),
143 "error (\"imtransform: %s\n\", lasterr ());");
144 else
145 error ("imtransform: expect 2 elements real vector for %s", prop)
146 endif
147 endif
148 endfor
149 if (isempty (xdata) && isempty (ydata))
150 xydata = findbounds (T, [udata vdata]);
151 xdata = xydata(:,1);
152 ydata = xydata(:,2);
153 elseif (isempty (xdata))
154 xydata = findbounds (T, [udata vdata]);
155 xdata = xydata(:,1);
156 elseif (isempty (ydata))
157 xydata = findbounds (T, [udata vdata]);
158 ydata = xydata(:,2);
159 endif
160
161 ## size and xyscale
162 tst = strcmp ("size", props);
163 if (any (tst))
164 val = vals{find (tst)(1)};
165 if (isnumeric (val) && numel (val) == 2 &&
166 all (val > 0))
167 imsize = val;
168 else
169 error ("imtransform: expect 2 elements real vector for size");
170 endif
171 elseif (any (tst = strcmp ("xyscale", props)))
172 val = vals{find (tst)(1)};
173 if (isnumeric (val) && all (val > 0))
174 if (numel (val) == 1)
175 xyscale(1:2) = val;
176 elseif (numel (val) == 2)
177 xyscale = val;
178 else
179 error ("imtransform: expect 1 or 2 element(s) real vector for xyscale");
180 endif
181 else
182 error ("imtransform: expect 1 or 2 elements real vector for xyscale");
183 endif
184 else
185 xyscale = [(diff (udata) / columns (im)) (diff (vdata) / rows (im))];
186 endif
187
188 ## Fillvalues
189 tst = strcmp ("fillvalues", props);
190 if (any (tst))
191 val = vals{find (tst)(1)};
192 if (isnumeric (val) && numel (val) == 1)
193 fillvalues(1:end) = val;
194 elseif (isnumeric (val) && numel (val) == 3)
195 fillvalues = val;
196 else
197 error ("imtransform: expect 1 or 3 elements real vector for `fillvalues'");
198 endif
199 endif
200 endif
201
202 ## Ouput/Input pixels
203 if (isempty (imsize))
204 if (isempty (xyscale))
205 xyscale = [(diff (udata) / columns (im)) (diff (vdata) / rows (im))];
206 endif
207 xscale = xyscale(1);
208 yscale = xyscale(2);
209 xsize = floor (diff (xdata) / xscale);
210 ysize = floor (diff (ydata) / yscale);
211 if (xsize > maximsize(2) || ysize > maximsize(1))
212 if (xsize >= ysize)
213 scalefactor = (diff (xdata) / maximsize(2)) / xscale;
214 else
215 scalefactor = (diff (ydata) / maximsize(1)) / yscale;
216 endif
217 xscale *= scalefactor
218 yscale *= scalefactor
219 xsize = floor (diff (xdata) / xscale);
220 ysize = floor (diff (ydata) / yscale);
221 warning ("imtransform: output image two large, adjusting the largest dimension to %d", maximsize);
222 endif
223 imsize = [ysize xsize];
224 endif
225 [xx yy] = meshgrid (linspace (xdata(1), xdata(2), imsize(2)),
226 linspace (ydata(1), ydata(2), imsize(1)));
227
228 [uu vv] = meshgrid (linspace (udata(1), udata(2), size(im)(2)),
229 linspace (vdata(1), vdata(2), size(im)(1)));
230
231 ## Input coordinates
232 [uui, vvi] = tforminv (T, reshape (xx, numel (xx), 1),
233 reshape (yy, numel (yy), 1));
234 uui = reshape (uui, size (xx));
235 vvi = reshape (vvi, size (yy));
236 ## Interpolation
237 for layer = 1:imdepth
238 imout(:,:,layer) = interp2 (uu, vv, im(:,:,layer), ...
239 uui, vvi, interp, fillvalues(layer));
240 endfor
241 if (nargout == 1)
242 varargout{1} = imout;
243 else
244 varargout = {imout, xdata, ydata};
245 endif
246 endfunction
247
248 %!demo
249 %! ## Various linear transforms
250 %! figure ();
251 %! im = [checkerboard(20, 2, 4); checkerboard(40, 1, 2)];
252 %! %input space corners
253 %! incp = [1 1; 160 1; 160 160; 1 160];
254 %! udata = [min(incp(:,1)) max(incp(:,1))];
255 %! vdata = [min(incp(:,2)) max(incp(:,2))];
256 %! subplot (2,3,1);
257 %! imshow (im)
258 %! hold on
259 %! plot (incp(:,1), incp(:,2), 'ob')
260 %! axis on
261 %! xlabel ('Original')
262 %!
263 %! % Translation and scaling
264 %! outcp = incp * 2;
265 %! outcp(:,1) += 200;
266 %! outcp(:,2) += 500;
267 %! T = maketform ('affine', incp(1:3,:), outcp(1:3,:));
268 %! subplot (2,3,2);
269 %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata,
270 %! 'vdata', vdata, 'fillvalues', 1);
271 %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata)
272 %! set (gca, 'xlim', xdata, 'ylim', ydata)
273 %! axis on, hold on, xlabel ('Translation / Scaling');
274 %! plot (outcp(:,1), outcp(:,2), 'or')
275 %!
276 %! % Shear
277 %! outcp = [1 1; 160 1; 140 160; -19 160]; % affine only needs 3 control points
278 %! T = maketform ('affine', incp(1:3,:), outcp(1:3,:));
279 %! subplot (2,3,3);
280 %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata,
281 %! 'vdata', vdata, 'fillvalues', 1);
282 %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata)
283 %! set (gca, 'xlim', xdata, 'ylim', ydata)
284 %! axis on, hold on, xlabel ('Shear');
285 %! plot (outcp(:,1), outcp(:,2), 'or')
286 %!
287 %! % Rotation
288 %! theta = pi/4;
289 %! T = maketform ('affine', [cos(theta) -sin(theta); ...
290 %! sin(theta) cos(theta); 0 0]);
291 %! outcp = tformfwd (T, incp);
292 %! subplot (2,3,4);
293 %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata,
294 %! 'vdata', vdata, 'fillvalues', 1 );
295 %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata)
296 %! set (gca, 'xlim', xdata, 'ylim', ydata)
297 %! axis on, hold on, xlabel ('Rotation');
298 %! plot (outcp(:,1), outcp(:,2), 'or')
299 %!
300 %! % Reflection around x axis
301 %! outcp = incp;
302 %! outcp(:,2) *= -1;
303 %! T = cp2tform (incp, outcp, 'similarity');
304 %! subplot (2,3,5);
305 %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata,
306 %! 'vdata', vdata, 'fillvalues', 1 );
307 %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata)
308 %! set (gca, 'xlim', xdata, 'ylim', ydata)
309 %! axis on, hold on, xlabel ('Reflection');
310 %! plot (outcp(:,1), outcp(:,2), 'or')
311 %!
312 %! % Projection
313 %! outcp = [1 1; 160 -40; 220 220; 12 140];
314 %! T = maketform ('projective', incp, outcp);
315 %! subplot (2,3,6);
316 %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata,
317 %! 'vdata', vdata, 'fillvalues', 1 );
318 %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata)
319 %! set (gca, 'xlim', xdata, 'ylim', ydata)
320 %! axis on, hold on, xlabel ('Projection');
321 %! plot (outcp(:,1), outcp(:,2), 'or')
322
323 %!demo
324 %! ## Streched image
325 %! rad = 2; % minimum value: 4/pi
326 %! [uu vv] = meshgrid ((-2:2)/rad, (-2:2)/rad);
327 %! rescfactor = sin ((uu.^2 + vv.^2).^.5);
328 %! inpts = [(reshape (uu, numel (uu), 1)), (reshape (vv, numel (uu), 1))];
329 %! xx = rescfactor .* sign(uu);
330 %! yy = rescfactor .* sign(vv);
331 %! outpts = [reshape(xx, numel (xx), 1) reshape(yy, numel (yy), 1)];
332 %!
333 %! T = cp2tform (inpts, outpts, "polynomial", 4);
334 %! figure;
335 %! subplot (1,2,1)
336 %! im = zeros (800, 800, 3);
337 %! im(:,:,1) = checkerboard (100) > 0.2;
338 %! im(:,:,3) = checkerboard (100) < 0.2;
339 %! [im2 xdata ydata] = imtransform (im, T, 'udata', [-2 2],
340 %! 'vdata', [-2 2], 'fillvalues',
341 %! [0 1 0]);
342 %! imh = imshow (im2);
343 %! set (imh, 'xdata', xdata, 'ydata', ydata)
344 %! set (gca, 'xlim', xdata, 'ylim', ydata)
345 %! [im cmap] = imread ('default.img');
346 %! subplot (1,2,2)
347 %! [im2 xdata ydata] = imtransform (im, T, 'udata', [-1 1],
348 %! 'vdata', [-1 1], 'fillvalues',
349 %! round (length (cmap) / 2));
350 %! imh = imshow (im2, cmap);