X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?p=CreaPhase.git;a=blobdiff_plain;f=octave_packages%2Fimage-1.0.15%2Fpadarray.m;fp=octave_packages%2Fimage-1.0.15%2Fpadarray.m;h=4632c402fd1c5471111015ccc19fe80e071c7bb6;hp=0000000000000000000000000000000000000000;hb=f5f7a74bd8a4900f0b797da6783be80e11a68d86;hpb=1705066eceaaea976f010f669ce8e972f3734b05 diff --git a/octave_packages/image-1.0.15/padarray.m b/octave_packages/image-1.0.15/padarray.m new file mode 100644 index 0000000..4632c40 --- /dev/null +++ b/octave_packages/image-1.0.15/padarray.m @@ -0,0 +1,374 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see . + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } padarray (@var{A},@var{padsize}) +## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval}) +## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval},@var{direction}) +## Pads an array in a configurable way. +## +## B = padarray(A,padsize) pads an array @var{A} with zeros, where +## @var{padsize} defines the amount of padding to add in each dimension +## (it must be a vector of positive integers). +## +## Each component of @var{padsize} defines the number of elements of +## padding that will be added in the corresponding dimension. For +## instance, [4,5] adds 4 elements of padding in first dimension (vertical) +## and 5 in second dimension (horizontal). +## +## B = padarray(A,padsize,padval) pads @var{A} using the value specified +## by @var{padval}. @var{padval} can be a scalar or a string. Possible +## values are: +## +## @table @asis +## @item 0 +## Pads with 0 as described above. This is the default behaviour. +## @item Scalar +## Pads using @var{padval} as a padding value. +## @item "Circular" +## Pads with a circular repetition of elements in @var{A} (similar to +## tiling @var{A}). +## @item "Replicate" +## Pads replicating values of @var{A} which are at the border of the +## array. +## @item "Symmetric" +## Pads with a mirror reflection of @var{A}. +## @item "Reflect" +## Same as "symmetric", but the borders are not used in the padding. +## @end table +## +## B = padarray(A,padsize,padval,direction) pads @var{A} defining the +## direction of the pad. Possible values are: +## +## @table @asis +## @item "Both" +## For each dimension it pads before the first element the number +## of elements defined by @var{padsize} and the same number again after +## the last element. This is the default value. +## @item "Pre" +## For each dimension it pads before the first element the number of +## elements defined by @var{padsize}. +## @item "Post" +## For each dimension it pads after the last element the number of +## elements defined by @var{padsize}. +## @end table +## @end deftypefn + +## Author: Josep Mones i Teixidor + +function B = padarray(A, padsize, padval = 0, direction = "both") + # Check parameters + if (nargin < 2 || nargin > 4) + print_usage(); + endif + + if (!isvector(padsize) || !isnumeric(padsize) || any(padsize < 0) || any(padsize != round(padsize))) + error("padarray: padsize must be a vector of positive integers."); + endif + if (!isscalar(padval) && !ischar(padval)) + error("padarray: third input argument must be a string or a scalar"); + endif + if (!ischar(direction) || strcmpi(direction, {"pre", "post", "both"})) + error("padarray: fourth input argument must be 'pre', 'post', or 'both'"); + endif + + ## Assure padsize is a row vector + padsize = padsize(:).'; + + # Check direction + pre = any(strcmpi(direction, {"pre", "both"})); + post = any(strcmpi(direction, {"post", "both"})); + + B = A; + dim = 1; + for s = padsize + if (s > 0) + # padding in this dimension was requested + ds = size(B); + ds = [ds, ones(1,dim-length(ds))]; # data size + ps = ds; + ps(dim) = s; # padding size + + if (ischar(padval)) + # Init a "index all" cell array. All cases need it. + idx = cell(1, length(ds)); + for i = 1:length(ds) + idx{i} = 1:ds(i); + endfor + + switch (padval) + case ("circular") + complete = 0; + D = B; + if (ps(dim) > ds(dim)) + complete = floor(ps(dim)/ds(dim)); + ps(dim) = rem(ps(dim), ds(dim)); + endif + if (pre) + for i = 1:complete + B = cat(dim, D, B); + endfor + idxt = idx; + idxt{dim} = ds(dim)-ps(dim)+1:ds(dim); + B = cat(dim, D(idxt{:}), B); + endif + if (post) + for i = 1:complete + B = cat(dim, B, D); + endfor + idxt = idx; + idxt{dim} = 1:ps(dim); + B = cat(dim, B, D(idxt{:})); + endif + # end circular case + + case ("replicate") + if (pre) + idxt = idx; + idxt{dim} = 1; + pad = B(idxt{:}); + # can we do this without the loop? + for i = 1:s + B = cat(dim, pad, B); + endfor + endif + if (post) + idxt = idx; + idxt{dim} = size(B, dim); + pad = B(idxt{:}); + for i = 1:s + B = cat(dim, B, pad); + endfor + endif + # end replicate case + + case ("symmetric") + if (ps(dim) > ds(dim)) + error("padarray: padding is longer than data using symmetric padding"); + endif + if (pre) + idxt = idx; + idxt{dim} = ps(dim):-1:1; + B = cat(dim, B(idxt{:}), B); + endif + if (post) + idxt = idx; + sbd = size(B, dim); + idxt{dim} = sbd:-1:sbd-ps(dim)+1; + B = cat(dim, B, B(idxt{:})); + endif + # end symmetric case + + case ("reflect") + if (ps(dim) > ds(dim)-1) + error("padarray: padding is longer than data using 'reflect' padding"); + endif + if (pre) + idxt = idx; + idxt{dim} = (ps(dim):-1:1) + 1; + B = cat(dim, B(idxt{:}), B); + endif + if (post) + idxt = idx; + sbd = size(B, dim)-1; + idxt{dim} = sbd:-1:sbd-ps(dim)+1; + B = cat(dim,B,B(idxt{:})); + endif + # end reflect case + + otherwise + error("padarray: invalid string in padval parameter."); + + endswitch + # end cases where padval is a string + + elseif (isscalar(padval)) + # Handle fixed value padding + if (padval == 0) + pad = zeros(ps, class(A)); ## class(pad) = class(A) + else + pad = padval*ones(ps, class(A)); ## class(pad) = class(A) + endif + if (pre && post) + # check if this is not quicker than just 2 calls (one for each) + B = cat(dim, pad, B, pad); + elseif (pre) + B = cat(dim, pad, B); + elseif (post) + B = cat(dim, B, pad); + endif + endif + endif + dim+=1; + endfor +endfunction + +%!demo +%! padarray([1,2,3;4,5,6],[2,1]) +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 0 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],5) +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 5 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],0,'pre') +%! % pads [1,2,3;4,5,6] with a left and top border of 2 rows and 1 columns of 0 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'circular') +%! % pads [1,2,3;4,5,6] with a whole 'circular' border of 2 rows and 1 columns +%! % border 'repeats' data as if we tiled blocks of data + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'replicate') +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which +%! % 'replicates' edge data + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'symmetric') +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which +%! % is symmetric to the data on the edge + +% Test default padval and direction +%!assert(padarray([1;2],[1]), [0;1;2;0]); +%!assert(padarray([3,4],[0,2]), [0,0,3,4,0,0]); +%!assert(padarray([1,2,3;4,5,6],[1,2]), \ +%! [zeros(1,7);0,0,1,2,3,0,0;0,0,4,5,6,0,0;zeros(1,7)]); + +% Test padding on 3D array +%!test +%! int8(0); % fail for octave <= 2.1.57 without crashing +%! assert(padarray([1,2,3;4,5,6],[3,2,1]), cat(3, \ +%! zeros(8,7), \ +%! [zeros(3,7); [zeros(2,2), [1,2,3;4,5,6], zeros(2,2)]; zeros(3,7)], \ +%! zeros(8,7))); + +% Test if default param are ok +%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0)); +%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0,'both')); + +% Test literal padval +%!assert(padarray([1;2],[1],i), [i;1;2;i]); + +% Test directions (horizontal) +%!assert(padarray([1;2],[1],i,'pre'), [i;1;2]); +%!assert(padarray([1;2],[1],i,'post'), [1;2;i]); +%!assert(padarray([1;2],[1],i,'both'), [i;1;2;i]); + +% Test directions (vertical) +%!assert(padarray([1,2],[0,1],i,'pre'), [i,1,2]); +%!assert(padarray([1,2],[0,1],i,'post'), [1,2,i]); +%!assert(padarray([1,2],[0,1],i,'both'), [i,1,2,i]); + +% Test vertical padsize +%!assert(padarray([1,2],[0;1],i,'both'), [i,1,2,i]); + +% Test circular padding +%!test +%! A=[1,2,3;4,5,6]; +%! B=repmat(A,7,9); +%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); +%! % This tests when padding is bigger than data +%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); + +% Test replicate padding +%!test +%! A=[1,2;3,4]; +%! B=kron(A,ones(10,5)); +%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); +%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); +%! assert(padarray(A,[9,4],'replicate','both'), B); + +% Test symmetric padding +%!test +%! A=[1:3;4:6]; +%! HA=[3:-1:1;6:-1:4]; +%! VA=[4:6;1:3]; +%! VHA=[6:-1:4;3:-1:1]; +%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; +%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); + +% Repeat some tests with int* uint* class types +%!assert(padarray(int8([1;2]),[1]), int8([0;1;2;0])); +%!assert(padarray(uint8([3,4]),[0,2]), uint8([0,0,3,4,0,0])); +%!assert(padarray(int16([1;2]),[1],4), int16([4;1;2;4])); +%!assert(padarray(uint16([1;2]),[1],0), uint16([0;1;2;0])); +%!assert(padarray(int32([1;2]),[1],int32(4),'pre'), int32([4;1;2])); +%!assert(padarray(uint32([1;2]),[1],6,'post'), uint32([1;2;6])); + +% Test circular padding with int* uint* class types +%!test +%! A=int8([1,2,3;4,5,6]); +%! B=repmat(A,7,9); +%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); +%! % This tests when padding is bigger than data +%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); + +% Test replicate padding with int* uint* class types +%!test +%! A=uint8([1,2;3,4]); +%! B=[ones(10,5,"uint8")*1,ones(10,5,"uint8")*2; \ +%! ones(10,5,"uint8")*3,ones(10,5,"uint8")*4]; +%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); +%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); +%! assert(padarray(A,[9,4],'replicate','both'), B); + +% Test symmetric padding with int* uint* class types +%!test +%! A=int16([1:3;4:6]); +%! HA=int16([3:-1:1;6:-1:4]); +%! VA=int16([4:6;1:3]); +%! VHA=int16([6:-1:4;3:-1:1]); +%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; +%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); + + + +% +% $Log$ +% Revision 1.2 2007/03/23 16:14:37 adb014 +% Update the FSF address +% +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.6 2005/09/08 02:00:17 pkienzle +% [for Bill Denney] isstr -> ischar +% +% Revision 1.5 2004/09/03 18:33:11 pkienzle +% skip tests which use cat(3,X,Y) for octave <= 2.1.57 +% +% Revision 1.4 2004/09/03 13:37:10 jmones +% Corrected behaviour for int* and uint* types +% +% Revision 1.3 2004/08/15 19:21:50 jmones +% support column vector padsize +% +% Revision 1.2 2004/08/11 15:04:59 pkienzle +% Convert dos line endings to unix line endings +% +% Revision 1.1 2004/08/08 21:20:25 jmones +% uintlut and padarray functions added +% +%