1## Copyright (C) 2005 Søren Hauberg <soren@hauberg.org> 2## Copyright (C) 2013 Carnë Draug <carandraug@octave.org> 3## 4## This program is free software; you can redistribute it and/or modify it under 5## the terms of the GNU General Public License as published by the Free Software 6## Foundation; either version 3 of the License, or (at your option) any later 7## version. 8## 9## This program is distributed in the hope that it will be useful, but WITHOUT 10## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12## details. 13## 14## You should have received a copy of the GNU General Public License along with 15## this program; if not, see <http://www.gnu.org/licenses/>. 16 17## -*- texinfo -*- 18## @deftypefn {Function File} {} imresize (@var{im}, @var{scale}) 19## @deftypefnx {Function File} {} imresize (@var{im}, [@var{M} @var{N}]) 20## @deftypefnx {Function File} {} imresize (@dots{}, @var{method}) 21## Resize image with interpolation 22## 23## Scales the image @var{im} by a factor @var{scale} or into the size @var{M} 24## rows by @var{N} columns. For example: 25## 26## @example 27## @group 28## imresize (im, 1); # return the same image as input 29## imresize (im, 1.5); # return image 1.5 times larger 30## imresize (im, 0.5); # return image with half the size 31## imresize (im, 2); # return image with the double size 32## imresize (im, [512 610]); # return image of size 512x610 33## @end group 34## @end example 35## 36## If @var{M} or @var{N} is @code{NaN}, it will be determined automatically so 37## as to preserve aspect ratio. 38## 39## The optional argument @var{method} defines the interpolation method to be 40## used. All methods supported by @code{interp2} can be used. By default, the 41## @code{cubic} method is used. 42## 43## For @sc{matlab} compatibility, the methods @code{bicubic} (same as 44## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as 45## @code{linear}) are also supported. 46## 47## @table @asis 48## @item bicubic (default) 49## Same as @code{cubic}. 50## 51## @item bilinear 52## Same as @code{linear}. 53## 54## @item triangle 55## Same as @code{linear}. 56## @end table 57## 58## @seealso{imremap, imrotate, interp2} 59## @end deftypefn 60 61function im = imresize (im, scale, method = "cubic") 62 63 if (nargin < 2 || nargin > 3) 64 print_usage (); 65 elseif (! isimage (im)) 66 error ("imresize: IM must be an image") 67 elseif (! isnumeric (scale) || any (scale <= 0) || all (isnan (scale))) 68 error ("imresize: SCALE or [M N] must be numeric positive values") 69 elseif (! ischar (method)) 70 error ("imresize: METHOD must be a string with interpolation method") 71 endif 72 method = interp_method (method); 73 74 inRows = rows (im); 75 inCols = columns (im); 76 77 ## we may be able to use clever indexing instead of interpolation 78 int_row_scale = false; 79 int_col_scale = false; 80 if (isscalar (scale)) 81 outRows = ceil (rows (im) * scale); 82 outCols = ceil (columns (im) * scale); 83 84 ## check if we can use clever indexing 85 scale_rows = scale_cols = scale; 86 int_row_scale = int_col_scale = is_for_integer (scale); 87 elseif (numel (scale) == 2) 88 outRows = scale(1); 89 outCols = scale(2); 90 ## maintain aspect ratio if requested 91 if (isnan (outRows)) 92 outRows = inRows * (outCols / inCols); 93 elseif (isnan (outCols)) 94 outCols = inCols * (outRows / inRows); 95 endif 96 outRows = ceil (outRows); 97 outCols = ceil (outCols); 98 99 ## we will need this to use clever indexing. In this case, we will also need 100 ## to check that we are changing the rows and columns of the image in the 101 ## same direction 102 scale_rows = (outRows/inRows); 103 scale_cols = (outCols/inCols); 104 int_row_scale = is_for_integer (scale_rows); 105 int_col_scale = is_for_integer (scale_cols); 106 else 107 error ("imresize: SCALE argument must be a scalar or a 2 element vector"); 108 end 109 110 ## Perform the actual resizing 111 if (inRows == outRows && inCols == outCols) 112 ## no resizing to do 113 elseif (strcmpi (method, "nearest") && all ([int_row_scale int_col_scale])) 114 ## we are matlab incompatible here on purpose. We can the stuff here in 2 115 ## ways. With interp2 or by clever indexing. Indexing is much much faster 116 ## than interp2 but they return different results (the way we are doing it 117 ## at least). Matlab does the same as we are doing if the both columns and 118 ## rows go the same direction but if they increase one and decrease the 119 ## other, then they return the same as if we were using interp2. We are 120 ## smarter and use indexing even in that case but then the results differ 121 if (int_row_scale == 1) 122 row_idx = (1:rows (im))(ones (1, scale_rows), :); 123 elseif (int_row_scale == -1) 124 row_idx = ceil (linspace (floor (1/(scale_rows * 2)) + 1, inRows, outRows)); 125 endif 126 if (int_col_scale == 1) 127 col_idx = (1:columns (im))(ones (scale_cols, 1), :); 128 elseif (int_col_scale == -1) 129 col_idx = ceil (linspace (floor (1/(scale_cols * 2)) + 1, inCols, outCols)); 130 endif 131 im = im(row_idx, col_idx); 132 133 else 134 [XI, YI] = meshgrid (linspace (1, inCols, outCols), linspace (1, inRows, outRows)); 135 im = imremap (im, XI, YI, method); 136 endif 137endfunction 138 139function retval = is_for_integer (scale) 140 retval = false; 141 if (fix (scale) == scale) 142 retval = 1; 143 elseif (fix (1/scale) == (1/scale)) 144 ## if scale/n is an integer then we are resizing to one half, one third, etc 145 ## and we can also use clever indexing 146 retval = -1; 147 endif 148endfunction 149 150%!test 151%! in = [116 227 153 69 146 194 59 130 139 106 152%! 2 47 137 249 90 75 16 24 158 44 153%! 155 68 46 84 166 156 69 204 32 152 154%! 71 221 137 230 210 153 192 115 30 118 155%! 107 143 108 52 51 73 101 21 175 90 156%! 54 158 143 77 26 168 113 229 165 225 157%! 9 47 133 135 130 207 236 43 19 73]; 158%! assert (imresize (uint8 (in), 1, "nearest"), uint8 (in)) 159%! assert (imresize (uint8 (in), 1, "bicubic"), uint8 (in)) 160%! 161%! out = [116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 162%! 116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 163%! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 164%! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 165%! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 166%! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 167%! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 168%! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 169%! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 170%! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 171%! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 172%! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 173%! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73 174%! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73]; 175%! assert (imresize (uint8 (in), 2, "nearest"), uint8 (out)) 176%! assert (imresize (uint8 (in), 2, "neAreST"), uint8 (out)) 177%! assert (imresize (uint8 (in), [14 NaN], "nearest"), uint8 (out)) 178%! assert (imresize (uint8 (in), [NaN 20], "nearest"), uint8 (out)) 179%! 180%! out = [116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 181%! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 182%! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 183%! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 184%! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 185%! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 186%! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73]; 187%! assert (imresize (uint8 (in), [7 20], "nearest"), uint8 (out)) 188%! 189%! assert (imresize (uint8 (in), 1.5, "bicubic"), imresize (uint8 (in), 1.5, "cubic")) 190%! assert (imresize (uint8 (in), [NaN, size(in,2)*1.5], "bicubic"), imresize (uint8 (in), 1.5, "cubic")) 191%! assert (imresize (uint8 (in), [size(in,1)*1.5, NaN], "bicubic"), imresize (uint8 (in), 1.5, "cubic")) 192%! assert (imresize (uint8 (in), 1.5, "linear"), imresize (uint8 (in), 1.5, "LIneAR")) 193%! assert (imresize (uint8 (in), 1.5, "linear"), imresize (uint8 (in), 1.5, "triangle")) 194%! 195%! out = [ 47 249 75 24 44 196%! 221 230 153 115 118 197%! 158 77 168 229 225 198%! 47 135 207 43 73]; 199%! assert (imresize (uint8 (in), 0.5, "nearest"), uint8 (out)) 200 201## Do not enforce floating point images to be in the [0 1] range (bug #43846) 202%!assert (imresize (repmat (5, [3 3]), 2), repmat (5, [6 6]), eps*100) 203 204## Similarly, do not enforce images to have specific dimensions and only 205## expand on the first 2 dimensions. 206%!assert (imresize (repmat (5, [3 3 2]), 2), repmat (5, [6 6 2]), eps*100) 207 208## The following are the matlab results. We have slighlty different 209## results but not by much. If there's would be any fixes, they 210## would have to be on interp2 or maybe in imremap. 211 212%!shared in 213%! in = [116 227 153 69 146 194 59 130 139 106 214%! 2 47 137 249 90 75 16 24 158 44 215%! 155 68 46 84 166 156 69 204 32 152 216%! 71 221 137 230 210 153 192 115 30 118 217%! 107 143 108 52 51 73 101 21 175 90 218%! 54 158 143 77 26 168 113 229 165 225 219%! 9 47 133 135 130 207 236 43 19 73]; 220 221%!xtest 222%! out = [116 185 235 171 96 64 134 189 186 74 90 141 140 124 108 223%! 44 92 143 149 164 163 119 123 118 44 38 80 151 118 63 224%! 14 21 47 107 195 228 115 81 70 24 19 56 137 105 49 225%! 145 98 49 49 71 107 148 159 132 58 124 176 61 85 145 226%! 118 139 144 92 116 168 201 188 159 140 167 158 27 69 152 227%! 62 151 218 145 174 219 201 164 146 187 148 84 48 76 115 228%! 102 132 151 119 90 72 72 72 83 114 60 31 144 130 81 229%! 82 121 154 133 87 41 19 67 116 95 108 140 183 180 164 230%! 40 96 152 149 117 74 34 108 179 131 175 215 153 177 219 231%! 11 33 73 127 137 125 113 158 212 229 148 55 35 63 96 232%! 4 17 53 121 141 138 133 171 220 253 141 16 7 36 67]; 233%! assert (imresize (uint8 (in), 1.5, "bicubic"), uint8 (out)) 234 235%!xtest 236%! out = [116 172 215 165 111 82 133 170 171 81 95 132 138 123 106 237%! 59 98 138 144 152 152 125 127 119 54 58 89 137 112 75 238%! 27 39 62 110 172 202 123 96 78 36 40 68 123 100 62 239%! 129 97 64 62 87 119 146 148 128 74 117 154 73 94 134 240%! 113 129 136 101 125 162 183 172 151 135 146 139 53 83 135 241%! 77 143 195 145 166 197 186 162 146 171 138 92 62 84 113 242%! 101 129 149 120 98 81 78 82 91 111 77 56 132 123 95 243%! 81 116 147 130 96 61 43 80 119 109 116 132 162 164 158 244%! 46 93 139 141 114 80 50 109 168 141 166 189 151 171 200 245%! 16 41 77 123 130 123 115 157 204 214 145 69 48 71 98 246%! 9 28 61 119 134 134 131 169 212 231 140 39 23 46 73]; 247%! assert (imresize (uint8 (in), 1.5, "bilinear"), uint8 (out)) 248 249%!xtest 250%! out = [108 136 125 89 107 251%! 111 132 143 114 99 252%! 106 110 106 127 136 253%! 47 121 163 138 68]; 254%! assert (imresize (uint8 (in), 0.5, "bilinear"), uint8 (out)) 255 256%!xtest 257%! out = [103 141 124 78 110 258%! 111 134 153 114 91 259%! 115 108 93 128 146 260%! 38 124 175 143 54]; 261%! assert (imresize (uint8 (in), 0.5, "bicubic"), uint8 (out)) 262 263%!xtest 264%! ## bug #55202 265%! assert (imresize (zeros (1, 20), [1 30], "nearest"), zeros (1, 30)) 266 267%!test 268%! ## a test for bug #55780 269%! a = zeros (7, "uint8"); 270%! a (4,4) = 255; 271%! c = [ 4 13 24 31 31 24 13 4; 272%! 13 44 79 103 103 79 44 13; 273%! 24 79 140 182 182 140 79 24; 274%! 31 103 182 238 238 182 103 31; 275%! 31 103 182 238 238 182 103 31; 276%! 24 79 140 182 182 140 79 24; 277%! 13 44 79 103 103 79 44 13; 278%! 4 13 24 31 31 24 13 4]; 279%! b = imresize (a, 4, "bicubic"); 280%! assert (b(11:18,11:18), c, eps) 281 282