## 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, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## -*- texinfo -*- ## @deftypefn {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}], @var{block_type}) ## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}]) ## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, 'indexed', ...) ## Rearranges image blocks into columns ## ## @code{B=im2col(A, [m, n], blocktype)} rearranges blocks in @var{A} ## into columns in a way that's determined by @var{block_type}, which ## can take the following values: ## ## @table @code ## @item distinct ## Rearranges each distinct @var{m}-by-@var{n} block in image @var{A} ## into a column of @var{B}. Blocks are scanned from left to right and ## the up to bottom in @var{A}, and columns are added to @var{B} from ## left to right. If @var{A}'s size is not multiple @var{m}-by-@var{n} ## it is padded. ## @item sliding ## Rearranges any @var{m}-by-@var{n} sliding block of @var{A} in a ## column of @var{B}, without any padding, so only sliding blocks which ## can be built using a full @var{m}-by-@var{n} neighbourhood are taken. ## In consequence, @var{B} has @var{m}*@var{n} rows and ## (@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) columns (where @var{mm} and ## @var{nn} are the size of @var{A}). ## ## This case is thought to be used applying operations on columns of ## @var{B} (for instance using sum(:)), so that result is a ## 1-by-(@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) vector, that is what ## the complementary function @code{col2im} expects. ## @end table ## ## @code{B=im2col(A,[m,n])} takes @code{distinct} as a default value for ## @var{block_type}. ## ## @code{B=im2col(A,'indexed',...)} will treat @var{A} as an indexed ## image, so it will pad using 1 if @var{A} is double. All other cases ## (incluing indexed matrices with uint8 and uint16 types and ## non-indexed images) will use 0 as padding value. ## ## Any padding needed in 'distinct' processing will be added at right ## and bottom edges of the image. ## ## @strong{Compatibility notes:} ## ## @itemize @bullet ## @item ## 'sliding' blocks are arranged into @var{B} in a top-down and ## left-right order. Since this isn't explicity described in MATLAB ## documentation, we ignore if it does it this way. It has been ## deduced because im2col implements inverse operation as a simple ## reshape (if we chose left to right and then up to down order we would ## had to transpose result). If you have MATLAB please check this ## issue. ## @item ## MATLAB docs say that when using @code{'indexed'}, padding with 0 is ## done for uint8 type. Since most functions do that too for uint16, we ## have chosen to use 0 also for uint16, even if documentation doesn't ## say it explicity, since it looks as an omission. ## @end itemize ## ## @end deftypefn ## @seealso{col2im} ## Author: Josep Mones i Teixidor function B = im2col(A, varargin) if(nargin<2 || nargin>4) usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); endif ## check 'indexed' presence indexed=false; p=1; if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) if(nargin<3) usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); endif indexed=true; p+=1; if(isa(A,"uint8") || isa(A,"uint16")) padval=0; else padval=1; endif else padval=0; endif ## check [m,n] if(!isvector(varargin{p})) error("im2col: expected [m,n] but param is not a vector."); endif if(length(varargin{p})!=2) error("im2col: expected [m,n] but param has wrong length."); endif m=varargin{p}(1); n=varargin{p}(2); p+=1; block_type='sliding'; if(nargin>p) ## we have block_type param if(!ischar(varargin{p})) error("im2col: invalid parameter block_type."); endif block_type=varargin{p}; p+=1; endif ## if we didn't have 'indexed' but had 4 parameters there's an error if(nargin>p) usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); endif ## common checks if(!ismatrix(A)) error("im2col: A should be a matrix (or vector)."); endif switch(block_type) case('distinct') ## calc needed padding sp=mod(-size(A)',[m;n]); if(any(sp)) A=padarray(A,sp,padval,'post'); endif ## iterate through all blocks B=[]; for i=1:m:size(A,1) ## up to bottom for j=1:n:size(A,2) ## left to right ## TODO: check if we can horzcat([],uint8([10;11])) in a ## future Octave version > 2.1.58 if(isempty(B)) B=A(i:i+m-1,j:j+n-1)(:); else B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); endif endfor endfor case('sliding') if(indexed) disp("WARNING: 'indexed' has no sense when using sliding."); endif if(m>size(A,1) || n>size(A,2)) error("im2col: block size can't be greater than image size in sliding"); endif ## TODO: check if matlab uses top-down and left-right order B=[]; for j=1:1:size(A,2)-n+1 ## left to right for i=1:1:size(A,1)-m+1 ## up to bottom ## TODO: check if we can horzcat([],uint8([10;11])) in a ## future Octave version > 2.1.58 if(isempty(B)) B=A(i:i+m-1,j:j+n-1)(:); else B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); endif endfor endfor otherwise error("im2col: invalid block_type."); endswitch endfunction %!demo %! A=[1:10;11:20;21:30;31:40] %! B=im2col(A,[2,5],'distinct') %! C=col2im(B,[2,5],[4,10],'distinct') %! # Divide A using distinct blocks and reverse operation %!shared B, A, Bs, As, Ap, Bp0, Bp1 %! v=[1:10]'; %! r=reshape(v,2,5); %! B=[v, v+10, v+20, v+30, v+40, v+50]; %! A=[r, r+10; r+20, r+30; r+40, r+50]; %! As=[1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]; %! b1=As(1:2,1:4)(:); %! b2=As(2:3,1:4)(:); %! b3=As(1:2,2:5)(:); %! b4=As(2:3,2:5)(:); %! Bs=[b1,b2,b3,b4]; %! Ap=A(:,1:9); %! Bp1=Bp0=B; %! Bp0([9:10],[2,4,6])=0; %! Bp1([9:10],[2,4,6])=1; %!# bad block_type %!error(im2col(A,[2,5],'wrong_block_type')); %!# distinct %!assert(im2col(A,[2,5],'distinct'), B); %!# padding %!assert(im2col(Ap,[2,5],'distinct'), Bp0); %!assert(im2col(Ap,'indexed',[2,5],'distinct'), Bp1); %!# now sliding %!assert(im2col(As,[2,4]), Bs); %!assert(im2col(As,[2,4],'sliding'), Bs); %!assert(im2col(As,[3,5],'sliding'), As(:)); %!# disctint uint8 & uint16 %!assert(im2col(uint8(A),[2,5],'distinct'), uint8(B)); %!assert(im2col(uint16(A),[2,5],'distinct'), uint16(B)); %!# padding uint8 & uint16 (to 0 even in indexed case) %!assert(im2col(uint8(Ap),[2,5],'distinct'), uint8(Bp0)); %!assert(im2col(uint8(Ap),'indexed',[2,5],'distinct'), uint8(Bp0)); %!assert(im2col(uint16(Ap),[2,5],'distinct'), uint16(Bp0)); %!assert(im2col(uint16(Ap),'indexed',[2,5],'distinct'), uint16(Bp0)); %!# now sliding uint8 & uint16 %!assert(im2col(uint8(As),[2,4],'sliding'), uint8(Bs)); %!assert(im2col(uint16(As),[2,4],'sliding'), uint16(Bs)); % % $Log: im2col.m,v $ % Revision 1.3 2005/09/08 02:00:17 pkienzle % [for Bill Denney] isstr -> ischar % % Revision 1.2 2004/09/03 17:37:08 jmones % Added support for int* and uint* types % % Revision 1.1 2004/08/18 14:39:07 jmones % im2col and col2im added % %