./PaxHeaders.6632/image-2.4.10000644000000000000000000000013212561122761012340 xustar0030 mtime=1438950897.802252238 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/0000755000175000017500000000000012561122761015103 5ustar00carandraugcarandraug00000000000000image-2.4.1/PaxHeaders.6632/inst0000644000000000000000000000013212561122761013160 xustar0030 mtime=1438950897.782252238 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/inst/0000755000175000017500000000000012561122761016060 5ustar00carandraugcarandraug00000000000000image-2.4.1/inst/PaxHeaders.6632/imtranslate.m0000644000000000000000000000013212561122761015736 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imtranslate.m0000644000175000017500000000422612561122761020565 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2002 Jeff Orchard ## ## 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 3 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{Y}} = imtranslate (@var{M}, @var{x}, @var{y}) ## @deftypefnx {Function File} {@var{Y}} = imtranslate (@var{M}, @var{x}, @var{y}, @var{bbox}) ## Translate a 2D image by (x,y) using Fourier interpolation. ## ## @var{M} is a matrix, and is translated to the right by @var{X} pixels ## and translated up by @var{Y} pixels. ## ## @var{bbox} can be either 'crop' or 'wrap' (default). ## ## @end deftypefn function Y = imtranslate (X, a, b, bbox = "wrap") if ( strcmp(bbox, "crop")==1 ) pre = post = ceil ([a b]); pre(pre > 0) = 0; post(post < 0) = 0; X = padarray (X, abs (pre), "pre"); X = padarray (X, post, "post"); endif [dimy, dimx] = size(X); x = fft2(X); px = exp(-2*pi*i*a*(0:dimx-1)/dimx); py = exp(-2*pi*i*b*(0:dimy-1)/dimy)'; % actually to correspond to index notation 'b' should be % replaced with '-b' % but I do not want to brake previous version compatibility % note: it also must be done in the cropping iand padding code P = py * px; y = x .* P; Y = real(ifft2(y)); % fft return complex number % for integer shifts imaginary part is 0 % so real takes care of transfer from complex number to real if ( strcmp(bbox, "crop")==1 ) Y = Y(ypad(1)+1:dimy-ypad(2) , xpad(1)+1:dimx-xpad(2)); endif endfunction image-2.4.1/inst/PaxHeaders.6632/montage.m0000644000000000000000000000013212561122761015045 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/montage.m0000644000175000017500000003252312561122761017675 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} montage (@var{I}) ## @deftypefnx {Function File} {} montage (@var{X}, @var{cmap}) ## @deftypefnx {Function File} {} montage (@var{filenames}) ## @deftypefnx {Function File} {} montage (@dots{}, @var{param1}, @var{value1}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} montage (@dots{}) ## Create montage from multiple images. ## ## The created montage will be of a single large image built from the 4D matrix ## @var{I}. @var{I} must be a MxNx1x@var{P} or MxNx3x@var{P} matrix for a ## grayscale and binary, or RGB image with @var{P} frames. ## ## Alternatively, @var{X} can be a MxNx1x@var{P} indexed image with @var{P} ## frames, with the colormap @var{cmap}, or a cell array of @var{filenames} ## for multiple images. ## ## @table @asis ## @item DisplayRange ## A vector with 2 or 0 elements setting the highest and lowest value for ## display range. It is interpreted like the @var{limits} argument to ## @code{imshow}. ## ## @item Indices ## A vector with the image indices to be displayed. Defaults to all images, ## i.e., @code{1:size (@var{I}, 4)}. ## ## @item Size ## Sets the montage layout size. Must be a 2 element vector setting ## [@var{nRows} @var{nCols}]. A value of NaN will be adjusted to the required ## value to display all images. If both values are NaN (default), it will ## find the most square layout capable of displaying all of the images. ## ## @item MarginColor ## Sets color for the margins between panels. Defaults to white. Must be a ## 1 or 3 element vector for grayscale or RGB images. ## ## @item MarginWidth ## Sets width for the margins between panels. Defaults to 0 pixels. Note that ## the margins are only between panels. ## ## @item BackgroundColor ## Sets the montage background color. Defaults to black. Must be a ## 1 or 3 element vector for grayscale or RGB images. This will only affect ## montages with more panels than images. ## @end table ## ## The optional return value H is a graphics handle to the created plot. ## ## @seealso{imshow, padarray, permute, reshape} ## @end deftypefn function h = montage (images, varargin) if (nargin < 1) print_usage (); endif if (iscellstr (images)) ## we are using cellfun instead of passing the "all" option ## to file_in_loadpath, so we know which of the figures was ## not found, and provide a more meaningful error message fullpaths = cellfun (@file_in_loadpath, images(:), "UniformOutput", false); lost = cellfun (@isempty, fullpaths); if (any (lost)) badpaths = strjoin (images(:)(lost), "\n"); error ("montage: unable to find files:\n%s", badpaths); endif ## supporting grayscale, indexed, and truecolor images in ## the same list, complicates things a bit. Also, don't forget ## some images may be multipage infos = cellfun (@imfinfo, fullpaths, "UniformOutput", false); nImg = sum (cellfun (@numel, infos)); # number of images ## in case of multipage images, different pages may have different sizes, ## so we must check the height and width of each page of each image height = infos{1}(1).Height; width = infos{1}(1).Width; if (any (cellfun (@(x) any (arrayfun (@(y) y.Height != height || y.Width != width, x)), infos))) error ("montage: all images must have the same size."); endif ## To save on memory, we find the image with highest bitdepth, and ## create a matrix with the correct dimensions, where the images will ## be read into. We could read all the images and maps with a single ## cellfun call, and that would be a bit simpler than deducing ## from imfinfo but then we'd end up taking up the double of memory ## as we reorganize and convert the images ## a multipage image could have a mixture of colortypes, so we must ## check the type of every single one. If they are all grayscale, that's ## nice, it will be one dimension less, otherwise 3rd dimension is for ## rgb values. Also, any indexed image will be later converted to ## truecolor with rgb2ind so it will count as double if (any (cellfun (@(x) any (strcmp ({x(:).ColorType}, "indexed")), infos))) cl = "double"; convt = @im2double; else maxbd = max (cellfun (@(x) max ([x(:).BitDepth]), infos)); switch (maxbd) case {8} cl = "uint8"; convt = @im2uint8; case {16} ## includes both uint18 and int16 cl = "uint16"; convt = @im2uint16; otherwise ## includes maxbd == 32 plus anything else. In case of anything ## unexpected, better play safe and use the one with more precision cl = "double"; convt = @im2double; endswitch endif if (all (cellfun (@(x) all (strcmp ({x(:).ColorType}, "grayscale")), infos))) images = zeros (height, width, 1, nImg, cl); else images = zeros (height, width, 3, nImg, cl); endif nRead = 0; # count of pages already read for idx = 1:numel (infos) img_info = infos{idx}; nPages = numel (img_info); nRead += nPages; page_range = nRead+1-nPages:nRead; ## we won't be handling the alpha channel, but matlab doesn't either if (size (images, 3) == 1 || all (strcmp ({img_info(:).ColorType}, "truecolor"))) ## sweet, no problems for sure [images(:,:,:,page_range), map] = imread (img_info(idx).Filename, 1:nPages); else [tmp_img, map] = imread (fullpaths(:), 1:nPages); if (! isempty (map)) ## an indexed image. According to TIFF 6 specs, an indexed ## multipage image can have different colormaps for each page. ## How does imread behave with such images? And do they actually ## exist out there? tmp_img = ind2rgb (ind, map) elseif (size (tmp_img, 3) == 1) ## must be a grayscale image, propagate values to all channels tmp_img = repmat (tmp_img, [1 1 3 nPages]) else ## must be a truecolor image, do nothing endif images(:,:,:,page_range) = tmp_img; endif endfor ## we can't really distinguish between a multipage indexed and normal ## image. So we'll assume it's an indexed if there's a second argument ## that is a colormap elseif (isimage (images) && nargin > 1 && iscolormap (varargin{1})) images = ind2rgb (images, varargin{1}); varargin(1) = []; elseif (isimage (images)) ## all is nice else print_usage (); endif [height, width, channels, nImg] = size (images); p = inputParser (); p.FunctionName = "montage"; ## FIXME: inputParser was first implemented in the general package in the ## old @class type which allowed for a very similar interface to ## Matlab. classdef was implemented in the upcoming 4.0 release, ## which enabled inputParser to be implemented exactly the same and ## it is now part of Octave core. To prevent issues while all this ## versions are available, we check if the inputParser being used ## is in a @inputParser directory. ## ## Remove all this checks once the general package has been released ## again without the @inputParser class if (strfind (which ("inputParser"), ["@inputParser" filesep "inputParser.m"])) p = p.addParamValue ("DisplayRange", [], @(x) isnumeric (x) && any (numel (x) == [0 2])); p = p.addParamValue ("Indices", 1:nImg, @(x) isindex (x, nImg)); p = p.addParamValue ("Size", [NaN NaN], @(x) isnumeric (x) && numel (x) == 2); p = p.addParamValue ("MarginWidth", 0, @(x) isnumeric (x) && isscalar (x)); p = p.addParamValue ("MarginColor", getrangefromclass (images)(2), @(x) isnumeric (x) && any (numel (x) == [1 3])); p = p.addParamValue ("BackgroundColor", getrangefromclass (images)(1), @(x) isnumeric (x) && any (numel (x) == [1 3])); p = p.parse (varargin{:}); else p.addParamValue ("DisplayRange", [], @(x) isnumeric (x) && any (numel (x) == [0 2])); p.addParamValue ("Indices", 1:nImg, @(x) isindex (x, nImg)); p.addParamValue ("Size", [NaN NaN], @(x) isnumeric (x) && numel (x) == 2); p.addParamValue ("MarginWidth", 0, @(x) isnumeric (x) && isscalar (x)); p.addParamValue ("MarginColor", getrangefromclass (images)(2), @(x) isnumeric (x) && any (numel (x) == [1 3])); p.addParamValue ("BackgroundColor", getrangefromclass (images)(1), @(x) isnumeric (x) && any (numel (x) == [1 3])); p.parse (varargin{:}); endif ## remove unnecessary images images = images(:,:,:,p.Results.Indices); nImg = size (images, 4); ## 1) calculate layout of the montage [nRows, nCols] = deal (p.Results.Size(1), p.Results.Size(2)); if (isnan (nRows) && isnan (nCols)) ## We must find the smallest layout that is most square. The most square ## are the ones with smallest difference between height and width. And to ## find the smallest layout for each number of columns, is the one that ## requires less rows. The smallest layout will be used as a mask to choose ## the minimum from hxW_diff v_heights = cumsum (linspace (height, nImg*height, nImg)); v_widths = cumsum (linspace (width, nImg*width, nImg)); HxW_diff = abs (v_heights' - v_widths); small_layout = ((1:nImg)' .* (1:nImg)) >= nImg; small_layout = logical (diff (padarray (small_layout, 1, 0, "pre"))); HxW_diff(! small_layout) = Inf; [nRows, nCols] = find (HxW_diff == min (HxW_diff(:)), 1); elseif (isnan (nRows)) nRows = ceil (nImg/nCols); elseif (isnan (nCols)) nCols = ceil (nImg/nRows); elseif (nCols * nRows < nImg) error ("montage: size of %ix%i is not enough for image with %i frames.", nRows, nCols, nImg); endif ## 2) build the image margin_width = p.Results.MarginWidth; back_color = fix_color (p.Results.BackgroundColor, channels); disp_img = zeros (height*nRows + margin_width*(nRows-1), width *nCols + margin_width*(nCols-1), channels, class (images)) + back_color; ## find the start and end coordinates for each of the images xRows = start_end (nRows, height, margin_width); xCols = start_end (nCols, width, margin_width); ## Using reshape and permute to build the final image turned out to ## be quite a problem. So yeah... we'll use a for loop. Anyway, the number ## of images on a montage is never very high, this function is unlikely ## to be the speed bottleneck for any usage, and will make the code ## much more readable. iRow = iCol = 1; for iImg = 1:nImg if (iCol > nCols) iCol = 1; iRow++; endif rRow = xRows(1,iRow):xRows(2,iRow); # range of rows rCol = xCols(1,iCol):xCols(2,iCol); # range of columns disp_img(rRow,rCol,:) = images(:,:,:,iImg); iCol++; endfor ## 3) color margins as required margin_color = fix_color (p.Results.MarginColor, channels); if (margin_width > 0 && any (margin_color != back_color)) mRows = linspace (xRows(2,1:end-1) +1, xRows(1,2:end) -1, margin_width) (:); mCols = linspace (xCols(2,1:end-1) +1, xCols(1,2:end) -1, margin_width) (:); ## a function that can be used to brodcast assignment bd_ass = @(x, y) subsasgn (x, struct ("type", "()", "subs", {{":"}}), y); disp_img(mRows,:,:) = bsxfun (bd_ass, disp_img(mRows,:,:), margin_color); disp_img(:,mCols,:) = bsxfun (bd_ass, disp_img(:,mCols,:), margin_color); endif ## 4) display the image ## because there is no default value for limits in imshow, we call imshow ## in this condition. Actually, the default is dependent on the image type ## which would make this even longer if (any (strcmpi (p.UsingDefaults, "DisplayRange"))) tmp_h = imshow (disp_img, p.Results.DisplayRange); else tmp_h = imshow (disp_img); endif if (nargout > 0) h = tmp_h; endif endfunction ## given number of elements (n), the length or each, and the border length ## between then, returns start and end coordinates for each of the elements function [coords] = start_end (n, len, bord) coords = bord * (0:(n-1)) + len * (0:(n-1)) + 1; coords(2,:) = coords(1,:) + len - 1; endfunction ## color values can be given in grayscale or RGB values and may not match ## the values of the image. This function will make the color match the ## image and give a 1x1x(1||3) vector that can be used for broadcasting function color = fix_color (color, img_channels) if (numel (color) != img_channels) if (img_channels == 3) color = repmat (color, [3 1]); elseif (img_channels == 1) color = rgb2gray (reshape (color, [1 1 3])); else error ("montage: image has an unknown number (%d) of channels.", img_channels); endif endif color = reshape (color, [1 1 img_channels]); endfunction image-2.4.1/inst/PaxHeaders.6632/im2uint16.m0000644000000000000000000000013212561122761015151 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2uint16.m0000644000175000017500000000624012561122761017776 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Søren Hauberg ## Copyright (C) 2012-2014 Carnë Draug ## ## 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 3 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} {} im2uint16 (@var{img}) ## @deftypefnx {Function File} {} im2uint16 (@var{img}, "indexed") ## Convert image to uint16. ## ## The conversion of @var{img} to a 16-bit unsigned integer, is dependent ## on the type of input image. The following input classes are supported ## for non-indexed images: ## ## @table @samp ## @item int16 or uint8 ## Values are rescaled to the range of the uint16 class [0 65535]. ## ## @item logical ## True and false values are assigned a value of 0 and 255 respectively. ## ## @item double or single ## Values are truncated to the interval [0 1] and then rescaled to the range ## of values of the int16 class [0 255]. ## ## @item uint16 ## Returns the same image. ## ## @end table ## ## If the second argument is the string @qcode{"indexed"}, then values are ## cast to uint16, and a -1 offset is applied if input is ## a floating point class. Input checking is performed and an error will ## be throw is the range of values in uint16 is not enough for all the ## image indices. ## ## @seealso{im2bw, imcast, im2uint8, im2double, im2int16, im2single} ## @end deftypefn function imout = im2uint16 (im, varargin) if (nargin < 1 || nargin > 2) print_usage (); elseif (nargin == 2 && ! strcmpi (varargin{1}, "indexed")) error ("im2uint16: second input argument must be the string \"indexed\""); endif imout = imcast (im, "uint16", varargin{:}); endfunction %!assert (im2uint16 (uint16 ([1 2 3])), uint16 ([1 2 3])); %!assert (im2uint16 (uint8 ([0 127 128 255])), uint16 ([0 32639 32896 65535])); %!assert (im2uint16 ([0 0.5 1]), uint16 ([0 32768 65535])); %!assert (im2uint16 ([0 1/65535 1.4/65535 1.5/65535 1]), uint16 ([0 1 1 2 65535])); %!assert (im2uint16 ([1 2]), uint16 ([65535 65535])); %!assert (im2uint16 ([-1 0 0.5 1]), uint16 ([0 0 32768 65535])); %!assert (im2uint16 (int16 ([-32768 -1 0 32768])), uint16 ([0 32767 32768 65535])); %!assert (im2uint16 ([false true]), uint16 ([0 65535])); %!assert (im2uint16 ([true false]), uint16 ([65535 0])); %!assert (im2uint16 (uint8 ([3 25]), "indexed"), uint16 ([3 25])); %!assert (im2uint16 ([1 3 25], "indexed"), uint16 ([0 2 24])); %!error im2uint16 ([0 1 2], "indexed"); %!error im2uint16 (int16 ([17 8]), "indexed"); %!error im2uint16 (int16 ([-7 8]), "indexed"); %!error im2uint16 ([false true], "indexed"); %!error im2uint16 (65537, "indexed"); image-2.4.1/inst/PaxHeaders.6632/im2double.m0000644000000000000000000000013212561122761015275 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2double.m0000644000175000017500000000551512561122761020126 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Søren Hauberg ## Copyright (C) 2012-2014 Carnë Draug ## ## 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 3 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} {} im2double (@var{img}) ## @deftypefnx {Function File} {} im2double (@var{img}, "indexed") ## Convert image to double precision. ## ## The conversion of @var{img} to double precision, is dependent ## on the type of input image. The following input classes are supported: ## ## @table @samp ## @item uint8, uint16, and int16 ## The whole range of values from the class (see @code{getrangefromclass}) ## are scaled for the interval [0 1], e.g., if input image was uint8, ## intensity values of 0, 127, and 255, are converted to intensity of ## 0, 0.498, and 1. ## ## @item logical ## True and false values are assigned a value of 0 and 1 respectively. ## ## @item single ## Values are cast to single precision. ## ## @item double ## Returns the same image. ## ## @end table ## ## If the second argument is the string @qcode{"indexed"}, then values are ## cast to double precision, and a +1 offset is applied if input is ## an integer class. ## ## @seealso{im2bw, imcast, im2uint8, im2int16, im2single, im2uint16} ## @end deftypefn function imout = im2double (img, varargin) if (nargin < 1 || nargin > 2) print_usage (); elseif (nargin == 2 && ! strcmpi (varargin{1}, "indexed")) error ("im2double: second input argument must be the string \"indexed\""); endif imout = imcast (img, "double", varargin{:}); endfunction %!assert (im2double ([1 2 3]), [1 2 3]); %!assert (im2double (single ([1 2 3])), [1 2 3]); %!assert (im2double (uint8 ([0 127 128 255])), [0 127/255 128/255 1]); %!assert (im2double (uint16 ([0 127 128 65535])), [0 127/65535 128/65535 1]); %!assert (im2double (int16 ([-32768 -32767 -32766 32767])), [0 1/65535 2/65535 1]); %!assert (im2double (uint8 ([0 1 255]), "indexed"), [1 2 256]); %!assert (im2double (uint16 ([0 1 2557]), "indexed"), [1 2 2558]); %!assert (im2double ([3 25], "indexed"), [3 25]); %!error im2double (single ([0 1 2]), "indexed"); %!error im2double (int16 ([17 8]), "indexed"); %!error im2double (int16 ([-7 8]), "indexed"); %!error im2double ([false true], "indexed"); image-2.4.1/inst/PaxHeaders.6632/normxcorr2.m0000644000000000000000000000013212561122761015526 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/normxcorr2.m0000644000175000017500000001103612561122761020352 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Benjamin Eltzner ## ## 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 3 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} {} normxcorr2 (@var{template}, @var{img}) ## Compute normalized cross-correlation. ## ## Returns the the cross-correlation coefficient of matrices @var{template} ## and @var{img}, a matrix of the same size as @var{img} with values ranging ## between -1 and 1. ## ## Normalized correlation is mostly used for template matching, finding an ## object or pattern, @var{template}, withing an image @var{img}. Higher ## values on the output show their locations, even in the presence of noise. ## ## @group ## @example ## img = randi (255, 600, 400); ## template = imnoise (img(100:150, 300:320), "gaussian"); ## cc = normxcorr2 (template, img); ## [r, c] = find (cc == max (cc(:))) ## @result{r} 150 ## @result{c} 320 ## @end example ## @end group ## ## Despite the function name, this function will accept input with an arbitrary ## number of dimensions. ## ## @seealso{conv2, convn, corr2, xcorr, xcorr2} ## @end deftypefn ## Author: Benjamin Eltzner function c = normxcorr2 (a, b) if (nargin != 2) print_usage (); endif ## If this happens, it is probably a mistake if (ndims (a) > ndims (b) || any (postpad (size (a), ndims (b)) > size (b))) warning ("normxcorr2: TEMPLATE larger than IMG. Arguments may be swapped."); endif a = double (a) - mean (a(:)); b = double (b) - mean (b(:)); a1 = ones (size (a)); ar = reshape (a(end:-1:1), size (a)); c = convn (b, conj (ar)); b = convn (b.^2, a1) .- convn (b, a1).^2 ./ (prod (size (a))); a = sumsq (a(:)); c = reshape (c ./ sqrt (b * a), size (c)); c(isnan (c)) = 0; endfunction %!function offsets = get_max_offsets (c) %! l = find (c == max (c(:))); %! offsets = nthargout (1:ndims (c), @ind2sub, size (c), l); %!endfunction ## test basic usage %!test %! row_shift = 18; %! col_shift = 20; %! a = randi (255, 30, 30); %! b = a(row_shift-10:row_shift, col_shift-7:col_shift); %! c = normxcorr2 (b, a); %! ## should return exact coordinates %! assert (get_max_offsets (c), {row_shift col_shift}); %! %! ## Even with some small noise, should return exact coordinates %! b = imnoise (b, "gaussian"); %! c = normxcorr2 (b, a); %! assert (get_max_offsets (c), {row_shift col_shift}); ## The value for a "perfect" match should be 1. However, machine precision ## creeps in most of the times. %!test %! a = rand (10, 10); %! c = normxcorr2 (a(5:7, 6:9), a); %! assert (c(7, 9), 1, eps*2); ## coeff of autocorrelation must be same as negative of correlation ## by additive inverse %!test %! a = 10 * randn (100, 100); %! auto = normxcorr2 (a, a); %! add_in = normxcorr2 (a, -a); %! assert (auto, -add_in); ## Normalized correlation should be independent of scaling and shifting ## up to rounding errors %!test %! a = 10 * randn (50, 50); %! b = 10 * randn (100, 100); %! do %! scale = 100 * rand (); %! until (scale != 0) %! %! assert (max ((normxcorr2 (scale*a,b) .- normxcorr2 (a,b))(:)), 0, 1e-10); %! assert (max ((normxcorr2 (a,scale*b) .- normxcorr2 (a,b))(:)), 0, 1e-10); %! %! a_shift1 = a .+ scale * ones (size (a)); %! b_shift1 = b .+ scale * ones (size (b)); %! a_shift2 = a .- scale * ones (size (a)); %! b_shift2 = b .- scale * ones (size (b)); %! assert (max ((normxcorr2 (a_shift1,b) .- normxcorr2 (a,b))(:)), 0, 1e-10); %! assert (max ((normxcorr2 (a,b_shift1) .- normxcorr2 (a,b))(:)), 0, 1e-10); %! assert (max ((normxcorr2 (a_shift2,b) .- normxcorr2 (a,b))(:)), 0, 1e-10); %! assert (max ((normxcorr2 (a,b_shift2) .- normxcorr2 (a,b))(:)), 0, 1e-10); ## test n dimensional input %!test %! a = randi (100, 15, 15, 15); %! c = normxcorr2 (a(5:10, 2:6, 3:7), a); %! assert (get_max_offsets (c), {10 6 7}); %! %! a = randi (100, 15, 15, 15); %! c = normxcorr2 (a(5:10, 2:6, 1:1), a); %! assert (get_max_offsets (c), {10 6 1}); %!warning normxcorr2 (rand (20), rand (5)); %!error normxcorr2 (rand (5)); %!error normxcorr2 (rand (5), rand (20), 2); image-2.4.1/inst/PaxHeaders.6632/psf2otf.m0000644000000000000000000000013212561122761014776 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/psf2otf.m0000644000175000017500000000641112561122761017623 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2015 Carnë Draug ## ## 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 3 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} {} psf2otf (@var{psf}) ## @deftypefnx {Function File} {} psf2otf (@var{psf}, @var{outsize}) ## Compute OTF from PSF. ## ## Returns the Optical Transfer Function (OTF) of the Point Spread ## Function @var{psf}. ## ## The optional argument @var{outsize} defines the size of the computed ## @var{otf}. The input @var{psf} is post-padded with zeros previous to ## the OTF computation. ## ## @seealso{circshift, fft2, fftn, otf2psf} ## @end deftypefn function otf = psf2otf (psf, outsize) if (nargin < 1 || nargin > 2) print_usage (); elseif (! isnumeric (psf) || ! isreal (psf)) error ("psf2otf: PSF must be numeric and real") endif insize = size (psf); if (nargin > 1) if (! isnumeric (outsize) || ! isvector (outsize)) error ("psf2otf: OUTSIZE must be a numeric vector"); endif n = max (numel (outsize), numel (insize)); outsize = postpad (outsize(:), n, 1); insize = postpad (insize(:), n, 1); if (any (outsize < insize)) error ("psf2otf: OUTSIZE must be larger than or equal than PSF size"); endif psf = padarray (psf, outsize - insize, "post", "zeros"); endif psf = circshift (psf, - floor (insize / 2)); otf = fftn (psf); endfunction ## Basic usage, 1, 2, and 3 dimensional %!test %! psf = rand (6, 1); %! assert (psf2otf (psf), fft (circshift (psf, [-3]))); %!test %! psf = rand (6, 6); %! assert (psf2otf (psf), fft2 (circshift (psf, [-3 -3]))); %!test %! psf = rand (6, 6, 6); %! assert (psf2otf (psf), fftn (circshift (psf, [-3 -3 -3]))); ## Test when length of some sides are odd %!test %! psf = rand (7, 1); %! assert (psf2otf (psf), fft (circshift (psf, [-3]))); %!test %! psf = rand (7, 7); %! assert (psf2otf (psf), fft2 (circshift (psf, [-3 -3]))); %!test %! psf = rand (6, 7, 8); %! assert (psf2otf (psf), fftn (circshift (psf, [-3 -3 -4]))); ## Test the outsize/padding option %!test %! psf = rand (6, 1); %! ppsf = [psf; 0]; %! assert (psf2otf (psf, 7), fft (circshift (ppsf, [-3]))); %!test %! psf = rand (6, 1); %! ppsf = [[psf; 0] zeros(7, 6)]; %! assert (psf2otf (psf, [7 7]), fft2 (circshift (ppsf, [-3 0]))); %!test %! psf = rand (6, 6); %! ppsf = [psf zeros(6, 1)]; %! assert (psf2otf (psf, [6 7]), fft2 (circshift (ppsf, [-3 -3]))); %!error psf2otf (complex (rand (16), rand (16))) %!error psf2otf (rand (16), 14) %!error psf2otf (rand (16), [14 14]) %!error psf2otf (rand (16), [18]) %!error psf2otf (rand (16), [18 14]) image-2.4.1/inst/PaxHeaders.6632/ordfiltn.m0000644000000000000000000000013212561122761015234 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/ordfiltn.m0000644000175000017500000001140012561122761020053 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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} {} ordfiltn (@var{A}, @var{nth}, @var{domain}) ## @deftypefnx {Function File} {} ordfiltn (@var{A}, @var{nth}, @var{domain}, @var{S}) ## @deftypefnx {Function File} {} ordfiltn (@dots{}, @var{padding}) ## N dimensional ordered filtering. ## ## Ordered filter replaces an element of @var{A} with the @var{nth} element ## element of the sorted set of neighbours defined by the logical ## (boolean) matrix @var{domain}. ## Neighbour elements are selected to the sort if the corresponding ## element in the @var{domain} matrix is true. ## ## The optional variable @var{S} is a matrix of size(@var{domain}). ## Values of @var{S} corresponding to nonzero values of domain are ## added to values obtained from @var{A} when doing the sorting. ## ## Optional variable @var{padding} determines how the matrix @var{A} ## is padded from the edges. See @code{padarray} for details. ## ## @seealso{medfilt2, padarray, ordfilt2} ## @end deftypefn ## This function is based on 'ordfilt2' by Teemu Ikonen ## which is released under GPLv2 or later. function retval = ordfiltn (A, nth, domain, varargin) ## Check input if (nargin < 3) print_usage (); elseif (! isnumeric (A) && ! islogical (A)) error ("ordfiltn: A must be a numeric or logical array"); elseif (! isscalar (nth) || nth <= 0 || fix (nth) != nth) error ("ordfiltn: second input argument must be a positive integer"); elseif (! isnumeric (domain) && ! islogical (domain)) error ("ordfiltn: DOMAIN must be a numeric or logical array or scalar"); elseif (isscalar (domain) && (domain <= 0 || fix (domain) != domain)) error ("ordfiltn: third input argument must be a positive integer, when it is a scalar"); endif if (isscalar (domain)) domain = true (repmat (domain, 1, ndims (A))); endif if (ndims (A) != ndims (domain)) error ("ordfiltn: first and second argument must have same dimensionality"); elseif (any (size (A) < size (domain))) error ("ordfiltn: domain array cannot be larger than the data array"); endif ## Parse varargin S = zeros (size (domain)); padding = 0; for idx = 1:length(varargin) opt = varargin{idx}; if (ischar (opt) || isscalar (opt)) padding = opt; elseif (isnumeric (opt) && size_equal (opt, domain)) S = opt; else error ("ordfiltn: unrecognized option from input argument #%i and class %s", 3 + idx, class (opt)); endif endfor A = pad_for_sliding_filter (A, size (domain), padding); ## Perform the filtering retval = __spatial_filtering__ (A, logical (domain), "ordered", S, nth); endfunction %!shared b, f, s %! b = [ 0 1 2 3 %! 1 8 12 12 %! 4 20 24 21 %! 7 22 25 18]; %! %! f = [ 8 12 12 12 %! 20 24 24 24 %! 22 25 25 25 %! 22 25 25 25]; %!assert (ordfiltn (b, 9, true (3)), f); %! %! f = [ 1 8 12 12 %! 8 20 21 21 %! 20 24 24 24 %! 20 24 24 24]; %!assert (ordfiltn (b, 8, true (3)), f); %! %! f = [ 1 2 8 12 %! 4 12 20 21 %! 8 22 22 21 %! 20 24 24 24]; %!assert (ordfiltn (b, 7, true (3), "symmetric"), f); %! %! f = [ 1 8 12 12 %! 4 20 24 21 %! 7 22 25 21 %! 7 22 25 21]; %!assert (ordfiltn (b, 3, true (3, 1)), f); %! %! f = [ 1 8 12 12 %! 4 20 24 18 %! 4 20 24 18 %! 4 20 24 18]; %!assert (ordfiltn (b, 3, true (4, 1)), f); %! %! f = [ 4 20 24 21 %! 7 22 25 21 %! 7 22 25 21 %! 7 22 25 21]; %!assert (ordfiltn (b, 4, true (4, 1)), f); %! %! s = [0 0 1 %! 0 0 1 %! 0 0 1]; %! f = [ 2 8 12 12 %! 9 20 22 21 %! 21 25 24 24 %! 21 25 24 24]; %!assert (ordfiltn (b, 8, true (3), s), f); %! %! b(:,:,2) = b(:,:,1) - 1; %! b(:,:,3) = b(:,:,2) - 1; %! f(:,:,1) = [ 1 8 11 11 %! 8 20 21 21 %! 20 24 24 24 %! 20 24 24 24]; %! f(:,:,2) = [ 6 10 11 11 %! 18 22 22 22 %! 20 24 24 24 %! 20 24 24 24]; %! f(:,:,3) = [ 0 7 10 10 %! 7 19 20 20 %! 19 23 23 23 %! 19 23 23 23]; %!assert (ordfiltn (b, 25, true (3, 3, 3)), f); image-2.4.1/inst/PaxHeaders.6632/imregionalmax.m0000644000000000000000000000013212561122761016247 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imregionalmax.m0000644000175000017500000000547312561122761021103 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imregionalmax (@var{img}) ## @deftypefnx {Function File} {} imregionalmax (@var{img}, @var{conn}) ## Compute regional maxima. ## ## Returns a logical matrix, same size as the input @var{img}, with the ## regional maxima. ## ## The optional argument @var{conn}, defines the connectivity. It can ## be a scalar value or a boolean matrix (see @code{conndef} for details). ## Defaults to @code{conndef (ndims (@var{img}), "maximal")} ## ## Regional maxima should not be mistaken with local maxima. Local maxima ## are pixels whose value is greater or equal to all of its neighbors. ## A regional maxima is the connected component of pixels whose values are ## all higher than the neighborhood of the maxima (the connected component, ## not its individual pixels). ## All pixels belonging to a regional maximum are local maxima, but the ## inverse is not true. ## ## @seealso{immaximas, imreconstruct, imregionalmin} ## @end deftypefn function bw = imregionalmax (img, conn) if (nargin < 1 || nargin > 2) print_usage (); endif if (nargin < 2) conn = conndef (ndims (img), "maximal"); else conn = conndef (conn); endif if (islogical (img)) bw = img; else ## we could probably still make this more efficient recon = imreconstruct (img, img + 1, conn); bw = (recon == img); endif endfunction %!test %! a = [ %! 7 3 9 3 10 3 %! 4 2 3 10 1 3 %! 1 4 6 9 4 10 %! 8 7 9 3 4 8 %! 5 9 3 3 8 9 %! 3 6 9 4 1 10]; %! %! a4 = [ %! 1 0 1 0 1 0 %! 0 0 0 1 0 0 %! 0 0 0 0 0 1 %! 1 0 1 0 0 0 %! 0 1 0 0 0 0 %! 0 0 1 0 0 1]; %! assert (imregionalmax (a, 4), logical (a4)) %! a8 = [ %! 1 0 0 0 1 0 %! 0 0 0 1 0 0 %! 0 0 0 0 0 1 %! 0 0 0 0 0 0 %! 0 0 0 0 0 0 %! 0 0 0 0 0 1]; %! assert (imregionalmax (a, 8), logical (a8)) %! assert (imregionalmax (a), logical (a8)) image-2.4.1/inst/PaxHeaders.6632/houghtf.m0000644000000000000000000000013212561122761015057 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/houghtf.m0000644000175000017500000000760712561122761017714 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{H} = houghtf (@var{bw}) ## @deftypefnx{Function File} @var{H} = houghtf (@var{bw}, @var{method}) ## @deftypefnx{Function File} @var{H} = houghtf (@var{bw}, @var{method}, @var{arg}) ## Perform the Hough transform for lines or circles. ## ## The @var{method} argument chooses between the Hough transform for lines and ## circles. It can be either "line" (default) or "circle". ## ## @strong{Line Detection} ## ## If @var{method} is "line", the function will compute the Hough transform for ## lines. A line is parametrised in @var{r} and @var{theta} as ## @example ## @var{r} = x*cos(@var{theta}) + y*sin(@var{theta}), ## @end example ## where @var{r} is distance between the line and the origin, while @var{theta} ## is the angle of the vector from the origin to this closest point. The result ## @var{H} is an @var{N} by @var{M} matrix containing the Hough transform. Here, ## @var{N} is the number different values of @var{r} that has been attempted. ## This is computed as @code{2*diag_length - 1}, where @code{diag_length} is ## the length of the diagonal of the input image. @var{M} is the number of ## different values of @var{theta}. These can be set through the third input ## argument @var{arg}. This must be a vector of real numbers, and is by default ## @code{pi*(-90:90)/180}. ## ## @strong{Circle Detection} ## ## If @var{method} is "circle" the function will compute the Hough transform for ## circles. The circles are parametrised in @var{r} which denotes the radius of ## the circle. The third input argument @var{arg} must be a real vector containing ## the possible values of @var{r}. ## If the input image is @var{N} by @var{M}, then the result @var{H} will be an ## @var{N} by @var{M} by @var{K} array, where @var{K} denotes the number of ## different values of @var{r}. ## ## As an example, the following shows how to compute the Hough transform for circles ## with radius 3 or 7 in the image @var{im} ## @example ## bw = edge(im); ## H = houghtf(bw, "circle", [3, 7]); ## @end example ## Here @var{H} will be an NxMx2 array, where @var{H}(:,:,1) will contain the ## Hough transform for circles with radius 3, and @var{H}(:,:,2) for radius 7. ## To find good circles you now need to find local maximas in @var{H}. If you ## find a local maxima in @var{H}(row, col, 1) it means that a good circle exists ## with center (row,col) and radius 3. One way to locate maximas is to use the ## @code{immaximas} function. ## ## @seealso{hough_line, hough_circle, immaximas} ## @end deftypefn function [accum, R] = houghtf(bw, varargin) ## Default arguments method = "line"; args = {}; ## Check input arguments if (nargin == 0) error("houghtf: not enough input arguments"); endif if (! ismatrix (bw)) error("houghtf: BW must be a 2-dimensional matrix"); endif if (nargin > 1) if (ischar(varargin{1})) method = varargin{1}; args = varargin(2:end); else args = varargin; endif endif ## Choose method switch (lower(method)) case "line" [accum, R] = hough_line(bw, args{:}); case "circle" accum = hough_circle(bw, args{:}); otherwise error("houghtf: unsupported method '%s'", method); endswitch endfunction image-2.4.1/inst/PaxHeaders.6632/iptnum2ordinal.m0000644000000000000000000000013212561122761016362 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/iptnum2ordinal.m0000644000175000017500000000667512561122761021223 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{ord} =} iptnum2ordinal (@var{num}) ## Convert number to ordinal string. ## ## @var{num} must be a real positive integer which will be converted to a string ## with its ordinal form @var{ord}. ## ## @example ## @group ## iptnum2ordinal (1) ## @result{} first ## iptnum2ordinal (12) ## @result{} twelfth ## iptnum2ordinal (21) ## @result{} 21st ## @end group ## @end example ## ## @seealso{num2str, sprintf, int2str, mat2str} ## @end deftypefn function ord = iptnum2ordinal (num) ## thanks to Skei in ##matlab for checking the grammar of ordinals and that it ## is after number 20 that it starts using the suffixes only ## thanks to porten in ##matlab for help checking these corner-cases ## the following were test and failed: Inf, 0, -1, 3.4, 1e-7 ## using a string kind of succeeded as the character position in the ascii ## table as used for the conversion if (nargin != 1) print_usage; elseif (!isnumeric (num) || !isscalar (num) || !isreal (num) || num <= 0 || rem (num, 1) != 0) error ("num must be a real positive integer"); endif switch num case {1} ord = "first"; case {2} ord = "second"; case {3} ord = "third"; case {4} ord = "fourth"; case {5} ord = "fifth"; case {6} ord = "sixth"; case {7} ord = "seventh"; case {8} ord = "eighth"; case {9} ord = "ninth"; case {10} ord = "tenth"; case {11} ord = "eleventh"; case {12} ord = "twelfth"; case {13} ord = "thirteenth"; case {14} ord = "fourteenth"; case {15} ord = "fifteenth"; case {16} ord = "sixteenth"; case {17} ord = "seventeenth"; case {18} ord = "eighteenth"; case {19} ord = "nineteenth"; case {20} ord = "twentieth"; otherwise ## if we ever want to mimic matlab's defective behaviour of accepting a ## string and return the ordinal of position on the ascii table, we must ## check here if it's a string, and if so, use: ## ord = sprintf ("%dth", num); num = num2str (num); switch num(end) case {"1"} ord = strcat (num, "st"); case {"2"} ord = strcat (num, "nd"); case {"3"} ord = strcat (num, "rd"); otherwise ord = strcat (num, "th"); endswitch endswitch endfunction %!assert (strcmp (iptnum2ordinal (1), 'first')); # simple works %!assert (strcmp (iptnum2ordinal (21), '21st')); # after 20, goes stupid %!assert (strcmp (iptnum2ordinal (100), '100th')); # use th correctly %!fail ("iptnum2ordinal (inf)"); # must be real %!fail ("iptnum2ordinal (0)"); # must be positive %!fail ("iptnum2ordinal (-1)"); # must be positive %!fail ("iptnum2ordinal (3.4)"); # must be integer image-2.4.1/inst/PaxHeaders.6632/fchcode.m0000644000000000000000000000013212561122761015006 xustar0030 mtime=1438950897.734252238 30 atime=1438950897.734252238 30 ctime=1438950899.342252237 image-2.4.1/inst/fchcode.m0000644000175000017500000000472712561122761017643 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Andrew Kelly, IPS Radio & Space Services ## ## 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 3 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{fcc} = } fchcode (@var{bound}) ## Determine the Freeman chain code for a boundary. ## ## @code{fchcode} computes the Freeman chain code for the @var{n}-connected ## boundary @var{bound}. @var{n} must be either 8 or 4. ## ## @var{bound} is a K-by-2 matrix containing the row/column coordinates of points ## on the boundary. Optionally, the first point can be repeated as the last point, ## resulting in a (K+1)-by-2 matrix. ## ## @var{fcc} is a structure containing the following elements. ## ## @example ## x0y0 = Row/column coordinates where the code starts (1-by-2) ## fcc = Freeman chain code (1-by-K) ## diff = First difference of fcc (1-by-K) ## @end example ## ## The code uses the following directions. ## ## @example ## 3 2 1 ## 4 . 0 ## 5 6 7 ## @end example ## ## @seealso{bwboundaries} ## @end deftypefn function fcc = fchcode (bound) # ensure the boundary start and end points are the same if (!isempty (bound) && !isequal (bound (1, :), bound (end, :))) bound = [bound; bound(1, :)]; endif # number of boundary points n = max (0, rows (bound)-1); # structure in which to return results fcc = struct (... 'x0y0', zeros (1, n), ... 'fcc', zeros (1, n), ... 'diff', zeros (1, n) ... ); # an empty boundary? if (isempty (bound)) return; endif # direction map dir = [3, 2, 1; ... 4, NaN, 0; ... 5, 6, 7]; # coordinates ROW = 1; COL = 2; # direction changes as row/column indexes into DIR ch = 2 + diff (bound, 1, ROW); # starting point fcc.x0y0 = bound (1, :); # chain code fcc.fcc = dir (sub2ind (size (dir), ch (:, ROW), ch (:, COL)))'; # chain code difference fcc.diff = mod (diff ([fcc.fcc, fcc.fcc(1)]), 8); endfunction image-2.4.1/inst/PaxHeaders.6632/fftconv2.m0000644000000000000000000000013212561122761015142 xustar0030 mtime=1438950897.734252238 30 atime=1438950897.734252238 30 ctime=1438950899.342252237 image-2.4.1/inst/fftconv2.m0000644000175000017500000001136312561122761017771 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2004 Stefan van der Walt ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are met: ## ## 1 Redistributions of source code must retain the above copyright notice, ## this list of conditions and the following disclaimer. ## 2 Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in the ## documentation and/or other materials provided with the distribution. ## ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' ## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## -*- texinfo -*- ## @deftypefn {Function File} {} fftconv2 (@var{a}, @var{b}) ## @deftypefnx {Function File} {} fftconv2 (@var{v1}, @var{v2}, @var{a}) ## @deftypefnx {Function File} {} fftconv2 (@dots{}, @var{shape}) ## Convolve 2 dimensional signals using the FFT. ## ## This method is faster but less accurate than @var{conv2} for large @var{a} ## and @var{b}. It also uses more memory. A small complex component will be ## introduced even if both @var{a} and @var{b} are real. ## @seealso{conv2, fftconv, fft, ifft} ## @end deftypefn function X = fftconv2 (varargin) if (nargin < 2) print_usage (); endif nargs = nargin; # nargin minus the shape option if (ischar (varargin{end})) shape = varargin{end}; nargs--; else shape = "full"; endif rowcolumn = false; if (nargs == 2) ## usage: fftconv2(a, b[, shape]) a = varargin{1}; b = varargin{2}; elseif (nargs == 3) ## usage: fftconv2 (v1, v2, a[, shape]) rowcolumn = true; if (! isnumeric (varargin{3}) && ! islogical (varargin{3})) error ("fftconv2: A must be a numeric or logical array"); endif v1 = vec (varargin{1}); v2 = vec (varargin{2}, 2); orig_a = varargin{3}; else print_usage (); endif if (rowcolumn) a = fftconv2 (orig_a, v2); b = v1; endif ra = rows(a); ca = columns(a); rb = rows(b); cb = columns(b); A = fft2 (padarray (a, [rb-1 cb-1], "post")); B = fft2 (padarray (b, [ra-1 ca-1], "post")); X = ifft2 (A.*B); if (rowcolumn) rb = rows (v1); ra = rows (orig_a); cb = columns (v2); ca = columns (orig_a); endif switch (tolower (shape)) case "full", ## do nothing case "same", r_top = ceil ((rb + 1) / 2); c_top = ceil ((cb + 1) / 2); X = X(r_top:r_top + ra - 1, c_top:c_top + ca - 1); case "valid", X = X(rb:ra, cb:ca); otherwise error ("fftconv2: unknown convolution SHAPE `%s'", shape); endswitch endfunction ## usage: fftconv2(a,b,[, shape]) %!test %! a = repmat (1:10, 5); %! b = repmat (10:-1:3, 7); %! assert (fftconv2 (a, b), conv2 (a, b), 1.3e4*eps) %! assert (fftconv2 (b, a), conv2 (b, a), 1.3e4*eps) %! assert (fftconv2 (a, b, "full"), conv2 (a, b, "full"), 1.3e4*eps) %! assert (fftconv2 (b, a, "full"), conv2 (b, a, "full"), 1.3e4*eps) %! assert (fftconv2 (a, b, "same"), conv2 (a, b, "same"), 1e4*eps) %! assert (fftconv2 (b, a, "same"), conv2 (b, a, "same"), 1e4*eps) %! assert (isempty (fftconv2 (a, b, "valid"))); %! assert (fftconv2 (b, a, "valid"), conv2 (b, a, "valid"), 1e4*eps) ## usage: fftconv2(v1, v2, a[, shape]) %!test %! x = 1:4; %! y = 4:-1:1; %! a = repmat(1:10, 5); %! assert (fftconv2 (x, y, a), conv2 (x, y, a), 1e4*eps) %! assert (fftconv2 (x, y, a, "full"), conv2 (x, y, a, "full"), 1e4*eps) %! assert (fftconv2 (x, y, a, "same"), conv2 (x, y, a, "same"), 1e4*eps) %! assert (fftconv2 (x, y, a, "valid"), conv2 (x, y, a, "valid"), 1e4*eps) %!demo %! ## Draw a cross %! z = zeros (101, 101); %! z(50, :) = 1; %! z(:, 50) = 1; %! subplot (1, 3, 1) %! imshow (z); %! title ("Original thin cross") %! %! ## Draw a sinc blob %! b = getheight (strel ("ball", 10, 1)); %! subplot (1, 3, 2) %! imshow (b); %! title ("Sync blob") %! %! ## Convolve the cross with the blob %! fc = real (fftconv2 (z, b, "same")); %! subplot (1, 3, 3) %! imshow (fc, [min(fc(:)) max(fc(:))]) %! title ("Convolution in the frequency domain") image-2.4.1/inst/PaxHeaders.6632/col2im.m0000644000000000000000000000013212561122761014600 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/col2im.m0000644000175000017500000002130012561122761017417 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} col2im (@var{B}, @var{block_size}, @var{A_size}) ## @deftypefnx {Function File} {} col2im (@var{B}, @var{block_size}, @var{A_size}, @var{block_type}) ## Rearrange block columns back into matrix. ## ## Rearranges columns of the matrix @var{B}, representing blocks of size ## @var{block_size} from a matrix of size @var{A_size}, back into its ## original size (usually close to @var{A_size}. This function is most ## useful as reverse operation to @code{im2col}. ## ## ## Blocks are assumed to be from one of two types as defined by ## @var{block_type} (defaults to @qcode{"sliding"}): ## ## @table @asis ## @item @qcode{"distinct"} ## Each column of @var{B} is assumed to be distinct blocks, with no ## overlapping elements, of size @var{block_size}, to rebuild a matrix of ## size @var{A_size}. Any padding that may have been required to form ## @var{B} from a matrix of @var{A_size}, is removed accordingly. ## ## @item @qcode{"sliding"} ## This reshapes @var{B} into a matrix of size ## @code{@var{A_size} - @var{block_size} +1}. Sliding blocks are most useful ## to apply a sliding window filter with functions that act along columns. ## In this situation, @var{B} is usually a row vector, so that if ## @var{block_size} is [1 1], @var{A_SIZE} will be the size of the output ## matrix. When converting a matrix into blocks with @code{im2col}, there ## will be less blocks to account to borders, so if @var{block_size} is the ## same in both @code{col2im} and @code{im2col}, @var{A_size} can be the size ## out the output from @code{im2col}. ## ## @end table ## ## Blocks are assumed to have been from a matrix, the same direction elements ## are organized in an Octave matrix (top to bottom, then left to right), and ## the direction that blocks are taken in @code{im2col}. ## ## @group ## @example ## ## Get distinct blocks of size [2 3] from A into columns, and ## ## put them back together into the original position ## A = reshape (1:24, [4 6]) ## B = im2col (A, [2 3], "distinct") ## col2im (B, [2 3], [4 6], "distinct") ## @end example ## ## @example ## ## Get sliding blocks of size [2 3] from A into columns, calculate ## ## the mean of each block (mean of each column), and reconstruct A. ## ## This is the equivalent to a sliding window filter and ignoring ## ## borders. ## A = reshape (1:24, [4 6]) ## B = im2col (A, [2 3], "sliding") ## C = mean (B); ## col2im (C, [1 1], [3 4], "sliding") ## @end example ## @end group ## ## @seealso{blockproc, bestblk, colfilt, im2col, nlfilter, reshape} ## @end deftypefn function A = col2im (B, block_size, A_size, block_type = "sliding") if (nargin < 3 || nargin > 4) print_usage (); elseif (! isnumeric (B) && ! islogical (B)) error ("col2im: B must be a numeric of logical matrix or vector"); elseif (! isnumeric (block_size) || ! isvector (block_size)) error("col2im: BLOCK_SIZE must be a numeric vector"); elseif (! isnumeric (A_size) || ! isvector (A_size)) error("col2im: A_SIZE must be a numeric vector"); elseif (! ischar (block_type)) error ("col2im: BLOCK_TYPE must be a string"); endif ## Make sure dimensions are row vectors block_size = block_size(:).'; A_size = A_size(:).'; ## expand size to include singleton dimensions if required block_size(end+1:numel (A_size)) = 1; A_size(end+1:numel (block_size)) = 1; switch (tolower (block_type)) case "distinct" ## A_size is out_size for distinct blocks if (prod (block_size) != rows (B)) error (["col2im: number of rows in B, must equal number of " ... "elements per block (prod (BLOCK_SIZE))"]); elseif (numel (B) < prod (A_size)) error ("col2im: not enough elements in B for a matrix of A_SIZE"); endif ## Calculate the number of blocks accross each dimension, and ## how much of padding we will need to remove (we calculate the ## number of cumulative elements by dimension, so the first ## element is the number of rows that are pad, the second ## second is the number of columns that are pad times the number ## of elements in a column, and so on for other dimensions) blocks = ceil (A_size ./ block_size); padding = mod (-A_size, block_size) .* [1 cumprod(A_size(1:end-1))]; cum_blk_size = [1 cumprod(block_size(1:end-1))]; cum_blocks = [1 cumprod(blocks(1:end-1))]; ## End of each block dimension in the column end_blk = ceil (cum_blk_size .* (block_size -1)); ## How much in the columns we need to shift to move to the ## next block per dimension. stride = rows (B) * cum_blocks; ## Last block for each dimension last_blk = stride .* (blocks -1); ind = 1; for dim = 1:numel(A_size) ind = ind(:) .+ (0:cum_blk_size(dim):end_blk(dim)); ind = ind(:) .+ (0:stride(dim):last_blk(dim)); ind(end+1-padding(dim):end) = []; # remove padding endfor A = reshape (B(ind(:)), A_size); case "sliding" out_size = A_size - block_size +1; if (prod (out_size) != numel (B)) error ("col2im: can't resize B in matrix sized (A_SIZE - BLOCK_SIZE +1)"); endif A = reshape (B, out_size); otherwise error ("col2im: invalid BLOCK_TYPE `%s'.", block_type); endswitch endfunction %!demo %! ## Divide A using distinct blocks and then reverse the operation %! A = [ 1:10 %! 11:20 %! 21:30 %! 31:40]; %! B = im2col (A, [2 5], "distinct") %! C = col2im (B, [2 5], [4 10], "distinct") %!demo %! ## Get sliding blocks of size from A into columns, calculate the %! ## mean of each block (mean of each column), and reconstruct A %! ## after a median filter. %! A = reshape (1:24, [4 6]) %! B = im2col (A, [2 3], "sliding") %! C = mean (B); %! col2im (C, [1 1], [3 4], "sliding") %!error col2im (ones (10), [5 5], [10 10], "wrong_block_type"); %!error col2im (ones (10), [1 1], [ 7 7], "sliding"); %!error col2im (ones (10), [3 3], [10 10], "distinct") %!error col2im (ones (10), [5 5], [10 11], "distinct"); ## test sliding %!assert (col2im (sum (im2col (magic (10), [3 3], "sliding")), [1 1], [8 8]), %! convn (magic (10), ones (3, 3), "valid")); %!test %! B = ones (1, (10-2+1)*(7-3+1)); %! A = ones ((10-2+1), (7-3+1)); %! assert (col2im (B, [2 3], [10 7]), A); %! %! ## same but different classes %! assert (col2im (int16 (B), [2 3], [10 7]), int16 (A)); %! assert (col2im (single (B), [2 3], [10 7]), single (A)); %! assert (col2im (logical (B), [2 3], [10 7]), logical (A)); ## test default to sliding %!test %! a = rand (10)(:); %! assert (col2im (a, [1 1], [10 10]), col2im (a, [1 1], [10 10], "sliding")) ## test distinct %!shared A, B %! v = [1:10]'; %! r = reshape (1:10, [2 5]); %! B = [v v+10 v+20 v+30 v+40 v+50]; %! A = [r r+30 %! r+10 r+40 %! r+20 r+50]; %! assert (col2im (B, [2 5], [6 10], "distinct"), A); ## respect different classes %!assert (col2im (int16 (B), [2 5], [6 10], "distinct"), int16 (A)); %!assert (col2im (logical (B), [2 5], [6 10], "distinct"), logical (A)); %!assert (col2im (single (B), [2 5], [6 10], "distinct"), single (A)); ## Test for columns with padding %!test %! a = rand (10, 8); %! b = im2col (a, [5 5], "distinct"); %! assert (col2im (b, [5 5], [10 8], "distinct"), a); %! %! a = rand (8); %! b = im2col (a, [5 5], "distinct"); %! assert (col2im (b, [5 5], [8 8], "distinct"), a); ## Test N-dimensional %!shared a, b %! ## Same number of multiple dimensions %! a = rand (10, 10, 10); %! b = im2col (a, [5 5 5], "distinct"); %!assert (col2im (b, [5 5 5], [10 10 10], "distinct"), a); %! %! ## Different number of dimensions %! a = rand (10, 10, 10); %! b = im2col (a, [5 5], "distinct"); %!assert (col2im (b, [5 5], [10 10 10], "distinct"), a); %! %! ## Removing padding from multiple dimensions %! a = rand (10, 10, 7); %! b = im2col (a, [5 5 3], "distinct"); %!assert (col2im (b, [5 5 3], [10 10 7], "distinct"), a); %! %! a = rand (10, 10, 7); %! b = im2col (a, [5 5 5 2], "distinct"); %!assert (col2im (b, [5 5 5 2], [10 10 7], "distinct"), a); image-2.4.1/inst/PaxHeaders.6632/wavelength2rgb.m0000644000000000000000000000013212561122761016334 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/inst/wavelength2rgb.m0000644000175000017500000001444112561122761021163 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 William Krekeler ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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{rgb} =} wavelength2rgb (@var{wavelength}) ## @deftypefnx {Function File} {@var{rgb} =} wavelength2rgb (@var{wavelength}, @var{class}) ## @deftypefnx {Function File} {@var{rgb} =} wavelength2rgb (@var{wavelength}, @var{class}, @var{gamma}) ## Convert wavelength in nm into an RGB value set. ## ## Given a N-dimensional matrix @var{wavelength} with color values in nm, returns ## a RGB image with N+3 dimensions. ## ## @group ## @example ## wavelength2rgb (400) ## @result{} [0.51222 0.00000 0.70849] ## ## wavelength2rgb ([400 410]) ## @result{(:,:,1)} 0.51222 0.49242 ## @result{(:,:,2)} 0 0 ## @result{(:,:,3)} 0.70849 0.85736 ## @end example ## @end group ## ## The @var{rgb} class can be specified with @var{class}. Possible values are ## double (default), single, uint8, uint16, and int16. ## ## @group ## @example ## wavelength2rgb (400) ## @result{} 0.51222 0.00000 0.70849 ## ## wavelength2rgb (400, "uint8") ## @result{} 131 0 181 ## @end example ## @end group ## ## The luminance of colors can be adjusted with @var{gamma} which must a scalar ## value in the range [0 1]. Defaults to 0.8. ## ## Reference: ## @itemize @bullet ## @item @uref{http://stackoverflow.com/questions/2374959/algorithm-to-convert-any-positive-integer-to-an-rgb-value} ## @item @uref{http://www.midnightkite.com/color.html} per Dan Bruton ## @end itemize ## @end deftypefn function rgb = wavelength2rgb (wavelength, out_class = "double", gamma = 0.8) if (nargin < 1 || nargin > 3) print_usage; elseif (!isnumeric (wavelength) || any (wavelength <= 0)) error ("wavelength2rgb: wavelength must a positive numeric"); elseif (!ischar (out_class) || all (!strcmpi (out_class, {"single", "double", "uint8", "uint16", "int16"}))) error ("wavelength2rgb: unsupported class `%s'", char (out_class)); elseif (!isnumeric (gamma) || !isscalar (gamma) || gamma > 1 || gamma < 0) error ("wavelength2rgb: gamma must a numeric scalar between 1 and 0"); endif ## initialize rgb. One extra dimension of size 3 for RGB. Later on, we will ## use ndims and when input is a scalar, ndims still returns 2 which means ## output would be 1x1x3. Check this and adjust later on if (isscalar (wavelength)) rgb = zeros (1, 3); size_adjust = 1; else rgb = zeros ([size(wavelength), 3]); size_adjust = 0; endif ## this RGBmask's will be used for broadcasting later Rmask = Gmask = Bmask = false ([ones(1, ndims (wavelength) - size_adjust) 3]); Rmask(1) = true; Gmask(2) = true; Bmask(3) = true; ## for each group of wavelengths we calculate the mask, expand for the 3 ## channels and use Rmask, Gmask and Bmask with broadcasting to select the ## right one. Will skip some channels since their values would be zero and ## we already initialized the matrix with zeros() get_rgb_mask = @(mask) repmat (mask, [ones(1, ndims (mask) - size_adjust) 3]); mask = wavelength >= 380 & wavelength < 440; rgbmask = get_rgb_mask (mask); rgb(rgbmask & Rmask) = -(wavelength(mask) - 440) / 60; # 60 comes from 440-380 ## skiping green channel (values of zero) rgb(rgbmask & Bmask) = 1; mask = wavelength >= 440 & wavelength < 490; rgbmask = get_rgb_mask (mask); ## skiping red channel (values of zero) rgb(rgbmask & Gmask) = (wavelength(mask) - 440) / 50; # 50 comes from 490-440 rgb(rgbmask & Bmask) = 1; mask = wavelength >= 490 & wavelength < 510; rgbmask = get_rgb_mask (mask); ## skiping red channel (values of zero) rgb(rgbmask & Gmask) = 1; rgb(rgbmask & Bmask) = -(wavelength(mask) - 510) / 20; # 20 comes from 510-490 mask = wavelength >= 510 & wavelength < 580; rgbmask = get_rgb_mask (mask); rgb(rgbmask & Rmask) = (wavelength(mask) - 510) / 70; # 70 comes from 580-510 rgb(rgbmask & Gmask) = 1; ## skiping blue channel (values of zero) mask = wavelength >= 580 & wavelength < 645; rgbmask = get_rgb_mask (mask); rgb(rgbmask & Rmask) = 1; rgb(rgbmask & Gmask) = -(wavelength(mask) - 645) / 65; # 65 comes from 645-580 ## skiping blue channel (values of zero) mask = wavelength >= 645 & wavelength <= 780; rgbmask = get_rgb_mask (mask); rgb(rgbmask & Rmask) = 1; ## skiping green channel (values of zero) ## skiping blue channel (values of zero) ## all other wavelengths have values of zero in all channels (black) ## let intensity fall off near the vision limits ## set the factor factor = zeros (size (wavelength)); mask = wavelength >= 380 & wavelength < 420; factor(mask) = 0.3 + 0.7*(wavelength(mask) - 380) / 40; # 40 = 420 - 380 mask = wavelength >= 420 & wavelength <= 700; factor(mask) = 1; mask = wavelength > 700 & wavelength <= 780; factor(mask) = 0.3 + 0.7*(780 - wavelength(mask)) / 80; # 80 = 780 - 700 ## for other wavelengths, factor is 0 ## expand factor for the 3 channels factor = repmat (factor, [ones(1, ndims (factor) - size_adjust) 3]); ## correct rgb rgb = (rgb .* factor) .^gamma; ## scale to requested class switch tolower (out_class) case {"single"} rgb = im2single (rgb); case {"double"} ## do nothing, already class double case {"uint8"} rgb = im2uint8 (rgb); case {"uint16"} rgb = im2uint16 (rgb); case {"int16"} rgb = im2int16 (rgb); otherwise error ("wavelength2rgb: unsupported class `%s'", out_class) endswitch endfunction %!demo %! %! ##draw RGB values for wavelengths between 350 and 800 nm %! RGB = wavelength2rgb (350:800); %! rgbplot (squeeze (RGB), "composite"); %! axis off; image-2.4.1/inst/PaxHeaders.6632/medfilt2.m0000644000000000000000000000013212561122761015121 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/medfilt2.m0000644000175000017500000001035112561122761017744 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Teemu Ikonen ## ## 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 3 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} {} medfilt2 (@var{A}) ## @deftypefnx {Function File} {} medfilt2 (@var{A}, @var{nhood}) ## @deftypefnx {Function File} {} medfilt2 (@var{A}, [@var{M} @var{N}]) ## @deftypefnx {Function File} {} medfilt2 (@dots{}, @var{pad}) ## Two dimensional median filtering. ## ## Replaces elements of @var{A} with the median of their neighbours as defined ## by the true elements of logical matrix @var{nhood} or by a matrix of size ## @var{M} by @var{N}. The default @var{nhood} is a 3 by 3 matrix of true ## elements. ## ## @example ## @group ## ## median filtering specifying neighborhood dimensions ## medfilt2 (img) # default is [3 3] ## medfilt2 (img, [3 1]) # a 3x1 vector ## medfilt2 (img, [5 5]) # 5 element wide square ## @end group ## ## @group ## ## median filtering specifying neighborhood ## medfilt2 (img, true (5)) # same as [5 5] ## nhood = logical ([0 1 0 ## 1 1 1 ## 0 1 0]); ## medfilt2 (img, nhood) # 3 element wide cross ## @end group ## @end example ## ## The optional variable @var{pad} defines the padding used in augmenting ## the borders of @var{A}. See @code{padarray} for details. ## @seealso{ordfilt2, ordfiltn} ## @end deftypefn function retval = medfilt2 (A, varargin) if (nargin < 1 || nargin > 3) print_usage (); elseif (! isimage (A)) error ("medfilt2: A must be a real matrix") endif ## defaults padding = "zeros"; domain = true (3, 3); for idx = 1:numel (varargin) opt = varargin{idx}; if (ischar (opt) || isscalar (opt)) padding = opt; elseif (isnumeric (opt) || islogical (opt)) ## once we have removed the ability of selecting domain with a non logical ## matrix, we can use it to make this N dimensional domain = [3 3 3]. if (isvector (opt) && ! islogical (opt) && numel (opt) == 2) domain = true (opt); else if (! islogical (opt)) persistent warned = false; if (! warned) warned = true; warning ("medfilt2: to specify filter instead of dimensions use a matrix of logical class. This usage will be removed from future releases of the image package."); endif endif domain = logical (opt); endif else error ("medfilt2: unrecognized option of class %s", class (opt)) endif endfor ## TODO this should probably be implemented as an option of ## __spatial_filtering__ where median() cold be called directly n = nnz (domain); if ((n - 2*floor(n/2)) == 0) % n even - more work nth = floor (n/2); a = ordfiltn (A, nth, domain, padding); b = ordfiltn (A, nth + 1, domain, padding); retval = a./2 + b./2; # split into two divisions to avoid overflow on integer data else nth = floor (n/2) + 1; retval = ordfiltn (A, nth, domain, padding); endif endfunction %!shared b, f %! b = [ 0 1 2 3 %! 1 8 12 12 %! 4 20 24 21 %! 7 22 25 18]; %! f = [ 0 1 2 0 %! 1 4 12 3 %! 4 12 20 12 %! 0 7 20 0]; %!assert (medfilt2 (b), f); %! %! f = [ 0 1 2 3 %! 1 8 12 12 %! 4 20 24 18 %! 4 20 24 18]; %!assert (medfilt2 (b, true (3, 1)), f); %!assert (medfilt2 (b, [3 1]), f); %! %! f = [ 1 8 10 10 %! 1 8 12 12 %! 4 20 24 18 %! 7 20 24 18]; %!assert (medfilt2 (b, [3 1], 10), f); %!assert (medfilt2 (b, 10, [3 1]), f); %! %! f = [ 0.5 4.5 7.0 7.5 %! 2.5 14.0 18.0 15.0 %! 2.5 14.0 18.0 15.0 %! 2.0 10.0 12.0 9.0]; %!assert (medfilt2 (b, true (4, 1)), f); %!assert (medfilt2 (b, [4 1]), f); image-2.4.1/inst/PaxHeaders.6632/rgb2ycbcr.m0000644000000000000000000000013212561122761015272 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/rgb2ycbcr.m0000644000175000017500000000511712561122761020121 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{YCbCrmap} =} rgb2ycbcr (@var{cmap}) ## @deftypefnx {Function File} {@var{YCbCr} =} rgb2ycbcr (@var{RGB}) ## @deftypefnx {Function File} {@dots{} =} rgb2ycbcr (@dots{}, [@var{Kb} @var{Kr}]) ## @deftypefnx {Function File} {@dots{} =} rgb2ycbcr (@dots{}, @var{standard}) ## Convert RGB values to YCbCr. ## ## The conversion changes the image @var{RGB} or colormap @var{cmap}, from ## the RGB color model to YCbCr (luminance, chrominance blue, and chrominance ## red). @var{RGB} must be of class double, single, uint8, or uint16. ## ## The formula used for the conversion is dependent on two constants, @var{Kb} ## and @var{Kr} which can be specified individually, or according to existing ## standards: ## ## @table @asis ## @item "601" (default) ## According to the ITU-R BT.601 (formerly CCIR 601) standard. Its values ## of @var{Kb} and @var{Kr} are 0.114 and 0.299 respectively. ## @item "709" (default) ## According to the ITU-R BT.709 standard. Its values of @var{Kb} and ## @var{Kr} are 0.0722 and 0.2116 respectively. ## @end table ## ## @seealso{hsv2rgb, ntsc2rgb, rgb2hsv, rgb2ntsc} ## @end deftypefn function ycbcr = rgb2ycbcr (rgb, standard = "601") if (nargin < 1 || nargin > 2) print_usage (); endif ycbcr = ycbcrfunc ("rgb2ycbcr", rgb, standard); endfunction %!test %! in(:,:,1) = magic (5); %! in(:,:,2) = magic (5); %! in(:,:,3) = magic (5); %! out(:,:,1) = [31 37 17 23 29 %! 36 20 22 28 30 %! 19 21 27 33 35 %! 25 26 32 34 19 %! 25 31 37 18 24]; %! out(:,:,2) = 128; %! out(:,:,3) = 128; %! assert (rgb2ycbcr (uint8 (in)), uint8 (out)); %!shared cbcr %! cbcr = 0.5019607843137255; %! out(1:10, 1) = linspace (16/255, 235/255, 10); %! out(:, [2 3]) = cbcr; %! assert (rgb2ycbcr (gray (10)), out, 0.00001); %!assert (rgb2ycbcr ([1 1 1]), [0.92157 cbcr cbcr], 0.0001); image-2.4.1/inst/PaxHeaders.6632/imclose.m0000644000000000000000000000013212561122761015046 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imclose.m0000644000175000017500000001114712561122761017675 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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} {} imclose (@var{img}, @var{SE}) ## Perform morphological closing. ## ## The matrix @var{img} must be numeric while @var{SE} can be a: ## @itemize @bullet ## @item ## strel object; ## @item ## array of strel objects as returned by `@@strel/getsequence'; ## @item ## matrix of 0's and 1's. ## @end itemize ## ## The closing corresponds to a dilation followed by an erosion of @var{img}, ## using the same @var{SE}, i.e., it is equivalent to: ## @example ## imerode (imdilate (img, se), se); ## @end example ## ## @seealso{imdilate, imerode, imopen} ## @end deftypefn function closed = imclose (img, se) if (nargin != 2) print_usage (); elseif (! isimage (img)) error("imclose: IMG must be a numeric matrix"); endif se = prepare_strel ("imclose", se); ## Perform filtering closed = imerode (imdilate (img, se), se); endfunction %!shared in, out %! in = [ 0 0 0 1 1 1 0 0 1 1 %! 0 1 0 1 1 1 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 0 %! 0 1 1 1 1 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 1 1 1 %! 0 0 0 0 1 0 1 0 1 0 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 0 1 1 1 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! %! out = [ 1 1 1 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 1 %! 0 0 0 1 1 0 0 0 1 1 %! 0 0 0 1 1 1 1 1 1 1 %! 0 0 0 1 1 1 1 1 1 1 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 1 1 1 1 0 0 0 %! 0 0 0 1 1 1 1 0 0 0]; %!assert (imclose (logical (in), ones (3)), logical (out)); %! %! out = [99 99 16 16 16 73 74 64 64 64 %! 98 88 16 16 16 73 71 64 64 64 %! 93 88 88 61 61 61 68 70 70 70 %! 93 88 88 61 61 61 68 71 71 71 %! 93 93 88 61 61 61 68 75 66 66 %! 79 79 82 90 90 49 49 49 49 66 %! 79 79 82 91 91 48 46 46 46 66 %! 79 79 82 95 97 48 46 46 46 72 %! 18 18 94 96 84 48 46 46 46 59 %! 18 18 100 96 84 50 50 50 50 59]; %!assert (imclose (magic (10), ones (3)), out); %!assert (imclose (uint8 (magic (10)), strel ("square", 3)), uint8 (out)); %! %! ## using a se that will be decomposed in 2 pieces %! out =[ 99 99 88 74 74 74 74 70 70 70 %! 98 93 88 74 74 74 74 70 70 70 %! 93 93 88 74 74 74 74 70 70 70 %! 93 93 88 74 74 74 74 71 71 71 %! 93 93 88 75 75 75 75 75 75 75 %! 93 93 90 90 90 72 72 72 72 72 %! 93 93 91 91 91 72 72 72 72 72 %! 93 93 93 95 97 72 72 72 72 72 %! 94 94 94 96 97 72 72 72 72 72 %! 100 100 100 97 97 72 72 72 72 72]; %!assert (imclose (magic (10), ones(5)), out); %! %! ## using a weird non-symmetric and even-size se %! out =[ 92 99 16 16 16 70 74 58 58 58 %! 98 88 60 73 16 73 69 70 64 58 %! 88 81 88 60 60 60 69 69 70 70 %! 87 87 61 68 61 60 68 69 71 69 %! 86 93 87 61 61 61 68 75 68 69 %! 23 82 89 89 90 45 68 45 68 66 %! 23 23 82 89 91 48 45 45 45 66 %! 79 23 82 95 97 46 48 46 45 72 %! 18 79 94 96 78 50 46 46 46 59 %! 18 18 100 94 94 78 50 50 46 59]; %!assert (imclose (magic (10), [1 0 0 0; 1 1 1 0; 0 1 0 1]), out); image-2.4.1/inst/PaxHeaders.6632/analyze75write.m0000644000000000000000000000013212561122761016305 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/analyze75write.m0000644000175000017500000002431112561122761021131 0ustar00carandraugcarandraug00000000000000%% Copyright (C) 2012 Adam H Aitkenhead %% %% 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 3 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} analyze75write (@var{filename}, @var{data}, @var{header}) %% @deftypefnx {Function File} analyze75write (@var{filename}, @var{data}, @var{x}, @var{y}, @var{z}) %% @deftypefnx {Function File} analyze75write (@var{filename}, @var{data}, @var{header}, @var{x}, @var{y}, @var{z}) %% Write image data to an Analyze 7.5 file. %% %% @var{filename} is the path to write the Analyze 7.5 file; @var{data} is %% the 3D image data; @var{header} is a structure containing the file %% information; @var{x}, @var{y}, @var{z} are lists of the x,y,z coordinates %% (in cm) of the data grid. %% %% @seealso{analyze75info, analyze75read} %% @end deftypefn %% Author: Adam H. Aitkenhead function analyze75write (varargin); if (nargin ~= 3 && nargin ~= 5 && nargin ~= 6) print_usage; else filename = varargin{1}; data = varargin{2}; if (nargin ==3) header = varargin{3}; x = ( (0:header.Dimensions(2)-1) - (header.Dimensions(2)-1)/2 ) * header.PixelDimensions(2); y = ( (0:header.Dimensions(1)-1) - (header.Dimensions(1)-1)/2 ) * header.PixelDimensions(1); z = ( (0:header.Dimensions(3)-1) - (header.Dimensions(3)-1)/2 ) * header.PixelDimensions(3); % Convert mm to cm if strncmpi(header.VoxelUnits,'mm',2)==1 x = x / 10; y = y / 10; z = z / 10; end elseif (nargin ==5) header = struct; x = varargin{3}; y = varargin{4}; z = varargin{5}; elseif (nargin ==6) header = varargin{3}; x = varargin{4}; y = varargin{5}; z = varargin{6}; end end if (~ischar (filename)) error ('analyze75write: `filename'' must be a string.'); end %% Strip the filename of the extension fileextH = strfind (filename, '.hdr'); fileextI = strfind (filename, '.img'); if (~isempty (fileextH)) fileprefix = filename(1:fileextH(end)-1); elseif (~isempty (fileextI)) fileprefix = filename(1:fileextI(end)-1); else fileprefix = filename; end % Check the byteorder if (nargin == 6) if (isfield (header, 'ByteOrder')) && (any (strcmpi (header.ByteOrder, {'ieee-be', 'b'}))) warning ('analyze75write: No support for big-endian. Please consider submitting a patch. Attempting to write as little-endian'); end end header.ByteOrder = 'ieee-le'; %% Rearrange the data data = permute(data,[2,1,3]); % Force uniform slice spacing if (max(unique(diff(z))) - min(unique(diff(z))) > 1e-4) warning ('analyze75write: Data slices must be equally spaced. Attempting to interpolate the data onto equally spaced slices.') [data,z] = interpslices(data,x,y,z); end % Check certain header fields header.PixelDimensions = single(10 * [x(2)-x(1),y(2)-y(1),z(2)-z(1)]); header.Dimensions = int16([size(data),1]); header.HdrFileSize = int32(348); header.VoxelUnits = 'mm '; header.GlobalMin = int32(min(data(:))); header.GlobalMax = int32(max(data(:))); header.FileName = [fileprefix,'.hdr']; % Descriptor: Generate a string containing the coordinates of the first voxel (stored in the header for information only) origintext = ['Coordinates of first voxel: ',num2str( 10* [x(1),y(1),z(1)] ,' %07.2f' )]; header.Descriptor = sprintf('%-80s',origintext); % Determine the type of data if (isa(data,'int16')) header.ImgDataType = 'DT_SIGNED_SHORT'; header.BitDepth = int16(16); DataTypeLabel = int16(4); DataTypeString = 'int16'; elseif (isa(data,'int32')) header.ImgDataType = 'DT_SIGNED_INT'; header.BitDepth = int16(32); DataTypeLabel = int16(8); DataTypeString = 'int32'; elseif (isa(data,'single')) header.ImgDataType = 'DT_FLOAT'; header.BitDepth = int16(32); DataTypeLabel = int16(16); DataTypeString = 'single'; elseif (isa(data,'double')) header.ImgDataType = 'DT_DOUBLE'; header.BitDepth = int16(64); DataTypeLabel = int16(64); DataTypeString = 'double'; end % Write the .hdr file fidH = fopen([fileprefix,'.hdr'],'w'); fwrite(fidH,header.HdrFileSize,'int32',header.ByteOrder); % HdrFileSize fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); % HdrDataType fwrite(fidH,repmat(' ',1,18),'char',header.ByteOrder); % DatabaseName fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % Extents fwrite(fidH,zeros(1,1,'int16'),'int16',header.ByteOrder); % SessionError fwrite(fidH,'r','char',header.ByteOrder); % Regular fwrite(fidH,repmat(' ',1,1),'char',header.ByteOrder); % unused fwrite(fidH,zeros(1,1,'int16'),'int16',header.ByteOrder); % unused fwrite(fidH,header.Dimensions(1),'int16',header.ByteOrder); % Dimensions(1) fwrite(fidH,header.Dimensions(2),'int16',header.ByteOrder); % Dimensions(2) fwrite(fidH,header.Dimensions(3),'int16',header.ByteOrder); % Dimensions(3) fwrite(fidH,header.Dimensions(4),'int16',header.ByteOrder); % Dimensions(4) fwrite(fidH,zeros(1,3,'int16'),'int16',header.ByteOrder); % unused fwrite(fidH,header.VoxelUnits,'char',header.ByteOrder); % VoxelUnits if (isfield(header,'CalibrationUnits')) % CalibrationUnits fwrite(fidH,sprintf('%-8s',header.CalibrationUnits(1:min([8,numel(header.CalibrationUnits)]))),'char',header.ByteOrder); else fwrite(fidH,repmat(' ',1,8),'char',header.ByteOrder); end fwrite(fidH,zeros(1,1,'int16'),'int16',header.ByteOrder); % unused fwrite(fidH,DataTypeLabel,'int16',header.ByteOrder); % ImgDataType fwrite(fidH,header.BitDepth,'int16',header.ByteOrder); % BitDepth fwrite(fidH,zeros(1,1,'int16'),'int16',header.ByteOrder); % unused fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % unused fwrite(fidH,header.PixelDimensions(1),'float',header.ByteOrder); % PixelDimensions(1) fwrite(fidH,header.PixelDimensions(2),'float',header.ByteOrder); % PixelDimensions(2) fwrite(fidH,header.PixelDimensions(3),'float',header.ByteOrder); % PixelDimensions(3) fwrite(fidH,zeros(1,4,'single'),'float',header.ByteOrder); % unused fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % VoxelOffset fwrite(fidH,zeros(1,3,'single'),'float',header.ByteOrder); % unused fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % CalibrationMax fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % CalibrationMin fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % Compressed fwrite(fidH,zeros(1,1,'single'),'float',header.ByteOrder); % Verified fwrite(fidH,header.GlobalMax,'int32',header.ByteOrder); % GlobalMax fwrite(fidH,header.GlobalMin,'int32',header.ByteOrder); % GlobalMin fwrite(fidH,header.Descriptor,'char',header.ByteOrder); % Descriptor fwrite(fidH,'none ','char',header.ByteOrder); % AuxFile fwrite(fidH,repmat(' ',1,1),'char',header.ByteOrder); % Orientation fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); % Originator fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); % Generated fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); % Scannumber if (isfield(header,'PatientID')) % PatientID fwrite(fidH,sprintf('%-10s',header.PatientID(1:min([10,numel(header.PatientID)]))),'char',header.ByteOrder); else fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); end if (isfield(header,'ExposureDate')) % ExposureDate fwrite(fidH,sprintf('%-10s',header.ExposureDate(1:min([10,numel(header.ExposureDate)]))),'char',header.ByteOrder); elseif (isfield(header,'StudyDate')) fwrite(fidH,sprintf('%-10s',header.StudyDate(1:min([10,numel(header.StudyDate)]))),'char',header.ByteOrder); else fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); end if (isfield(header,'ExposureTime')) % ExposureTime fwrite(fidH,sprintf('%-10s',header.ExposureTime(1:min([10,numel(header.ExposureTime)]))),'char',header.ByteOrder); elseif (isfield(header,'StudyTime')) fwrite(fidH,sprintf('%-10s',header.StudyTime(1:min([10,numel(header.StudyTime)]))),'char',header.ByteOrder); else fwrite(fidH,repmat(' ',1,10),'char',header.ByteOrder); end fwrite(fidH,repmat(' ',1,3),'char',header.ByteOrder); % unused fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % Views fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % VolumesAdded fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % StartField fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % FieldSkip fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % OMax fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % OMin fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % SMax fwrite(fidH,zeros(1,1,'int32'),'int32',header.ByteOrder); % SMin fclose(fidH); % Write the .img file fidI = fopen([fileprefix,'.img'],'w'); fwrite(fidI,data,DataTypeString,header.ByteOrder); fclose(fidI); end function [datanew,znew] = interpslices(data,x,y,z) znew = z(1):min(diff(z)):z(end); datanew = zeros(numel(x),numel(y),numel(znew),class(data)); for loopN = 1:numel(znew) datanew(:,:,loopN) = interpn(x,y,z,data,x,y,znew(loopN)); end end image-2.4.1/inst/PaxHeaders.6632/stretchlim.m0000644000000000000000000000013212561122761015571 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/stretchlim.m0000644000175000017500000001454612561122761020426 0ustar00carandraugcarandraug00000000000000## 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 3 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{LOW_HIGH} = } stretchlim (@var{I},@var{TOL}) ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I}) ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB},@var{TOL}) ## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB}) ## Finds limits to contrast stretch an image ## ## @code{LOW_HIGH=stretchlim(I,TOL)} returns a vector @var{LOW_HIGH} ## which contains a pair of intensities which can be used in ## @code{imadjust} to stretch the contrast of an image, first of them ## will be lower value (@code{imadjust} would assign 0 to it) and second ## is the upper bound. @var{TOL} specifies the fraction of the image to ## saturate at lower and upper limits. It can be a vector of length 2: ## @code{[LOW_FRACT, HIGH_FRACT]}, or it can be a scalar, in that case ## @code{[LOW_FRACT, HIGH_FRACT]=[TOL, 1-TOL]}. ## ## @var{TOL} can't be larger than 0.50 and for TOL=0 then ## @code{LOW_HIGH=[min(I(:)), max(I(:))]}. ## ## @code{LOW_HIGH=stretchlim(I)} behaves as described but defaults ## @var{TOL} to @code{[0.01, 0.99]}. ## ## @code{LOW_HIGH=stretchlim(RGB,TOL)} returns a 2-by-3 matrix in ## @var{LOW_HIGH} of lower and upper values to saturate for each plane ## of the RGB image in M-by-N-by-3 array @var{RGB}. @var{TOL} is a ## vector or a scalar, as described above, and the same fractions are ## applied for each plane. ## ## @code{LOW_HIGH=stretchlim(RGB)} uses @code{[0.01, 0.99]} as default ## value for @var{TOL}. ## ## @strong{Notes:} ## ## Values in @var{LOW_HIGH} are of type double and comprised between 0 ## and 1 regardless class of input image. ## ## @strong{Compatibility notes:} ## ## @itemize @bullet ## @item ## int* and uint* types are still not implemented (waiting for support ## in Octave 2.1.58). ## @item ## This function tries to find limits that are nearer to saturate ## requested interval. So, for instance, if you requested a 5% and it ## has to choose between discarding a 1% and a 7%, it will choose the ## later despite being more than requested. This should be test against ## MATLAB behaviour. ## @end itemize ## ## @seealso{imadjust} ## @end deftypefn function LOW_HIGH = stretchlim(image, TOL) if (nargin<1 || nargin>2) print_usage; endif if(! isimage (image) ) error("stretchlim: image should be a matrix"); endif ## Prepare limits if(nargin==1) low_count=0.01; high_count=0.01; ## we use this definition in __stretchlim_plane__ else if(isscalar(TOL)) if(TOL<0 || TOL>=0.5) error("stretchlim: TOL out of bounds. Expected: 0<=TOL<0.5"); endif low_count=TOL; high_count=TOL; ## as before... elseif(isvector(TOL)) if(length(TOL)!=2) error("stretchlim: TOL length must be 2."); endif low_count=TOL(1); high_count=1-TOL(2); ## as before... else error("stretchlim: TOL contains an invalid value."); endif endif ## well use size of image several times... simage=size(image); ## Convert fractions to pixels psimage=prod(simage(1:2)); low_count*=psimage; high_count*=psimage; if(length(simage)<=2) ## intensity LOW_HIGH=__stretchlim_plane__(image, low_count, high_count); elseif(length(simage)==3 && simage(3)==3) ## RGB LOW_HIGH=zeros(2,3); for i=1:3 LOW_HIGH(:,i)=__stretchlim_plane__(image(:,:,i), low_count, ... high_count); endfor else error("stretchlim: invalid image."); endif endfunction ## Processes a plane ## high_count is defined so that high_count=elements is the same as ## low_count=elements (and not total_elements-elements) function LOW_HIGH = __stretchlim_plane__(plane, low_count, high_count) ## check exceptions if(low_count==0 && high_count==0) LOW_HIGH=[min(plane(:)); max(plane(:))]; else ## we sort values sorted=sort(plane(:)); low=sorted(round(low_count+1)); pos=find(sorted>low); if(length(pos)>0) low2=sorted(pos(1)); d1=low_count-sum(sorted0) high2=sorted(pos(end)); d1=high_count-sum(sorted>high); d2=sum(sorted>high2)-high_count; if(d2 1% lost %!# test RGB %!test %! RGB=zeros(100,1,3); %! RGB(:,:,1)=[1:100]; %! RGB(:,:,2)=[2:2:200]; %! RGB(:,:,3)=[4:4:400]; %! assert(stretchlim(RGB),[2,4,8;99,198,396]); image-2.4.1/inst/PaxHeaders.6632/regionprops.m0000644000000000000000000000013212561122761015762 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/regionprops.m0000644000175000017500000004433712561122761020620 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Søren Hauberg ## Copyright (C) 2012 Jordi Gutiérrez Hermoso ## Copyright (C) 2015 Hartmut Gimpel ## ## 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 3 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{props} = } regionprops (@var{BW}) ## @deftypefnx {Function File} {@var{props} = } regionprops (@var{BW}, @var{properties}, @dots{}) ## @deftypefnx {Function File} {@var{props} = } regionprops (@var{L}, @var{properties}, @dots{}) ## @deftypefnx {Function File} {@var{props} = } regionprops (@dots{}, @var{I}, @var{properties}, @dots{}) ## Compute object properties in a binary image. ## ## @code{regionprops} computes various properties of the individual objects (as ## identified by @code{bwlabel}) in the binary image @var{BW}. The result is a ## structure array containing an entry per property per object. ## ## The optional grayscale image @var{I} is used for pixel value measurements ## (MaxIntensity, MinIntensity, MeanIntensity, PixelValues and WeightedCentroid). ## ## The following properties can be computed: ## ## @table @asis ## @item "Area" ## The number of pixels in the object. ## ## @item "BoundingBox" ## @itemx "bounding_box" ## The bounding box of the object. This is represented as a 4-vector where the ## first two entries are the @math{x} and @math{y} coordinates of the upper left ## corner of the bounding box, and the two last entries are the width and the ## height of the box. ## ## @item "Centroid" ## The center coordinate of the object. ## ## @item "Eccentricity" ## The eccentricity of the ellipse that has the same normalized ## second central moments as the object (value between 0 and 1). ## ## @item "EquivDiameter" ## @itemx "equiv_diameter" ## The diameter of a circle with the same area as the object. ## ## @item "EulerNumber" ## @itemx "euler_number" ## The Euler number of the object (see @code{bweuler} for details). ## ## @item "Extent" ## The area of the object divided by the area of the bounding box. ## ## @item "Extrema" ## Returns an 8-by-2 matrix with the extrema points of the object. ## The first column holds the returned x- and the second column the y-values. ## The order of the 8 points is: top-left, top-right, right-top, right-bottom, bottom-right, bottom-left, left-bottom, left-top. ## ## @item "FilledArea" ## @itemx "filled_area" ## The area of the object including possible holes. ## ## @item "FilledImage" ## @itemx "filled_image" ## A binary image with the same size as the object's bounding box that contains ## the object with all holes removed. ## ## @item "Image" ## An image with the same size as the bounding box that contains the original ## pixels. ## ## @item "MajorAxisLength" ## @itemx "major_axis_length" ## The length of the major axis of the ellipse that has the same ## normalized second central moments as the object. ## ## @item "MaxIntensity" ## @itemx "max_intensity" ## The maximum intensity inside the object. ## ## @item "MeanIntensity" ## @itemx "mean_intensity" ## The mean intensity inside the object. ## ## @item "MinIntensity" ## @itemx "min_intensity" ## The minimum intensity inside the object. ## ## @item "MinorAxisLength" ## @itemx "minor_axis_length" ## The length of the minor axis of the ellipse that has the same ## normalized second central moments as the object. ## ## @item "Perimeter" ## The length of the boundary of the object. ## ## @item "PixelIdxList" ## @itemx "pixel_idx_list" ## The indices of the pixels in the object. ## ## @item "Orientation" ## The angle between the x-axis and the major axis of the ellipse that ## has the same normalized second central moments as the object ## (value in degrees between -90 and 90). ## ## @item "PixelList" ## @itemx "pixel_list" ## The actual pixel values inside the object. This is only useful for grey scale ## images. ## ## @item "PixelValues" ## @itemx "pixel_values" ## The pixel values inside the object represented as a vector. ## ## @item "WeightedCentroid" ## @itemx "weighted_centroid" ## The centroid of the object where pixel values are used as weights. ## @end table ## ## The requested properties can either be specified as several input arguments ## or as a cell array of strings. As a short-hand it is also possible to give ## the following strings as arguments. ## ## @table @asis ## @item "basic" ## The following properties are computed: @t{"Area"}, @t{"Centroid"} and ## @t{"BoundingBox"}. This is the default. ## ## @item "all" ## All properties are computed. ## @end table ## ## @seealso{bwlabel, bwperim, bweuler} ## @end deftypefn function retval = regionprops (bw, varargin) ## Check input if (nargin < 1) error ("regionprops: not enough input arguments"); endif prop_start = 1; if (numel (varargin) >= 1 && isnumeric (varargin{1})) if (size_equal (bw, varargin{1})) I = varargin{1}; varargin(1) = []; else error ("regionprops: I must have the same size as BW"); endif else I = bw; endif if (numel (varargin) == 0) properties = {"basic"}; elseif (numel (varargin) == 1 && iscellstr (varargin{1})) properties = varargin{1}; elseif (iscellstr (varargin)) properties = varargin; else error ("regionprops: properties must be a cell array of strings"); endif properties = lower (properties); all_props = {"Area", "EquivDiameter", "EulerNumber", ... "BoundingBox", "Extent", "Perimeter",... "Centroid", "PixelIdxList", "FilledArea", "PixelList",... "FilledImage", "Image", "MaxIntensity", "MinIntensity",... "WeightedCentroid", "MeanIntensity", "PixelValues",... "Orientation", "Eccentricity", "MajorAxisLength", ... "MinorAxisLength", "Extrema"}; if (ismember ("basic", properties)) properties = union (properties, {"Area", "Centroid", "BoundingBox"}); properties = setdiff (properties, "basic"); endif if (ismember ("all", properties)) properties = all_props; endif if (!iscellstr (properties)) error ("%s %s", "regionprops: properties must be specified as a list of", "strings or a cell array of strings"); endif ## Fix capitalisation, underscores of user-supplied properties... for k = 1:numel (properties) property = lower (strrep(properties{k}, "_", "")); [~, idx] = ismember (property, lower (all_props)); if (!idx) error ("regionprops: unsupported property: %s", property); endif properties(k) = all_props{idx}; endfor N = ndims (bw); ## Get a labelled image if (!islogical (bw) && all (bw >= 0) && all (bw == round (bw))) L = bw; # the image was already labelled num_labels = max (L (:)); elseif (N > 2) [L, num_labels] = bwlabeln (bw); else [L, num_labels] = bwlabel (bw); endif ## Return an empty struct with specified properties if there are no labels if num_labels == 0 retval = struct ([properties; repmat({{}}, size(properties))]{:}); return; endif ## Compute the properties retval = struct (); for property = lower(properties) property = property{:}; switch (property) case "area" for k = 1:num_labels retval (k).Area = local_area (L == k); endfor case "equivdiameter" if (N > 2) warning ("regionprops: skipping equivdiameter for Nd image"); else for k = 1:num_labels area = local_area (L == k); retval (k).EquivDiameter = sqrt (4*area/pi); endfor endif case "eulernumber" for k = 1:num_labels retval (k).EulerNumber = bweuler (L == k); endfor case "boundingbox" for k = 1:num_labels retval (k).BoundingBox = local_boundingbox (L == k); endfor case "extent" for k = 1:num_labels bb = local_boundingbox (L == k); area = local_area (L == k); idx = length (bb)/2 + 1; retval (k).Extent = area / prod (bb(idx:end)); endfor case "perimeter" if (N > 2) warning ("regionprops: skipping perimeter for Nd image"); else for k = 1:num_labels retval (k).Perimeter = sum (bwperim (L == k) (:)); endfor endif case "centroid" for k = 1:num_labels C = all_coords (L == k, true); retval (k).Centroid = [mean(C)]; endfor case "pixelidxlist" for k = 1:num_labels retval (k).PixelIdxList = find (L == k); endfor case "filledarea" for k = 1:num_labels retval (k).FilledArea = sum (bwfill (L == k, "holes") (:)); endfor case "pixellist" for k = 1:num_labels C = all_coords (L == k, true, true); retval (k).PixelList = C; endfor case "filledimage" for k = 1:num_labels retval (k).FilledImage = bwfill (L == k, "holes"); endfor case "image" for k = 1:num_labels tmp = (L == k); C = all_coords (tmp, false); idx = arrayfun (@(x,y) x:y, min (C), max (C), "unif", 0); idx = substruct ("()", idx); retval (k).Image = subsref (tmp, idx); endfor case "maxintensity" for k = 1:num_labels retval (k).MaxIntensity = max (I(L == k)(:)); endfor case "minintensity" for k = 1:num_labels retval (k).MinIntensity = min (I(L == k)(:)); endfor case "weightedcentroid" for k = 1:num_labels C = all_coords (L == k, true, true); vals = I(L == k)(:); vals /= sum (vals); retval (k).WeightedCentroid = [dot(C, repmat(vals, 1, columns(C)), 1)]; endfor case "meanintensity" for k = 1:num_labels retval (k).MeanIntensity = mean (I(L == k)(:)); endfor case "pixelvalues" for k = 1:num_labels retval (k).PixelValues = I(L == k)(:); endfor case "majoraxislength" if (N > 2) warning ("regionprops: skipping majoraxislength for ND image"); break endif for k = 1:num_labels [Y, X] = find (L == k); if (numel (Y) > 1) [major, ~, ~] = local_ellipsefit (X, Y); retval(k).MajorAxisLength = major; else retval(k).MajorAxisLength = 1; endif endfor case "minoraxislength" if (N > 2) warning ("regionprops: skipping minoraxislength for ND image"); break endif for k = 1:num_labels [Y, X] = find (L == k); if (numel (Y) > 1) [~, minor, ~] = local_ellipsefit (X, Y); retval(k).MinorAxisLength = minor; else retval(k).MinorAxisLength = 1; endif endfor case "eccentricity" if (N > 2) warning ("regionprops: skipping eccentricity for ND image"); break endif for k = 1:num_labels [Y, X] = find (L == k); if (numel (Y) > 1) [major, minor, ~] = local_ellipsefit (X, Y); retval(k).Eccentricity = sqrt (1- (minor/major)^2); else retval(k).Eccentricity = 0; # a circle has 0 eccentricity endif endfor case "orientation" if (N > 2) warning ("regionprops: skipping orientation for ND image"); break endif for k = 1:num_labels [Y, X] = find (L == k); if (numel (Y) > 1) [~, ~, major_vec] = local_ellipsefit (X, Y); retval(k).Orientation = -(180/pi) * atan (major_vec(2) / major_vec(1)); else retval(k).Orientation = 0; endif endfor case "extrema" if (N > 2) warning ("regionprops: skipping extrema for Nd image"); else for k = 1:num_labels pixelidxlist = find (L == k); if length(pixelidxlist) == 0 retval (k).Extrema = repmat (0.5, [8 2]); # for ML compatibility else [pixel_R, pixel_C] = ind2sub (size (L), pixelidxlist); top_r = min (pixel_R); # small "r" and "c" for scalars and capital "R" and "C" for vectors top_R = pixel_C (pixel_R == top_r); top_left_c = min (top_R) - 0.5; # add/substract 0.5 to all values for corner of pixles (as in ML) top_right_c = max (top_R) + 0.5; top_r = top_r - 0.5; right_c = max (pixel_C); right_C = pixel_R (pixel_C == right_c); right_top_r = min (right_C) - 0.5; right_bottom_r = max (right_C) + 0.5; right_c = right_c + 0.5; bottom_r = max (pixel_R); bottom_R = pixel_C (pixel_R == bottom_r); bottom_right_c = max (bottom_R) + 0.5; bottom_left_c = min (bottom_R) - 0.5; bottom_r = bottom_r + 0.5; left_c = min (pixel_C); left_C = pixel_R (pixel_C == left_c); left_bottom_r = max (left_C) + 0.5; left_top_r = min (left_C) - 0.5; left_c = left_c - 0.5; # return 8x2 matrix with x-values in first column and y-values in second column retval(k).Extrema = [top_left_c top_r; top_right_c top_r; ... right_c right_top_r; right_c right_bottom_r; ... bottom_right_c bottom_r; bottom_left_c bottom_r; ... left_c left_bottom_r; left_c left_top_r]; endif endfor endif #case "convexarea" #case "convexhull" #case "solidity" #case "conveximage" #case "subarrayidx" otherwise error ("regionprops: unsupported property '%s'", property); endswitch endfor ## Matlab returns a column vector struct array. retval = retval(:); endfunction function retval = local_area (bw) retval = sum (bw (:)); endfunction function retval = local_boundingbox (bw) C = all_coords (bw); retval = [min(C) - 0.5, max(C) - min(C) + 1]; endfunction function C = all_coords (bw, flip = true, singleton = false) N = ndims (bw); idx = find (bw); C = cell2mat (nthargout (1:N, @ind2sub, size(bw), idx(:))); ## Coordinate convention for 2d images is to flip the X and Y axes ## relative to matrix indexing. Nd images inherit this for the first ## two dimensions. if (flip) [C(:, 2), C(:, 1)] = deal (C(:, 1), C(:, 2)); endif ## Some functions above expect to work columnwise, so don't return a ## vector if (rows (C) == 1 && !singleton) C = [C; C]; endif endfunction function [major, minor, major_vec] = local_ellipsefit (X, Y) ## calculate (centralised) second moment of region with pixels [X, Y] C = cov ([X(:), Y(:)], 1); # option 1 for normalisation with n instead of n-1 C = C + 1/12 .* eye (rows (C)); # centralised second moment of 1 pixel is 1/12 [V, lambda] = eig (C); lambda_d = 4 .* sqrt (diag (lambda)); [major, major_idx] = max (lambda_d); major_vec = V(:, major_idx); minor = min(lambda_d); endfunction %!test %! c = regionprops ([0 0 1], 'centroid'); %! assert (c.Centroid, [3 1]) %!test %! c = regionprops ([0 0 1; 0 0 0], 'centroid'); %! assert (c.Centroid, [3 1]) %!test %! c = regionprops ([0 1 1], 'centroid'); #bug 39701 %! assert (c.Centroid, [2.5 1]) %!test %! c = regionprops([0 1 1; 0 0 0], 'centroid'); #bug 39701 %! assert (c.Centroid, [2.5 1]) %!test %! a = zeros (2, 3, 3); %! a(:, :, 1) = [0 1 0; 0 0 0]; %! a(:, :, 3) = a(:, :, 1); %! c = regionprops (a, 'centroid'); %! assert (c.Centroid, [2 1 2]) %!test %! d1=2; d2=4; d3=6; %! a = ones (d1, d2, d3); %! c = regionprops (a, 'centroid'); %! assert (c.Centroid, [mean(1:d2), mean(1:d1), mean(1:d3)], eps) %!test %! a = [0 0 2 2; 3 3 0 0; 0 1 0 1]; %! c = regionprops (a, 'centroid'); %! assert (c(1).Centroid, [3 3], eps) %! assert (c(2).Centroid, [3.5 1], eps) %! assert (c(3).Centroid, [1.5 2], eps) %!test %! img = zeros (3, 9); %! img(2, 1:9) = 0:0.1:0.8; %! bw = im2bw (img, 0.5); %! props = regionprops(bw, img, "WeightedCentroid"); %! ix = 7:9; %! x = sum (img(2,ix) .* (ix)) / sum (img(2,ix)); %! assert (props(1).WeightedCentroid(1), x, 10*eps) %! assert (props(1).WeightedCentroid(2), 2, 10*eps) %!assert (size (regionprops ([1 0 0; 0 0 2], "Area")), [2, 1]) %!test %! a = eye (4); %! t = regionprops (a, "majoraxislength"); %! assert (t.MajorAxisLength, 6.4291, 1e-3); %! t = regionprops (a, "minoraxislength"); %! assert(t.MinorAxisLength, 1.1547 , 1e-3); %! t = regionprops (a, "eccentricity"); %! assert (t.Eccentricity, 0.98374 , 1e-3); %! t = regionprops (a, "orientation"); %! assert (t.Orientation, -45); %! t = regionprops (a, "equivdiameter"); %! assert (t.EquivDiameter, 2.2568, 1e-3); %!test %! b = ones (5); %! t = regionprops (b, "majoraxislength"); %! assert (t.MajorAxisLength, 5.7735 , 1e-3); %! t = regionprops (b, "minoraxislength"); %! assert (t.MinorAxisLength, 5.7735 , 1e-3); %! t = regionprops (b, "eccentricity"); %! assert (t.Eccentricity, 0); %! t = regionprops (b, "orientation"); %! assert (t.Orientation, 0); %! t = regionprops (b, "equivdiameter"); %! assert (t.EquivDiameter, 5.6419, 1e-3); %!test %! c = [0 0 1; 0 1 1; 1 1 0]; %! t = regionprops (c, "minoraxislength"); %! assert (t.MinorAxisLength, 1.8037 , 1e-3); %! t = regionprops (c, "majoraxislength"); %! assert (t.MajorAxisLength, 4.1633 , 1e-3); %! t = regionprops (c, "eccentricity"); %! assert (t.Eccentricity, 0.90128 , 1e-3); %! t = regionprops (c, "orientation"); %! assert (t.Orientation, 45); % t = regionprops (c, "equivdiameter"); % assert (t.EquivDiameter, 2.5231, 1e-3); %!test %! f = [0 0 0 0; 1 1 1 1; 0 1 1 1; 0 0 0 0]; %! t = regionprops (f, "Extrema"); %! shouldbe = [0.5 1.5; 4.5 1.5; 4.5 1.5; 4.5 3.5; 4.5 3.5; 1.5 3.5; 0.5 2.5; 0.5 1.5]; %! assert (t.Extrema, shouldbe, eps); image-2.4.1/inst/PaxHeaders.6632/isind.m0000644000000000000000000000013212561122761014521 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/isind.m0000644000175000017500000000437112561122761017351 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} isind (@var{img}) ## Return true if @var{img} is an indexed image. ## ## A variable can be considered an indexed image if it is a non-sparse ## matrix of size @nospell{MxNx1xK} and: ## ## @itemize @bullet ## @item is of class double but all values are integers greater than ## or equal to 1; ## @item is of class uint8 or uint16. ## @end itemize ## ## @strong{Note:} despite their suggestive names, the functions isbw, ## isgray, isind, and isrgb, are ambiguous since it is not always possible ## to distinguish between those image types. For example, an uint8 matrix ## can be both a grayscale and indexed image. They are good to dismiss ## input as an invalid image type, but not for identification. ## ## @seealso{ind2gray, ind2rgb, isbw, isgray, isindex, isrgb} ## @end deftypefn function bool = isind (img) if (nargin != 1) print_usage; endif bool = false; if (isimage (img) && ndims (img) < 5 && size (img, 3) == 1) switch (class (img)) case "double" bool = isindex (img); case {"uint8", "uint16"} bool = true; endswitch endif endfunction %!assert (isind ([]), false); %!assert (isind (1:10), true); %!assert (isind (0:10), false); %!assert (isind (1), true); %!assert (isind (0), false); %!assert (isind ([1.3 2.4]), false); %!assert (isind ([1 2; 3 4]), true); %!assert (isind (randi(100, 10, 10, 1, 4)), true); %!assert (isind (randi(100, 10, 10, 3, 4)), false); %!assert (isind (randi(100, 10, 10, 1, 4, 2)), false); image-2.4.1/inst/PaxHeaders.6632/imopen.m0000644000000000000000000000013212561122761014702 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imopen.m0000644000175000017500000001120112561122761017520 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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} {} imopen (@var{img}, @var{SE}) ## Perform morphological opening. ## ## The matrix @var{img} must be numeric while @var{SE} can be a: ## @itemize @bullet ## @item ## strel object; ## @item ## array of strel objects as returned by `@@strel/getsequence'; ## @item ## matrix of 0's and 1's. ## @end itemize ## ## The opening corresponds to an erosion followed by a dilation of @var{img}, ## using the same @var{SE}, i.e., it is equivalent to: ## @example ## imdilate (imerode (img, se), se); ## @end example ## ## @seealso{imdilate, imerode, imclose} ## @end deftypefn function opened = imopen (img, se) if (nargin != 2) print_usage (); elseif (! isimage (img)) error("imopen: IMG must be a numeric matrix"); endif se = prepare_strel ("imopen", se); ## Perform filtering opened = imdilate (imerode (img, se), se); endfunction %!shared in, out %! in = [ 0 0 0 1 1 1 0 0 1 1 %! 0 1 0 1 1 1 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 0 %! 0 1 1 1 1 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 1 1 1 %! 0 0 0 0 1 0 1 0 1 0 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 0 1 1 1 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! %! out = [ 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0]; %!assert (imopen (logical (in), ones (3)), logical (out)); %! %! out = [80 80 1 8 15 51 51 51 51 40 %! 80 80 7 8 15 54 55 55 55 40 %! 4 7 7 8 15 54 55 55 55 40 %! 17 17 17 7 3 54 55 55 55 28 %! 17 17 17 2 9 54 54 54 52 33 %! 17 17 17 29 29 29 29 26 33 33 %! 5 5 13 29 29 29 30 32 39 39 %! 6 6 13 29 29 29 30 32 39 39 %! 10 12 77 77 77 35 35 35 39 39 %! 10 12 77 77 77 35 35 35 27 27]; %!assert (imopen (magic (10), ones (3)), out); %!assert (imopen (uint8 (magic (10)), strel ("square", 3)), uint8 (out)); %! %! ## using a se that will be decomposed in 2 pieces %! out =[ 1 1 1 8 15 40 40 40 40 40 %! 4 4 4 8 15 40 40 40 40 40 %! 4 4 4 8 15 40 40 40 40 40 %! 5 5 5 3 3 28 28 28 28 28 %! 5 5 5 2 9 28 28 28 28 28 %! 5 5 13 26 26 26 26 26 26 26 %! 5 5 13 29 29 29 29 29 27 27 %! 6 6 13 29 29 29 29 29 27 27 %! 6 6 13 29 29 29 29 29 27 27 %! 6 6 13 29 29 29 29 29 27 27]; %!assert (imopen (magic (10), ones(5)), out); %! %! ## using a weird non-symmetric and even-size se %! out =[ 7 7 1 8 15 55 51 51 41 40 %! 7 7 7 8 16 55 55 55 51 41 %! 4 9 7 7 16 54 55 54 55 47 %! 25 25 9 9 3 52 54 52 54 28 %! 25 24 25 2 9 33 52 34 52 34 %! 17 24 29 31 29 30 33 26 33 34 %! 17 5 29 31 31 31 30 32 39 33 %! 10 6 13 35 35 29 31 32 45 39 %! 10 12 77 36 36 35 35 31 45 45 %! 11 12 77 77 77 36 36 35 27 45]; %!assert (imopen (magic (10), [1 0 0 0; 1 1 1 0; 0 1 0 1]), out); image-2.4.1/inst/PaxHeaders.6632/imdivide.m0000644000000000000000000000013212561122761015205 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imdivide.m0000644000175000017500000000535012561122761020033 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} imdivide (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{out} =} imdivide (@var{a}, @var{b}, @var{class}) ## Divide image by another image or constant. ## ## If @var{a} and @var{b} are two images of same size and class, @var{a} is divided ## by @var{b}. Alternatively, if @var{b} is a floating-point scalar, @var{a} is divided ## by it. ## ## The class of @var{out} will be the same as @var{a} unless @var{a} is logical ## in which case @var{out} will be double. Alternatively, it can be ## specified with @var{class}. ## ## @emph{Note}: the values are truncated to the mininum value of the output ## class. ## @seealso{imabsdiff, imadd, imcomplement, immultiply, imlincomb, imsubtract} ## @end deftypefn function img = imdivide (img, val, out_class = class (img)) if (nargin < 2 || nargin > 3) print_usage; endif [img, val] = imarithmetics ("imdivide", img, val, out_class); ## matlab doesn't even gives a warning in this situation, it simply returns ## a double precision float if (nargin > 2 && strcmpi (out_class, "logical")) warning ("Ignoring request to return logical as output of division."); endif warning ("off", "Octave:divide-by-zero", "local"); img = img ./ val; endfunction %!assert (imdivide (uint8 ([23 250]), uint8 ([ 2 50])), uint8 ([ 12 5])); # default to first class %!assert (imdivide (uint8 ([56 255]), uint8 ([ 0 0])), uint8 ([255 255])); # dividing by zero works (tested in matlab) %!assert (imdivide (uint8 ([23 250]), 2), uint8 ([ 12 125])); # works subtracting a scalar %!assert (imdivide (uint8 ([23 250]), uint8 ([ 2 50]), "uint16"), uint16 ([ 12 5])); # defining output class works (not in matlab) %!assert (imdivide (logical ([1 1 0 0]), logical ([1 0 1 0])), double ([1 Inf 0 NaN])); # dividing logical matrix (tested in matlab) %!fail ("imdivide (uint8 ([23 250]), uint16 ([23 250]))"); # input needs to have same class image-2.4.1/inst/PaxHeaders.6632/qtgetblk.m0000644000000000000000000000013212561122761015230 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/qtgetblk.m0000644000175000017500000000732212561122761020057 0ustar00carandraugcarandraug00000000000000## 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 3 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{vals}] =} qtgetblk (@var{I}, @var{S}, @var{dim}) ## @deftypefnx {Function File} {[@var{vals},@var{idx}] =} qtgetblk (@var{I}, @var{S}, @var{dim}) ## @deftypefnx {Function File} {[@var{vals},@var{r},@var{c}] =} qtgetblk (@var{I}, @var{S}, @var{dim}) ## Obtain block values from a quadtree decomposition. ## ## [vals]=qtgetblk(I,S,dim) returns a dim-by-dim-by-k array in ## @var{vals} which contains the dim-by-dim blocks in the quadtree ## decomposition (@var{S}, which is returned by qtdecomp) of @var{I}. If ## there are no blocks, an empty matrix is returned. ## ## [vals,idx]=qtgetblk(I,S,dim) returns @var{vals} as described above. ## In addition, it returns @var{idx}, a vector which contains the linear ## indices of the upper left corner of each block returned (the same ## result as find(full(S)==dim)). ## ## [vals,r,c]=qtgetblk(I,S,dim) returns @var{vals} as described, and two ## vectors, @var{r} and @var{c}, which contain the row and column ## coordinates of the blocks returned. ## ## @seealso{qtdecomp, qtsetblk} ## @end deftypefn function [varargout] = qtgetblk(I, S, dim) if (nargin != 3 || nargout > 3) print_usage; endif ## get blocks [i,j,v]=find(S); ## filter the ones which match dim idx=find(v==dim); if(length(idx)==0) for i=1:nargout varargout{i}=[]; endfor else r=i(idx); c=j(idx); ## copy to a dim-by-dim-by-k array vals=zeros(dim,dim,length(idx)); for i=1:length(idx) vals(:,:,i)=I(r(i):r(i)+dim-1,c(i):c(i)+dim-1); endfor varargout{1}=vals; if(nargout==3) varargout{2}=r; varargout{3}=c; elseif(nargout==2) varargout{2}=(c-1)*rows(I)+r; endif endif endfunction %!demo %! [vals,r,c]=qtgetblk(eye(4),qtdecomp(eye(4)),2) %! % Returns 2 blocks, at [1,3] and [3,1] (2*2 zeros blocks) %!shared A,S %! A=[ 1, 4, 2, 5,54,55,61,62; %! 3, 6, 3, 1,58,53,67,65; %! 3, 6, 3, 1,58,53,67,65; %! 3, 6, 3, 1,58,53,67,65; %! 23,42,42,42,99,99,99,99; %! 27,42,42,42,99,99,99,99; %! 23,22,26,25,99,99,99,99; %! 22,22,24,22,99,99,99,99]; %! S=qtdecomp(A,10); %!test %! [va]=qtgetblk(A,S,8); %! [vb,r,c]=qtgetblk(A,S,8); %! [vc,i]=qtgetblk(A,S,8); %! assert(va, vb); %! assert(va, vc); %! assert(i,[]); %! assert(r,[]); %! assert(c,[]); %! R=[]; %! assert(va,R); %!test %! [va]=qtgetblk(A,S,4); %! [vb,r,c]=qtgetblk(A,S,4); %! [vc,i]=qtgetblk(A,S,4); %! assert(va, vb); %! assert(va, vc); %! assert(i, find(full(S)==4)); %! assert(r,[1;5]); %! assert(c,[1;5]); %! R=zeros(4,4,2); %! R(:,:,1)=A(1:4,1:4); %! R(:,:,2)=A(5:8,5:8); %! assert(va,R); %!test %! [va]=qtgetblk(A,S,2); %! [vb,r,c]=qtgetblk(A,S,2); %! [vc,i]=qtgetblk(A,S,2); %! assert(va, vb); %! assert(va, vc); %! assert(i, find(full(S)==2)); %! assert(r,[7;5;7;1;3;1;3]); %! assert(c,[1;3;3;5;5;7;7]); %! R=zeros(2,2,7); %! R(:,:,1)=A(7:8,1:2); %! R(:,:,2)=A(5:6,3:4); %! R(:,:,3)=A(7:8,3:4); %! R(:,:,4)=A(1:2,5:6); %! R(:,:,5)=A(3:4,5:6); %! R(:,:,6)=A(1:2,7:8); %! R(:,:,7)=A(3:4,7:8); %! assert(va,R); image-2.4.1/inst/PaxHeaders.6632/subimage.m0000644000000000000000000000013212561122761015207 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/subimage.m0000644000175000017500000000507012561122761020034 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} subimage (@var{bw}) ## @deftypefnx {Function File} {} subimage (@var{img}) ## @deftypefnx {Function File} {} subimage (@var{rgb}) ## @deftypefnx {Function File} {} subimage (@var{ind}, @var{cmap}) ## @deftypefnx {Function File} {} subimage (@var{x}, @var{y}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} subimage (@dots{}) ## Display images in subplots. ## ## A single figure, even with multiple subplots, is limited to a single ## colormap. With the exception of truecolor images, images will use the ## figure colormap which make it impossible to have multiple images with ## different display. This function transforms any image in truecolor ## to workaround this limitation. ## ## The new subimage is displayed as if using @code{image}. The optional ## arguments @var{x} and @var{y} are passed to @code{image} to specify the ## range of the axis labels. ## ## @seealso{image, imagesc, imshow, subplot} ## @end deftypefn function h = subimage (varargin) if (nargin < 1 || nargin > 4) print_usage (); endif if (nargin < 3) alternative_xy = false; im_ind = 1; else alternative_xy = true; im_ind = 3; if (numel (varargin{1}) == 2 && numel (varargin{2}) == 2) x = varargin{1}; y = varargin{2}; else error ("subimage: X and Y must be two element vectors each"); endif endif im = varargin{im_ind}; if (numel (varargin) > im_ind) rgb = ind2rgb (im, varargin{im_ind +1}); elseif (isbw (im)) rgb = repmat (im2uint8 (im), [1 1 3 1]); elseif (isgray (im)) rgb = repmat (im, [1 1 3 1]); elseif (isrgb (im)) rgb = im; else error ("subimage: no valid BW, IMG, IND, or RGB images in input arguments"); endif if (alternative_xy) tmp_h = image (x, y, rgb); else tmp_h = image (rgb); endif if (nargout > 0) h = tmp_h; endif endfunction image-2.4.1/inst/PaxHeaders.6632/radon.m0000644000000000000000000000013212561122761014516 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/radon.m0000644000175000017500000000454312561122761017347 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Alexander Barth ## ## 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 3 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{RT},@var{xp}] =} radon(@var{I}, @var{theta}) ## @deftypefnx {Function File} {[@var{RT},@var{xp}] =} radon(@var{I}) ## ## Calculates the 2D-Radon transform of the matrix @var{I} at angles given in ## @var{theta}. To each element of @var{theta} corresponds a column in @var{RT}. ## The variable @var{xp} represents the x-axis of the rotated coordinate. ## If @var{theta} is not defined, then 0:179 is assumed. ## @end deftypefn function [RT,xp] = radon (I,theta) ## Input checking if (nargin == 0 || nargin > 2) print_usage (); elseif (nargin == 1) theta = 0:179; endif if (! isnumeric (I) || ndims (I) != 2) error("radon: I must be a MxN numeric matrix"); endif if (!isvector(theta)) error("radon: second input must be a vector"); endif [m, n] = size (I); # center of image xc = floor ((m+1)/2); yc = floor ((n+1)/2); # divide each pixel into 2x2 subpixels d = reshape (I,[1 m 1 n]); d = d([1 1],:,[1 1],:); d = reshape (d,[2*m 2*n])/4; b = ceil (sqrt (sum (size (I).^2))/2 + 1); xp = [-b:b]'; sz = size(xp); [X,Y] = ndgrid (0.75 - xc + [0:2*m-1]/2,0.75 - yc + [0:2*n-1]/2); X = X(:)'; Y = Y(:)'; d = d(:)'; th = theta*pi/180; for l=1:length (theta) # project each pixel to vector (-sin(th),cos(th)) Xp = -sin (th(l)) * X + cos (th(l)) * Y; ip = Xp + b + 1; k = floor (ip); frac = ip-k; RT(:,l) = accumarray (k',d .* (1-frac),sz) + accumarray (k'+1,d .* frac,sz); endfor endfunction %!test %! A = radon(ones(2,2),30); %! assert (A,[0 0 0.608253175473055 2.103325780167649 1.236538105676658 0.051882938682637 0]',1e-10) image-2.4.1/inst/PaxHeaders.6632/nlfilter.m0000644000000000000000000000013212561122761015232 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/nlfilter.m0000644000175000017500000001425512561122761020064 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} nlfilter (@var{A}, @var{block_size}, @var{func}) ## @deftypefnx {Function File} {} nlfilter (@var{A}, @var{block_size}, @var{func}, @dots{}) ## @deftypefnx {Function File} {} nlfilter (@var{A}, "indexed", @dots{}) ## Process matrix in sliding blocks with user-supplied function. ## ## Executes the function @var{fun} on each sliding block of ## size @var{block_size}, taken from the matrix @var{A}. Both the matrix ## @var{A}, and the block can have any number of dimensions. This function ## is specially useful to perform sliding/moving window functions such as ## moving average. ## ## The output will have the same dimensions @var{A}, each one of its values ## corresponding to the processing of a block centered at the same ## coordinates in @var{A}, with @var{A} being padded with zeros for the ## borders (see below for indexed images). In case any side of the block ## is of even length, the center is considered at indices ## @code{floor ([@var{block_size}/2] + 1)}. ## ## The argument @var{func} must be a function handle that takes matrices of ## size @var{block_size} as input and returns a single scalar. Any extra ## input arguments to @code{nlfilter} are passed to @var{func} after the ## block matrix. ## ## If @var{A} is an indexed image, the second argument should be the ## string @qcode{"indexed"} so that any required padding is done correctly ## as done by @code{im2col}. ## ## @emph{Note}: if @var{func} is a column compression function, i.e., it acts ## along a column to return a single value, consider using @code{colfilt} ## which usually performs faster. If @var{func} makes use of the colon ## operator to select all elements in the block, e.g., if @var{func} looks ## anything like @code{@@(x) sum (x(:))}, it is a good indication that ## @code{colfilt} should be used. In addition, many sliding block operations ## have their own specific implementations (see help text of @code{colfilt} ## for a list). ## ## @seealso{blockproc, col2im, colfilt, im2col} ## @end deftypefn function B = nlfilter (A, varargin) ## Input check [p, block_size, padval] = im2col_check ("nlfilter", nargin, A, varargin{:}); if (nargin < p) print_usage (); endif func = varargin{p++}; if (! isa (func, "function_handle")) error ("nlfilter: FUNC must be a function handle"); elseif (! isscalar (func (ones (block_size, class (A)), varargin{p:nargin-1}))) error ("nlfilter: FUNC must take a matrix of size BLOCK_SIZE and return a scalar"); endif ## Remaining params are parameters to fun. We need to place them into ## a separate variable, we can't varargin{p:nargin-1} inside the anonymous ## function because nargin will have a different value there extra_args = varargin(p:nargin -1); ## Pad image as required padded = pad_for_sliding_filter (A, block_size, padval); ## Get the blocks (one per column) blks = im2col (padded, block_size, "sliding"); ## New function that reshapes the array into a block before ## passing it to the actual user supplied function blk_func = @(x, z) func (reshape (blks(x:z), block_size), extra_args{:}); ## Perform the filtering blk_step = 1:(rows (blks)):(rows (blks) * columns (blks)); B = arrayfun (blk_func, blk_step, blk_step + rows (blks) -1); ## Back into its original shape B = reshape (B, size (A)); endfunction %!demo %! ## creates a "wide" diagonal (although it can be performed more %! ## efficiently with "imdilate (A, true (3))") %! nlfilter (eye (10), [3 3], @(x) any (x(:) > 0)) %!assert (nlfilter (eye (4), [2 3], @(x) sum (x(:))), %! [2 2 1 0 %! 1 2 2 1 %! 0 1 2 2 %! 0 0 1 1]); %!assert (nlfilter (eye (4), "indexed", [2 3], @(x) sum (x(:))), %! [4 2 1 2 %! 3 2 2 3 %! 2 1 2 4 %! 4 3 4 5]); %!assert (nlfilter (eye (4), "indexed", [2 3], @(x, y) sum (x(:)) == y, 2), %! logical ([0 1 0 1 %! 0 1 1 0 %! 1 0 1 0 %! 0 0 0 0])); ## Check uint8 and uint16 padding (only the padding since the class of ## the output is dependent on the function and sum() always returns double) %!assert (nlfilter (uint8 (eye (4)), "indexed", [2 3], @(x) sum (x(:))), %! [2 2 1 0 %! 1 2 2 1 %! 0 1 2 2 %! 0 0 1 1]); %!assert (nlfilter (int16 (eye (4)), "indexed", [2 3], @(x) sum (x(:))), %! [4 2 1 2 %! 3 2 2 3 %! 2 1 2 4 %! 4 3 4 5]); ## Check if function class is preserved %!assert (nlfilter (uint8 (eye (4)), "indexed", [2 3], @(x) int8 (sum (x(:)))), %! int8 ([2 2 1 0 %! 1 2 2 1 %! 0 1 2 2 %! 0 0 1 1])); ## Test N-dimensional %!test %! a = randi (10, 20, 20, 20); %! ## extra dimensions on matrix only %! assert (nlfilter (a, [5 5], @(x) max(x(:))), imdilate (a, ones (5))) %! ## extra dimensions on both matrix and block %! assert (nlfilter (a, [5 5 5], @(x) max(x(:))), imdilate (a, ones ([5 5 5]))) %! ## extra dimensions and padding %! assert (nlfilter (a, [3 7], @(x) max(x(:))), imdilate (a, ones ([3 7]))) %! assert (nlfilter (a, [3 7 3], @(x) max(x(:))), imdilate (a, ones ([3 7 3]))) %!test %! a = randi (10, 15, 15, 4, 8, 3); %! assert (nlfilter (a, [3 4 7 5], @(x) max(x(:))), %! imdilate (a, ones ([3 4 7 5]))) ## Just to make sure it's not a bug in imdilate %!test %! a = randi (10, 15, 15, 4, 3, 8); %! ord = ordfiltn (a, 3, ones ([3 7 3 1 5])); %! assert (nlfilter (a, [3 7 3 1 5], @(x) sort (x(:))(3)), ord) %! assert (nlfilter (a, [3 7 3 1 5], @(x, y) sort (x(:))(y), 3), ord) image-2.4.1/inst/PaxHeaders.6632/corr2.m0000644000000000000000000000013212561122761014442 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/corr2.m0000644000175000017500000000235512561122761017272 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## ## 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 3 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{r} = corr2 (@var{I},@var{J}) ## Compute correlation coefficients of images. ## ## The two images @var{I} and @var{J} must be real type matrices or vectors of ## same size. ## @seealso{corr, cov, std2} ## @end deftypefn function r = corr2 (I, J) if (nargin != 2) print_usage (); elseif (! isimage (I) || ! isimage (J)) error ("corr2: I and J must be real matrices"); elseif (! size_equal (I, J)) error ("corr2: I and J must be of same size"); endif r = corr (I(:), J(:)); endfunction image-2.4.1/inst/PaxHeaders.6632/imcast.m0000644000000000000000000000013212561122761014673 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imcast.m0000644000175000017500000001543712561122761017530 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imcast (@var{img}, @var{type}) ## @deftypefnx {Function File} {} imcast (@var{img}, @var{type}, "indexed") ## Convert image to specific data type @var{type}. ## ## Converts a valid image @var{img} into another class @var{type}. A valid ## image must be of class logical, uint8, uint16, int16, single, or double. ## Conversion of images of class logical is valid, but not the inverse, i.e., ## conversion of images into logical class is not supported. Use of ## @code{im2bw} is recommended for such cases. ## ## If the image is indexed, the last argument may be the string ## @qcode{"indexed"}. An indexed image may not be of class int16 or ## single (see @code{isind} for details). ## ## Details on how the conversion is performed is class dependent, and can ## be seen on the help text of @code{im2double}, @code{im2single}, ## @code{im2uint8}, @code{im2uint16}, and @code{im2int16}. ## ## @seealso{im2bw, im2uint8, im2double, im2int16, im2single, im2uint16} ## @end deftypefn function imout = imcast (img, outcls, varargin) if (nargin < 2 || nargin > 3) print_usage (); elseif (nargin == 3 && ! strcmpi (varargin{1}, "indexed")) error ("imcast: third argument must be the string \"indexed\""); endif incls = class (img); if (strcmp (outcls, incls)) imout = img; return endif ## we are dealing with indexed images if (nargin == 3) if (! isind (img)) error ("imcast: input should have been an indexed image but it is not."); endif ## Check that the new class is enough to hold all the previous indices ## If we are converting to floating point, then we don't bother ## check the range of indices. Also, note that indexed images of ## integer class are always unsigned. ## we will be converting a floating point image to integer class if (strcmp (outcls, "single") || strcmp (outcls, "double")) if (isinteger (img)) imout = cast (img, outcls) +1; else imout = cast (img, outcls); endif ## we will be converting an indexed image to integer class else if (isinteger (img) && intmax (incls) > intmax (outcls) && max (img(:)) > intmax (outcls)) error ("imcast: IMG has too many colours '%d' for the range of values in %s", max (img(:)), outcls); elseif (isfloat (img)) imax = max (img(:)) -1; if (imax > intmax (outcls)) error ("imcast: IMG has too many colours '%d' for the range of values in %s", imax, outcls); endif img -= 1; endif imout = cast (img, outcls); endif ## we are dealing with "normal" images else problem = false; # did we found a bad conversion? switch (incls) case {"double", "single"} switch (outcls) case "uint8", imout = uint8 (img * 255); case "uint16", imout = uint16 (img * 65535); case "int16", imout = int16 (double (img * uint16 (65535)) -32768); case {"double", "single"}, imout = cast (img, outcls); otherwise, problem = true; endswitch case {"uint8"} switch (outcls) case "double", imout = double (img) / 255; case "single", imout = single (img) / 255; case "uint16", imout = uint16 (img) * 257; # 257 comes from 65535/255 case "int16", imout = int16 ((double (img) * 257) -32768); # 257 comes from 65535/255 otherwise, problem = true; endswitch case {"uint16"} switch (outcls) case "double", imout = double (img) / 65535; case "single", imout = single (img) / 65535; case "uint8", imout = uint8 (img / 257); # 257 comes from 65535/255 case "int16", imout = int16 (double (img) -32768); otherwise, problem = true; endswitch case {"logical"} switch (outcls) case {"double", "single"} imout = cast (img, outcls); case {"uint8", "uint16", "int16"} imout = repmat (intmin (outcls), size (img)); imout(img) = intmax (outcls); otherwise problem = true; endswitch case {"int16"} switch (outcls) case "double", imout = (double (img) + 32768) / 65535; case "single", imout = (single (img) + 32768) / 65535; case "uint8", imout = uint8 ((double (img) + 32768) / 257); # 257 comes from 65535/255 case "uint16", imout = uint16 (double (img) + 32768); otherwise, problem = true; endswitch otherwise error ("imcast: unknown image of class \"%s\"", incls); endswitch if (problem) error ("imcast: unsupported TYPE \"%s\"", outcls); endif endif endfunction %!test %! im = randi ([0 255], 40, "uint8"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "uint16"), im2uint16 (im)) %! assert (imcast (im, "single"), im2single (im)) %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "uint16", "indexed"), im2uint16 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([1 256], 40, "double"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([0 65535], 40, "uint16"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "single"), im2single (im)) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([1 255], 40, "double"); %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = rand (40); %! assert (imcast (im, "uint8"), im2uint8 (im)) %!error imcast (randi (127, 40, "int8"), "uint8") %!error imcast (randi (255, 40, "uint8"), "uint32") %!error imcast (randi (255, 40, "uint8"), "not a class") %!error imcast (randi ([0 65535], 40, "uint16"), "uint8", "indexed") image-2.4.1/inst/PaxHeaders.6632/@strel0000644000000000000000000000013212561122761014411 xustar0030 mtime=1438950897.714252238 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/0000755000175000017500000000000012561122761017311 5ustar00carandraugcarandraug00000000000000image-2.4.1/inst/@strel/PaxHeaders.6632/getheight.m0000644000000000000000000000013212561122761016614 xustar0030 mtime=1438950897.706252238 30 atime=1438950897.706252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/getheight.m0000644000175000017500000000205112561122761021435 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## ## 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 3 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{H} =} getheight (@var{SE}) ## Return the heights of a non-flat structuring element. ## If SE is flat, then all heights are zeros. ## ## @seealso{getnhood, strel} ## @end deftypefn function H = getheight (SE) if (SE.flat) H = zeros (size (SE.nhood)); else H = SE.height; endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/size.m0000644000000000000000000000013212561122761015616 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/size.m0000644000175000017500000000241612561122761020444 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 carnë Draug ## ## 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 3 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{TF} =} isflat (@var{SE}) ## Say if a structuring element object is flat or not. ## ## Although in accordance with me TF should be a logical value, it is typed ## double due to compatibility with MATLAB ## (Perhaps there is a good reason which I can't figure out now) ## ## @seealso{strel} ## @end deftypefn ## TODO: if SE is an array of strel, this function return results for any ## strel included. function vals = size (se) if (isempty (se.seq)) vals = [1 1]; else vals = size (se.seq); endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/subsref.m0000644000000000000000000000013212561122761016315 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/subsref.m0000644000175000017500000000330312561122761021137 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## ## 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 3 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 . function req = subsref (se, idx) if (! isa (se, "strel")) error ("object must be of the strel class but '%s' was used", class (se)); elseif (! strcmp (idx(1).type, "()") || numel (idx) > 1) error ("incorrect syntax to reference strel object. Use obj(idx) to access elements."); endif if (isempty (se.seq)) ## for matlab compatibility, if we don't have the sequence, then this is ## still an array of strel objects, it just happens we have we give ## back the object as longsame as 1 element sequence ## so we give the object back. This means the following: ## se(1) <-- works fine ## se(2) <-- fails ## se(1,1,1,1) <-- works fine ## se(1:3) <-- fails ## Yes, this is ugly but we don't have classdef yet... if (any (cellfun (@(x) any (x != 1), idx(1).subs))) error ("A(I): index out of bounds. This is not a sequence of strel object"); endif req = se; else req = se.seq{idx(1).subs{:}}; endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/getsequence.m0000644000000000000000000000013212561122761017154 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/getsequence.m0000644000175000017500000000521112561122761021776 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{seq} =} getsequence (@var{se}) ## Decompose structuring element. ## ## Returns a strel object @var{se} that can be indexed with @code{()} to obtain ## the decomposed structuring elements that can be used to "rebuild" @var{se}. ## ## Decomposing a structuring element may lead to faster operations by ## replacing a single operation with a large @var{se} (large nhood), with ## multiple operations with smaller @var{se}. ## ## Most functions will automatically perform SE decomposition provided a ## strel object is used (instead of a logical array). This also requires ## that specific shapes are specified instead of @qcode{"arbitrary"}, since ## it may prevent SE decomposition. ## ## @seealso{imdilate, imerode, strel} ## @end deftypefn function se = getsequence (se) if (isempty (se.seq)) ## guess a square/cube/rectangle/hyperrectangle shape even if shape ## is arbitrary. There's no need to decompose when it's very small ## hence the no bother if numel > 15 if (se.flat && all (se.nhood(:)) && ! isvector (se.nhood) && numel (se.nhood) > 15) nd = ndims (se.nhood); se.seq = cell (nd, 1); for idx = 1:nd vec_size = ones (1, nd); vec_size(idx) = size (se.nhood, idx); se.seq{idx} = strel ("arbitrary", true (vec_size)); endfor elseif (strcmp (se.shape, "octagon") && se.opt.apothem > 0) persistent octagon_template = get_octagon_template (); se.seq = repmat (octagon_template, se.opt.apothem /3, 1); else se.seq{1,1} = se; endif endif endfunction function template = get_octagon_template () template = repmat ({false(3)}, 4, 1); template{1}(2,:) = true; template{2}(:,2) = true; template{3}([1 5 9]) = true; template{4}([3 5 7]) = true; template = cellfun (@(x) strel ("arbitrary", x), template, "UniformOutput", false); endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/isscalar.m0000644000000000000000000000013212561122761016445 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/isscalar.m0000644000175000017500000000243312561122761021272 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 carnë Draug ## ## 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 3 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{TF} =} isflat (@var{SE}) ## Say if a structuring element object is flat or not. ## ## Although in accordance with me TF should be a logical value, it is typed ## double due to compatibility with MATLAB ## (Perhaps there is a good reason which I can't figure out now) ## ## @seealso{strel} ## @end deftypefn ## TODO: if SE is an array of strel, this function return results for any ## strel included. function retval = isscalar (se) if (isempty (se.seq)) retval = true; else retval = isscalar (se.seq); endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/isflat.m0000644000000000000000000000013212561122761016126 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/isflat.m0000644000175000017500000000232212561122761020750 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## ## 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 3 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{TF} =} isflat (@var{SE}) ## Say if a structuring element object is flat or not. ## ## Although in accordance with me TF should be a logical value, it is typed ## double due to compatibility with MATLAB ## (Perhaps there is a good reason which I can't figure out now) ## ## @seealso{strel} ## @end deftypefn ## TODO: if SE is an array of strel, this function return results for any ## strel included. function TF = isflat (SE) TF = double (SE.flat); endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/strel.m0000644000000000000000000000013212561122761015775 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/strel.m0000644000175000017500000006154612561122761020634 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012, 2013 Roberto Metere ## Copyright (C) 2012, 2013 Carnë Draug ## ## 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 3 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} {} strel (@var{shape}, @var{parameters}) ## Create a strel (structuring element) object for morphology operations. ## ## The structuring element can have any type of shape as specified by ## @var{shape}, each one with its @var{parameters}. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("arbitrary", @var{nhood}) ## @deftypefnx {Function File} {} strel ("arbitrary", @var{nhood}, @var{height}) ## Create arbitrary shaped structuring elements. ## ## @var{nhood} must be a matrix of 0's and 1's. Any number with of dimensions ## are possible. To create a non-flat SE, the @var{height} can be specified. ## See individual functions that use the strel object for an interpretation of ## non-flat SEs. ## ## Note that if an arbitrary shape is used, it may not be possible to guess ## it which may prevent shape-based optimizations (structuring element ## decomposition, see @@strel/getsequence for details). ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("ball", @var{radius}, @var{height}) ## Create ball shaped @var{nonflat} structuring element. @var{radius} must be a ## nonnegative integer that specifies the ray of a circle in X-Y plane. @var{height} ## is a real number that specifies the height of the center of the circle. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("cube", @var{edge}) ## Create cube shaped @var{flat} structuring element. @var{edge} must be a ## positive integer that specifies the length of its edges. This shape meant to ## perform morphology operations in volumes, see the square shape for 2 ## dimensional images. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("diamond", @var{radius}) ## Create diamond shaped flat structuring element. @var{radius} must be a ## positive integer. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("disk", @var{radius}) ## @deftypefnx {Function File} {} strel ("disk", @var{radius}, @var{n}) ## Create disk shaped flat structuring element. @var{radius} must be a positive ## integer. ## ## The optional @var{n} argument *must* have a value of zero but the default ## value is 4. This is to prevent future backwards incompatibilty since ## @sc{Matlab} default is also 4 but at the moment only 0 has been ## implemented. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("hypercube", @var{n}, @var{edge}) ## Create @var{n} dimensional cube (n-cube) shaped @var{flat} structuring ## element. @var{edge} must be a positive integer that specifies the length ## of its edges. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("hyperrectangle", @var{dimensions}) ## Create @var{n} dimensional hyperrectangle (or orthotope) shaped flat ## structuring element. @var{dimensions} must be a vector of positive ## integers with its lengtht at each of the dimensions. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("line", @var{len}, @var{deg}) ## Create line shaped flat structuring element. @var{len} must be a positive ## real number. @var{deg} must be a 1 or 2 elements real number, for a line in ## in 2D or 3D space. The first element of @var{deg} is the angle from X-axis ## to X-Y projection of the line while the second is the angle from Z-axis to ## the line. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("octagon", @var{apothem}) ## Create octagon shaped flat structuring element. @var{apothem} must be a ## non-negative integer, multiple of 3, that specifies the distance from the ## origin to the sides of the octagon. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("pair", @var{offset}) ## Create flat structuring element with two members. One member is placed ## at the origin while the other is placed with @var{offset} in relation to the ## origin. @var{offset} must then be a 2 element vector for the coordinates. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("periodicline", @var{p}, @var{v}) ## Create periodic line shaped flat structuring element. A periodic line will ## be built with 2*@var{p}+1 points around the origin included. These points will ## be displaced in accordance with the offset @var{v} at distances: 1*@var{v}, ## -1*@var{v}, 2*@var{v}, -2*@var{v}, ..., @var{p}*@var{v}, -@var{p}*@var{v}. ## Therefore @var{v} must be a 2 element vector for the coordinates. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("rectangle", @var{dimensions}) ## Create rectangular shaped flat structuring element. @var{dimensions} must ## be a two element vector of positive integers with the number of rows and ## columns of the rectangle. ## ## @end deftypefn ## @deftypefn {Function File} {} strel ("square", @var{edge}) ## Create square shaped flat structuring element. @var{edge} must be a positive ## integer that specifies the length of its edges. For use in volumes, see the ## cube shape. ## ## The actual structuring element neighborhood, the logical matrix used for the ## operations, can be accessed with the @code{getnhood} method. However, most ## morphology functions in the image package will have an improved performance ## if the actual strel object is used, and not its element neighborhood. ## ## @example ## @group ## se = strel ("square", 5); ## getnhood (se) ## @result{} ## 1 1 1 1 1 ## 1 1 1 1 1 ## 1 1 1 1 1 ## 1 1 1 1 1 ## 1 1 1 1 1 ## @end group ## @end example ## ## @seealso{imdilate, imerode} ## @end deftypefn function SE = strel (shape, varargin) if (nargin < 1 || nargin > 4 || (ischar (shape) && nargin < 2)) print_usage (); elseif (! ischar (shape)) varargin = horzcat ({shape}, varargin); shape = "arbitrary"; endif nvar = numel (varargin); ## because the order that these are created matters, we make them all here SE = struct; SE.shape = tolower (shape); SE.nhood = false; SE.flat = true; SE.height = []; SE.seq = cell; SE.opt = struct; switch (SE.shape) case "arbitrary" if (numel (varargin) == 1) nhood = varargin{1}; SE.flat = true; elseif (numel (varargin) == 2) nhood = varargin{1}; SE.height = varargin{2}; SE.flat = false; else error ("strel: an arbitrary shape takes 1 or 2 arguments"); endif ## don't use isbw because we also want to allow empty nhood if (any ((nhood(:) != 1) & (nhood(:) != 0))) error ("strel: NHOOD must be a matrix with only 0 and 1 values") endif SE.nhood = logical (nhood); # we need this as logical for the height tests if (! SE.flat && ! (isnumeric (SE.height) && isreal (SE.height) && ndims (SE.height) == ndims (nhood) && all (size (SE.height) == size (nhood)) && all (isfinite (SE.height(:))))) error ("strel: HEIGHT must be a finite real matrix of the same size as NHOOD"); endif if (nnz (SE.height) == 0) SE.flat = true; endif case "ball" if (numel (varargin) == 2) radius = varargin{1}; height = varargin{2}; else ## TODO implement third option for number of periodic lines approximation error ("strel: a ball shape needs 2 arguments"); endif if (! is_positive_integer (radius)) error ("strel: RADIUS must be a positive integer"); elseif (! (isscalar (height) && isnumeric (height))) error ("strel: HEIGHT must be a real number"); endif # Ellipsoid: (x/radius)^2 + (y/radius)^2 + (z/height)^2 = 1 # We need only the 1 cells of SE.nhood [x, y] = meshgrid (-radius:radius, -radius:radius); SE.nhood = ((x.^2 + y.^2) <= radius^2); # X-Y circle SE.height = height / radius * SE.nhood .* sqrt (radius^2 - x .^2 - y.^2); SE.flat = false; case "cube" if (numel (varargin) == 1) SE.opt.edge = varargin{1}; else error ("strel: no EDGE specified for cube shape"); endif if (! is_positive_integer (SE.opt.edge)) error ("strel: EDGE value must be a positive integer"); endif SE.nhood = true (SE.opt.edge, SE.opt.edge, SE.opt.edge); SE.flat = true; case "diamond" if (numel (varargin) == 1) radius = varargin{1}; else error ("strel: no RADIUS specified for diamond shape"); endif if (! is_positive_integer (radius)) error ("strel: RADIUS must be a positive integer"); endif corner = tril (true (radius+1, radius), -1); SE.nhood = [rot90(tril(true(radius+1))) corner; corner' rot90(triu(true(radius),1))]; SE.flat = true; case "disk" if (nvar < 1 || nvar > 2) error ("strel: disk shape takes 1 or 2 arguments"); endif radius = varargin{1}; if (! is_positive_integer (radius)) error ("strel: RADIUS must be a positive integer"); endif n = 4; if (nvar > 1) n = varargin{2}; if (! isnumeric (n) && ! isscalar (n) && any (n != [0 4 6 8])) error ("strel: N for disk shape must be 0, 4, 6, or 8"); endif endif ## TODO implement approximation by periodic lines if (n != 0) error ("strel: N for disk shape not yet implemented, use N of 0"); endif [x, y] = meshgrid (-radius:radius, -radius:radius); r = sqrt (x.^2 + y.^2); SE.nhood = r <= radius; SE.flat = true; case "hypercube" if (numel (varargin) == 2) SE.opt.n = varargin{1}; SE.opt.edge = varargin{2}; else error ("strel: an hypercube shape needs 2 arguments"); endif if (! is_positive_integer (SE.opt.n)) error ("strel: N value must be a positive integer"); elseif (! is_positive_integer (SE.opt.edge)) error ("strel: EDGE value must be a positive integer"); endif SE.nhood = true (repmat (SE.opt.edge, 1, SE.opt.n)); SE.flat = true; case "hyperrectangle" if (numel (varargin) == 1) SE.opt.dimensions = varargin{1}; else error ("strel: no DIMENSIONS specified for rectangle shape"); endif if (! isnumeric (SE.opt.dimensions)) error ("strel: DIMENSIONS must be a 2 element vector"); elseif (! all (arrayfun (@is_positive_integer, SE.opt.dimensions(:)))) error ("strel: DIMENSIONS values must be positive integers"); endif SE.nhood = true (SE.opt.dimensions(:)); SE.flat = true; case "line" if (numel (varargin) == 2) linelen = varargin{1}; degrees = varargin{2}; else error ("strel: a line shape needs 2 arguments"); endif if (! (isscalar (linelen) && isnumeric (linelen) && linelen > 0)) error ("strel: LEN must be a positive real number"); elseif (! isnumeric (degrees)) error ("strel: DEG must be numeric"); endif ## 2d or 3d line dimens = numel (degrees) +1; if (dimens == 2) degrees = degrees(1); elseif (dimens == 3) alpha = degrees(1); phi = degrees(2); else error ("strel: DEG must be a 1 or 2 elements matrix"); endif ## TODO this was the 3dline and line options, which have separate code ## but a proper merge should be made. if (dimens == 2) ## Line length are always odd, to center strel at the middle of the line. ## We look it as a diameter of a circle with given slope # It computes only lines with angles between 0 and 44.9999 deg90 = mod (degrees, 90); if (deg90 > 45) alpha = pi * (90 - deg90) / 180; else alpha = pi * deg90 / 180; endif ray = (linelen - 1)/2; ## We are interested only in the discrete rectangle which contains the diameter ## However we focus our attention to the bottom left quarter of the circle, ## because of the central symmetry. c = round (ray * cos (alpha)) + 1; r = round (ray * sin (alpha)) + 1; ## Line rasterization line = false (r, c); m = tan (alpha); x = [1:c]; y = r - fix (m .* (x - 0.5)); indexes = sub2ind ([r c], y, x); line(indexes) = true; ## We view the result as 9 blocks. # Preparing blocks linestrip = line(1, 1:c - 1); linerest = line(2:r, 1:c - 1); z = false (r - 1, c); # Assemblying blocks SE.nhood = vertcat ( horzcat (z, linerest(end:-1:1,end:-1:1)), horzcat (linestrip, true, linestrip(end:-1:1,end:-1:1)), horzcat (linerest, z(end:-1:1,end:-1:1)) ); # Rotate/transpose/flip? sect = fix (mod (degrees, 180) / 45); switch (sect) case 1, SE.nhood = transpose (SE.nhood); case 2, SE.nhood = rot90 (SE.nhood, 1); case 3, SE.nhood = fliplr (SE.nhood); otherwise, # do nothing endswitch elseif (dimens == 3) ## This is a first implementation ## Stroke line from cells (x1, y1, z1) to (x2, y2, z2) alpha *= pi / 180; phi *= pi / 180; x1 = y1 = z1 = 0; x2 = round (linelen * sin (phi) * cos (alpha)); y2 = round (linelen * sin (phi) * sin (alpha)); z2 = round (linelen * cos (phi)); # Adjust x2, y2, z2 to have one central cell x2 += (! mod (x2, 2)) * sign0positive (x2); y2 += (! mod (y2, 2)) * sign0positive (y2); z2 += (! mod (z2, 2)) * sign0positive (z2); # Invert x x2 = -x2; # Tanslate parallelepiped to be in positive quadrant if (x2 < 0) x1 -= x2; x2 -= x2; endif if (y2 < 0) y1 -= y2; y2 -= y2; endif if (z2 < 0) z1 -= z2; z2 -= z2; endif # Compute index2es dim = abs ([(x2 - x1) (y2 - y1) (z2 - z1)]); m = max (dim); base = meshgrid (0:m - 1,1) .+ 0.5; a = floor ((x2 - x1)/m .* base); b = floor ((y2 - y1)/m .* base); c = floor ((z2 - z1)/m .* base); # Adjust indexes to be valid a -= min (a) - 1; b -= min (b) - 1; c -= min (c) - 1; indexes = sub2ind (dim, a, b, c); SE.nhood = false (dim); SE.nhood(indexes) = true; endif SE.flat = true; case "octagon" if (numel (varargin) == 1) SE.opt.apothem = apothem = varargin{1}; else error ("strel: no APOTHEM specified for octagon shape"); endif if (! is_nonnegative_integer (apothem) || mod (apothem, 3) != 0) error ("strel: APOTHEM must be a positive integer multiple of 3"); endif ## we look at it as 9 blocks. North AND South are the same and West TO ## East as well. We make the corner for NorthEast and rotate it for the ## other corners if (apothem == 0) SE.nhood = true (1); else cwide = apothem/3*2 + 1; iwide = apothem/3*2 - 1; N_and_S = true ([cwide iwide]); corner = tril (true (cwide)); SE.nhood = [rotdim(corner), N_and_S, corner; true([iwide (2*apothem + 1)]); transpose(corner), N_and_S, rotdim(corner, -1)]; endif SE.flat = true; case "pair" if (numel (varargin) == 1) offset = varargin{1}; else error ("strel: no OFFSET specified for pair shape"); endif if (! isnumeric (offset) || numel (offset) != 2) error ("strel: OFFSET must be a 2 element vector"); elseif (any (fix (offset) != offset)) error ("strel: OFFSET values must be integers"); endif lengths = abs (2*offset) + 1; SE.nhood = false (lengths); origin = (lengths + 1)/2; SE.nhood(origin(1), origin(2)) = true; SE.nhood(origin(1) + offset(1), origin(2) + offset(2)) = true; SE.flat = true; case "periodicline" if (numel (varargin) == 2) p = varargin{1}; v = varargin{2}; else error ("strel: a periodic line shape needs 2 arguments"); endif if (! is_positive_integer (p)) error ("strel: P must be a positive integer"); elseif (! isnumeric (v) || numel (v) != 2) error ("strel: V must be a 2 element vector"); elseif (any (fix (v) != v)) error ("strel: values of V must be integers"); endif lengths = abs (2*p*v) + 1; SE.nhood = false (lengths); origin = (lengths + 1)/2; for i = -p:p point = i*v + origin; SE.nhood(point(1), point(2)) = true; endfor case "rectangle" if (numel (varargin) == 1) SE.opt.dimensions = varargin{1}; else error ("strel: no DIMENSIONS specified for rectangle shape"); endif if (! isnumeric (SE.opt.dimensions) || numel (SE.opt.dimensions) != 2) error ("strel: DIMENSIONS must be a 2 element vector"); elseif (! is_positive_integer (SE.opt.dimensions(1)) || ! is_positive_integer (SE.opt.dimensions(2))) error ("strel: DIMENSIONS values must be positive integers"); endif SE.nhood = true (SE.opt.dimensions); SE.flat = true; case "square" if (numel (varargin) == 1) SE.opt.edge = varargin{1}; else error ("strel: no EDGE specified for square shape"); endif if (! is_positive_integer (SE.opt.edge)) error ("strel: EDGE value must be positive integers"); endif SE.nhood = true (SE.opt.edge); SE.flat = true; otherwise error ("strel: unknown SHAPE `%s'", shape); endswitch SE = class (SE, "strel"); endfunction function retval = is_positive_integer (val) retval = isscalar (val) && isnumeric (val) && val > 0 && fix (val) == val; endfunction function retval = is_nonnegative_integer (val) retval = isscalar (val) && isnumeric (val) && val >= 0 && fix (val) == val; endfunction function retval = sign0positive (val) if (sign (val) == -1) retval = -1; else retval = 1; endif endfunction %!test %! shape = logical ([0 0 0 1]); %! assert (getnhood (strel (shape)), shape); %! assert (getnhood (strel ("arbitrary", shape)), shape); %! %! height = [0 0 0 3]; %! assert (getnhood (strel ("arbitrary", shape, height)), shape); %! assert (getheight (strel ("arbitrary", shape, height)), height); %!test %! shape = logical ([0 0 1]); %! height = [-2 1 3]; ## this works for matlab compatibility %! assert (getnhood (strel ("arbitrary", shape, height)), shape); %! assert (getheight (strel ("arbitrary", shape, height)), height); %!test %! shape = logical ([0 0 0 1 0 0 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 1 0 0 0]); %! height = [ 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 %! 0.00000 0.33333 0.66667 0.74536 0.66667 0.33333 0.00000 %! 0.00000 0.66667 0.88192 0.94281 0.88192 0.66667 0.00000 %! 0.00000 0.74536 0.94281 1.00000 0.94281 0.74536 0.00000 %! 0.00000 0.66667 0.88192 0.94281 0.88192 0.66667 0.00000 %! 0.00000 0.33333 0.66667 0.74536 0.66667 0.33333 0.00000 %! 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000]; %! assert (getnhood (strel ("ball", 3, 1)), shape); %! assert (getheight (strel ("ball", 3, 1)), height, 0.0001); %!test %! shape = logical ([0 0 0 1 0 0 0 %! 0 0 1 1 1 0 0 %! 0 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 %! 0 1 1 1 1 1 0 %! 0 0 1 1 1 0 0 %! 0 0 0 1 0 0 0]); %! assert (getnhood (strel ("diamond", 3)), shape); %!test %! shape = logical ([0 0 0 1 0 0 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 1 0 0 0]); %! assert (getnhood (strel ("disk", 3, 0)), shape); %!test %! shape = logical ([1 1 1]); %! assert (getnhood (strel ("line", 3.9, 20.17)), shape); %! shape = logical ([0 0 1 %! 0 1 0 %! 1 0 0]); %! assert (getnhood (strel ("line", 3.9, 20.18)), shape); %! shape = logical ([1 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 %! 0 0 1 0 0 0 0 0 0 %! 0 0 1 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 %! 0 0 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 0 1]); %! assert (getnhood (strel ("line", 14, 130)), shape); %!test %! se = strel ("octagon", 0); %! seq = getsequence (se); %! assert (getnhood (se), true (1)); %! assert (getnhood (seq(1)), true (1)); %! %! se = strel ("octagon", 3); %! seq = getsequence (se); %! shape = logical ([0 0 1 1 1 0 0 %! 0 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 1 %! 0 1 1 1 1 1 0 %! 0 0 1 1 1 0 0]); %! assert (getnhood (se), shape); %! assert (size (seq), [4 1]); %! %! templ1 = logical ([0 0 0; 1 1 1; 0 0 0]); %! templ2 = logical ([0 1 0; 0 1 0; 0 1 0]); %! templ3 = logical ([1 0 0; 0 1 0; 0 0 1]); %! templ4 = logical ([0 0 1; 0 1 0; 1 0 0]); %! assert ({getnhood(seq(1)) getnhood(seq(2)) getnhood(seq(3)) getnhood(seq(4))}, %! {templ1 templ2 templ3 templ4}); %! %! seq = getsequence (strel ("octagon", 21)); %! assert (size (seq), [28 1]); %! assert (arrayfun (@(x) getnhood (seq(x)), 1:4:25, "UniformOutput", false), %! repmat ({templ1}, 1, 7)); %! assert (arrayfun (@(x) getnhood (seq(x)), 2:4:26, "UniformOutput", false), %! repmat ({templ2}, 1, 7)); %! assert (arrayfun (@(x) getnhood (seq(x)), 3:4:27, "UniformOutput", false), %! repmat ({templ3}, 1, 7)); %! assert (arrayfun (@(x) getnhood (seq(x)), 4:4:28, "UniformOutput", false), %! repmat ({templ4}, 1, 7)); %!test %! shape = logical ([1 1 0]'); %! assert (getnhood (strel ("pair", [-1 0])), shape); %! shape = logical ([1 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 0]); %! assert (getnhood (strel ("pair", [-1 -3])), shape); %! shape = logical ([0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 1]); %! assert (getnhood (strel ("pair", [2 3])), shape); %!test %! assert (getnhood (strel ("rectangle", [10 5])), true (10, 5)); %! assert (getnhood (strel ("square", 5)), true (5)); ## test how @strel/getsequence and indexing works fine %!shared se, seq %! se = strel ("square", 5); %! seq = getsequence (se); %! assert (class (se(1)), "strel") %! assert (class (se(1,1)),"strel") %! assert (class (seq), "strel") %! assert (class (seq(1)), "strel") %! assert (class (seq(2)), "strel") %! assert (numel (se), 1) %! assert (numel (seq), 2) %! assert (getnhood (seq(1)), true (5, 1)) %! assert (getnhood (seq(2)), true (1, 5)) %! assert (size (se), [1 1]) %! assert (size (seq), [2 1]) %! assert (isscalar (se), true) %! assert (isscalar (seq), false) %!error se(2); %!error seq(3); ## test reflection %!test %! se = strel ("arbitrary", [1 0 0; 1 1 0; 0 1 0], [2 0 0; 3 1 0; 0 3 0]); %! ref = reflect (se); %! assert (getnhood (ref), logical([0 1 0; 0 1 1; 0 0 1])); %! assert (getheight (ref), [0 3 0; 0 1 3; 0 0 2]); ## test input validation %!error strel() %!error strel("nonmethodthing", 2) %!error strel("arbitrary", "stuff") %!error strel("arbitrary", [0 0 1], [2 0 1; 4 5 1]) %!error strel("arbitrary", [0 0 1], "stuff") %!error strel("ball", -3, 1) %!error strel("diamond", -3) %!error strel("disk", -3) %!error strel("line", 0, 45) %!error strel("octagon", 3.5) %!error strel("octagon", 4) %!error strel("octagon", -1) %!error strel("pair", [45 67 90]) %!error strel("rectangle", 2) %!error strel("rectangle", [2 -5]) %!error strel("square", [34 1-2]) image-2.4.1/inst/@strel/PaxHeaders.6632/translate.m0000644000000000000000000000013212561122761016641 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/translate.m0000644000175000017500000000223112561122761021462 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## ## 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 3 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{SE2} =} translate (@var{SE}, @var{V}) ## Generate a new structuring element, which is SE translated in rows and ## columns as expressed in the offset 2-dimensional array V. ## ## @seealso{reflect, strel} ## @end deftypefn ## TODO: If SE is an array of structuring element objects, then it reflects ## each element of SE. function SE2 = translate (SE) error ("translate: not yet implemented"); endfunctionimage-2.4.1/inst/@strel/PaxHeaders.6632/display.m0000644000000000000000000000013212561122761016311 xustar0030 mtime=1438950897.706252238 30 atime=1438950897.706252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/display.m0000644000175000017500000000275412561122761021144 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## ## 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 3 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} {} display (@var{SE}) ## Display the contents of object SE. ## ## @seealso{strel} ## @end deftypefn function display (SE) P = nnz (SE.nhood); if (SE.flat) flatstr = "Flat"; else flatstr = "Nonflat"; endif if (P != 1) plural_p = "s"; else plural_p = ""; endif ## FIXME using inputname won't work when SE is a field in a struct or in a ## cell array. Not only won't get the correct name sometimes, it may ## also mess up the display of nested structures. printf ("%s = \n", inputname (1)); printf (" %s STREL object with %d neighbor%s\n\n", flatstr, P, plural_p); printf (" Neighborhood:\n"); display (SE.nhood); if (!SE.flat) printf (" Height:\n"); display (SE.height); endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/getneighbors.m0000644000000000000000000000013212561122761017324 xustar0030 mtime=1438950897.706252238 30 atime=1438950897.706252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/getneighbors.m0000644000175000017500000000375612561122761022162 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{offsets}, @var{heights}] =} getneighbors (@var{se}) ## Get neighbors relative position and height. ## ## For each of the neighbors in the strel object @var{se}, @var{offsets} are ## their positions relative to the origin (center). It is a @var{P}x@var{N} ## matrix, with @var{P} as the number of neighbors, and @var{N} as the number ## of dimensions. ## ## @var{heights} is a vector with the height of each neighbor in @var{se}. ## ## @seealso{getnhood, getheight, strel} ## @end deftypefn function [offsets, heights] = getneighbors (se) se_ndims = ndims (se.nhood); se_size = size (se.nhood); ## To calculate the offsets we get the subscript indexes of all elements ## in a cell array, one cell for each dimension and the that dimension ## indexes in a column. We then just subtract the center position of each ## dimension to the respective column. sub = cell (1, se_ndims); ## The (:) on find(...)(:) is because find() will return a row (instead ## of a column), if the input is just a row vector. We need to make sure ## that we always get a column for ind2sub(). [sub{1:se_ndims}] = ind2sub (se_size, find (se.nhood)(:)); offsets = cell2mat (sub) - floor ((se_size + 1) / 2); heights = getheight (se)(se.nhood); endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/getnhood.m0000644000000000000000000000013212561122761016453 xustar0030 mtime=1438950897.706252238 30 atime=1438950897.706252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/getnhood.m0000644000175000017500000000170312561122761021277 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## ## 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 3 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{NHOOD} =} getnhood (@var{SE}) ## Return the neighborhood of structuring element SE. ## ## @seealso{getneighbors, strel} ## @end deftypefn function NHOOD = getnhood (SE) NHOOD = SE.nhood; endfunctionimage-2.4.1/inst/@strel/PaxHeaders.6632/reflect.m0000644000000000000000000000013212561122761016270 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/reflect.m0000644000175000017500000000501012561122761021107 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Roberto Metere ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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{se2} =} reflect (@var{se}) ## Reflect structuring element of strel object. ## ## Returns another strel object with all its elements reflected. If @var{se} is ## a sequence of strel objects, reflects each one of them. If @var{se} is a ## non-flat structuring element, its height is reflected accordingly. ## ## Reflection is a rotation of 180 degrees around the center, including for ## N-dimensional matrices. ## ## @seealso{strel, @@strel/getheight, @@strel/getsequence, @@strel/translate} ## @end deftypefn function se = reflect (se) ## FIXME this should be done in a smarter way for non-arbitrary shapes (but ## then we may need to also change some of the options values...) if (isempty (se.seq)) se = rotate_strel (se); else for idx = 1:numel (se.seq) se.seq{idx} = rotate_strel (se.seq{idx}); endfor endif endfunction function se = rotate_strel (se) nhood = getnhood (se); height = getheight (se); if (se.flat) se = strel ("arbitrary", rotate (nhood)); else se = strel ("arbitrary", rotate (nhood), rotate (height)); endif endfunction function rot = rotate (ori) rot = reshape (ori(end:-1:1), size (ori)); ## For Matlab compatibility: ## Check if any of the sides has an even size. If so, we create a larger ## matrix, all even sized, and place the rotated matrix on the top left ## corner (and whatever top and left means for N dimensions) if (any (mod (size (ori)+1, 2))) ## get subcript indices of the elements that matter ori_ind = find (ori); [subs{1:ndims (ori)}] = ind2sub (size (ori), ori_ind); rot = zeros ((floor (size (ori) /2) *2) +1, class (ori)); rot_ind = sub2ind (size (rot), subs{:}); rot(rot_ind) = ori(ori_ind); endif endfunction image-2.4.1/inst/@strel/PaxHeaders.6632/numel.m0000644000000000000000000000013212561122761015764 xustar0030 mtime=1438950897.710252238 30 atime=1438950897.710252238 30 ctime=1438950899.342252237 image-2.4.1/inst/@strel/numel.m0000644000175000017500000000202612561122761020607 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## ## 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 3 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} {} numel (@var{se}) ## Return number of structuring elements in a strel object. ## @seealso{strel, @@strel/getsequence} ## @end deftypefn function number = numel (se, varargin) if (isempty (se.seq)) number = 1; else number = numel (se.seq, varargin{:}); endif endfunction image-2.4.1/inst/PaxHeaders.6632/im2bw.m0000644000000000000000000000013212561122761014433 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2bw.m0000644000175000017500000000735112561122761017264 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2012, 2013 Carnë Draug ## ## 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 3 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} {} im2bw (@var{img}, threshold) ## @deftypefnx {Function File} {} im2bw (@var{X}, @var{cmap}, threshold) ## Convert image to binary, black and white, by threshold. ## ## The input image @var{img} can either be a grayscale or RGB image. In the later ## case, @var{img} is first converted to grayscale with @code{rgb2gray}. Input ## can also be an indexed image @var{X} in which case the colormap @var{cmap} ## needs to be specified. ## ## The value of @var{threshold} should be in the range [0,1] independently of the ## class of @var{img}. Values from other classes can be converted to the correct ## value with @code{im2double} for example. For an automatic threshold, consider ## using @code{graythresh}. ## ## @example ## @group ## bw = im2bw (img, graythresh (img)); ## @end group ## @end example ## ## @seealso{graythresh, ind2gray, rgb2gray} ## @end deftypefn function BW = im2bw (img, cmap, thres = 0.5) if (nargin < 1 || nargin > 3) print_usage (); elseif (nargin == 3 && ! isind (img)) error ("im2bw: IMG must be an indexed image when are 3 input arguments"); elseif (nargin == 3 && ! iscolormap (cmap)) error ("im2bw: CMAP must be a colormap"); elseif (nargin == 2) thres = cmap; endif if (! isimage (img)) error ("im2bw: IMG must be an image"); elseif (! isnumeric (thres) || ! isscalar (thres) || ! isreal (thres) || thres < 0 || thres > 1) error ("im2bw: THRESHOLD must be a scalar in the interval [0, 1]"); endif if (islogical (img)) warning ("im2bw: IMG is already binary so nothing is done"); tmp = img; else ## Convert img to gray scale if (nargin == 3) ## indexed image (we already checked that is indeed indexed earlier) img = ind2gray (img, cmap); elseif (isrgb (img)) img = rgb2gray (img); else ## Everything else, we do nothing, no matter how many dimensions endif ## Convert the threshold value to same image class to do the thresholding which ## is faster than converting the image to double and keep the threshold value switch (class (img)) case {"double", "single", "logical"} ## do nothing case {"uint8"} thres = im2uint8 (thres); case {"uint16"} thres = im2uint16 (thres); case {"int16"} thres = im2int16 (thres); otherwise ## we should have never got here in the first place anyway error("im2bw: unsupported image class"); endswitch tmp = (img > thres); # matlab compatible (not "greater than or equal") endif if (nargout > 0) BW = tmp; else imshow (tmp); endif endfunction %!assert(im2bw ([0 0.4 0.5 0.6 1], 0.5), logical([0 0 0 1 1])); # basic usage %!assert(im2bw (uint8 ([0 100 255]), 0.5), logical([0 0 1])); # with a uint8 input ## This will issue a warning %!assert (im2bw (logical ([0 1 0])), logical ([0 1 0])) %!assert (im2bw (logical ([0 1 0]), 0), logical ([0 1 0])) %!assert (im2bw (logical ([0 1 0]), 1), logical ([0 1 0])) image-2.4.1/inst/PaxHeaders.6632/tformfwd.m0000644000000000000000000000013212561122761015243 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/tformfwd.m0000644000175000017500000000414512561122761020072 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{UV}] =} tformfwd (@var{T}, @var{XY}) ## @deftypefnx {Function File} {[@var{U}, @var{V}] =} tformfwd (@var{T}, @var{X}, @var{Y}) ## ## Given two dimensional coordinates from one space, returns two ## dimensional coordinates in the other space, as defined in ## the transform structure @var{T}. Input and output coordinates ## may be given either as a n-by-2 arrays, or as two n-by-1 vectors. ## @seealso{maketform, cp2tform, tforminv} ## @end deftypefn ## Author: Pantxo Diribarne function varargout = tformfwd (T, varargin) if (nargin > 3 || nargin < 2) print_usage (); elseif (! istform (T)) error ("tformfwd: expect a transform structure as first argument") elseif (nargin == 2) XX = varargin{1}; if (columns (XX) != 2) error ("tformfwd: expect n-by-2 array as second argument") endif else if (!isvector (varargin{1}) || !isvector (varargin{2})) error ("tformfwd: expect vectors as coordinates") elseif (!all (size (varargin{1}) == size (varargin{2}))) error ("tformfwd: expect two vectors the same size") elseif (columns (varargin{1}) != 1) error ("tformfwd: expect column vectors") endif XX = [varargin{1} varargin{2}]; endif UU = T.forward_fcn(XX, T); if (nargin == 3) varargout{1} = UU(:,1); varargout{2} = UU(:,2); else varargout{1} = UU; endif endfunction image-2.4.1/inst/PaxHeaders.6632/mat2gray.m0000644000000000000000000000013212561122761015141 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/mat2gray.m0000644000175000017500000001064712561122761017774 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999, 2000 Kai Habel ## Copyright (C) 2011, 2012 Carnë Draug ## ## 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 3 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{I} =} mat2gray (@var{M}) ## @deftypefnx {Function File} {@var{I} =} mat2gray (@var{M}, [@var{min} @var{max}]) ## Convert a matrix to an intensity image. ## ## The returned matrix @var{I} is a grayscale image, of double class and in the ## range of values [0, 1]. The optional arguments @var{min} and @var{max} will ## set the limits of the conversion; values in @var{M} below @var{min} and ## above @var{max} will be set to 0 and 1 on @var{I} respectively. ## ## @var{max} and @var{min} default to the maximum and minimum values of @var{M}. ## ## If @var{min} is larger than @var{max}, the `inverse' will be returned. Values ## in @var{M} above @var{max} will be set to 0 while the ones below @var{min} ## will be set to 1. ## ## @strong{Caution:} For compatibility with @sc{matlab}, if @var{min} and @var{max} ## are equal (either from being actually being set manually or automatically ## calculated from the @var{M} min and max values, Octave's mat2gray will truncate ## all values between [0 1]. For example ## ## @example ## @group ## mat2gray ([-2 0 0.5 0.9 5], [2 2]) ## @result{} [0 0 0.5 0.9 1] ## mat2gray ([0.5 0.5 0.5]) ## @result{} [0.5 0.5 0.5] ## mat2gray ([4 4 4]) ## @result{} [1 1 1] ## @end group ## @end example ## ## @seealso{gray2ind, ind2gray, rgb2gray, im2double, im2uin16, im2uint8, im2int16} ## @end deftypefn function in = mat2gray (in, scale) if (nargin < 1 || nargin > 2) print_usage; elseif (! isnumeric (in) && ! islogical (in)) error ("mat2gray: IN must be a matrix"); elseif (nargin == 2 && (!isvector (scale) || numel (scale) != 2)) error ("mat2gray: second argument must be a vector with 2 elements"); endif if (nargin == 1) out_min = min (in(:)); out_max = max (in(:)); else ## see more at the end for the cases where max and min are swapped out_min = min (scale (1), scale (2)); out_max = max (scale (1), scale (2)); endif ## since max() and min() return a value of same class as input, ## need to make this values double or the calculations later may fail out_min = double (out_min); out_max = double (out_max); ## if max and min are the same, matlab seems to simple truncate the input ## between 0 and 1, and ignores the min/max values set. Don't get the logic ## but hey! Matlab compatibility if (out_min == out_max) in(in>1) = 1; in(in<0) = 0; return endif ## we are editing the input matrix rather than creating a new one to save ## memory. We need to make sure it's double though in = double(in); ## it's faster to get the index of values between max and min only once ## than to have it calculated on both sides of the assignment later on. We ## need to get the index before starting editing idx = (in > out_min & in < out_max); in(in <= out_min) = 0; in(in >= out_max) = 1; in(idx) = (1/(out_max - out_min)) * (double(in(idx)) - out_min); ## if the given min and max are in the inverse order... if (nargin > 1 && scale(1) > scale (2)) ## matlab seems to allow setting the min higher than the max but not by ## checking which one is actually correct. Seems to just invert it in = abs (in - 1); endif endfunction %!assert(mat2gray([1 2 3]), [0 0.5 1]); # standard use %!assert(mat2gray(repmat ([1 2; 3 3], [1 1 3])), repmat ([0 0.5; 1 1], [1 1 3])); # setting min and max %!assert(mat2gray([1 2 3], [2 2]), [1 1 1]); # equal min and max %!assert(mat2gray([-1 0 0.5 3], [2 2]), [0 0 0.5 1]); # equal min and max %!assert(mat2gray(ones(3*0.5)), ones(3*0.5)); # equal min and max from the image (not set) %!assert(mat2gray([1 2 3], [3 1]), [1 0.5 0]); # max and min inverted image-2.4.1/inst/PaxHeaders.6632/poly2mask.m0000644000000000000000000000013212561122761015334 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/poly2mask.m0000644000175000017500000001553612561122761020171 0ustar00carandraugcarandraug00000000000000## 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 3 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{BW} = } poly2mask (@var{x},@var{y},@var{m},@var{n}) ## Convert a polygon to a region mask. ## ## BW=poly2mask(x,y,m,n) converts a polygon, specified by a list of ## vertices in @var{x} and @var{y} and returns in a @var{m}-by-@var{n} ## logical mask @var{BW} the filled polygon. Region inside the polygon ## is set to 1, values outside the shape are set to 0. ## ## @var{x} and @var{y} should always represent a closed polygon, first ## and last points should be coincident. If they are not poly2mask will ## close it for you. If @var{x} or @var{y} are fractional they are ## nearest integer. ## ## If all the polygon or part of it falls outside the masking area ## (1:m,1:n), it is discarded or clipped. ## ## This function uses scan-line polygon filling algorithm as described ## in http://www.cs.rit.edu/~icss571/filling/ with some minor ## modifications: capability of clipping and scan order, which can ## affect the results of the algorithm (algorithm is described not to ## reach ymax, xmax border when filling to avoid enlarging shapes). In ## this function we scan the image backwards (we begin at ymax and end ## at ymin), and we don't reach ymin, xmin, which we believe should be ## compatible with MATLAB. ## @end deftypefn ## TODO: check how to create a logical BW without any conversion function BW = poly2mask (x, y, m, n) if (nargin != 4) print_usage (); endif ## check x and y x = round (x (:).'); y = round (y (:).'); if (length (x) < 3) error ("poly2mask: polygon must have at least 3 vertices."); endif if (length (x) != length (y)) error ("poly2mask: length of x doesn't match length of y."); endif ## create output matrix BW = false (m, n); ## close polygon if needed if ((x (1) != x (length (x))) || (y (1) != y (length (y)))) x = horzcat (x, x (1)); y = horzcat (y, y (1)); endif ## build global edge table ex = [x(1:length (x) - 1); x(1, 2:length (x))]; ## x values for each edge ey = [y(1:length (y) - 1); y(1, 2:length (y))]; ## y values for each edge idx = (ey (1, :) != ey (2, :)); ## eliminate horizontal edges ex = ex (:, idx); ey = ey (:, idx); eminy = min (ey); ## minimum y for each edge emaxy = max (ey); ## maximum y for each edge t = (ey == [eminy; eminy]); ## values associated to miny exminy = ex (:) (t); ## x values associated to min y exmaxy = ex (:) (!t); ## x values associated to max y emaxy = emaxy.'; ## we want them vertical now... eminy = eminy.'; m_inv = (exmaxy - exminy)./(emaxy - eminy); ## calculate inverse slope ge = [emaxy, eminy, exmaxy, m_inv]; ## build global edge table ge = sortrows (ge, [1, 3]); ## sort on eminy and exminy ## we add an extra dummy edge at the end just to avoid checking ## while indexing it ge = [-Inf, -Inf, -Inf, -Inf; ge]; ## initial parity is even (0) parity = 0; ## init scan line set to bottom line sl = ge (size (ge, 1), 1); ## init active edge table ## we use a loop because the table is sorted and edge list could be ## huge ae = []; gei = size (ge, 1); while (sl == ge (gei, 1)) ae = [ge(gei, 2:4); ae]; gei -= 1; endwhile ## calc minimum y to draw miny = min (y); if (miny < 1) miny = 1; endif while (sl >= miny) ## check vert clipping if (sl <= m) ## draw current scan line ## we have to round because 1/m is fractional ie = round (reshape (ae (:, 2), 2, size (ae, 1)/2)); ## this discards left border of image (this differs from version at ## http://www.cs.rit.edu/~icss571/filling/ which discards right ## border) but keeps an exception when the point is a vertex. ie (1, :) += (ie (1, :) != ie (2, :)); ## we'll clip too, just in case m,n is not big enough ie (1, (ie (1, :) < 1)) = 1; ie (2, (ie (2, :) > n)) = n; ## we eliminate segments outside window ie = ie (:, (ie (1, :) <= n)); ie = ie (:, (ie (2, :) >= 1)); for i = 1:columns (ie) BW (sl, ie (1, i):ie (2, i)) = true; endfor endif ## decrement scan line sl -= 1; ## eliminate edges that eymax==sl ## this discards ymin border of image (this differs from version at ## http://www.cs.rit.edu/~icss571/filling/ which discards ymax). ae = ae ((ae (:, 1) != sl), :); ## update x (x1=x0-1/m) ae (:, 2) -= ae (:, 3); ## update ae with new values while (sl == ge (gei, 1)) ae = vertcat (ae, ge (gei, 2:4)); gei -= 1; endwhile ## order the edges in ae by x value if (rows (ae) > 0) ae = sortrows (ae, 2); endif endwhile endfunction ## This should create a filled octagon %!demo %! s = [0:pi/4:2*pi]; %! x = cos (s) * 90 + 101; %! y = sin (s) * 90 + 101; %! bw = poly2mask(x, y, 200, 200); %! imshow (bw); ## This should create a 5-vertex star %!demo %! s = [0:2*pi/5:pi*4]; %! s = s ([1, 3, 5, 2, 4, 6]); %! x = cos (s) * 90 + 101; %! y = sin (s) * 90 + 101; %! bw = poly2mask (x, y, 200, 200); %! imshow (bw); %!# Convex polygons %!shared xs, ys, Rs, xt, yt, Rt %! xs=[3,3,10,10]; %! ys=[4,12,12,4]; %! Rs=zeros(16,14); %! Rs(5:12,4:10)=1; %! Rs=logical(Rs); %! xt=[1,4,7]; %! yt=[1,4,1]; %! Rt=[0,0,0,0,0,0,0; %! 0,0,1,1,1,1,0; %! 0,0,0,1,1,0,0; %! 0,0,0,1,0,0,0; %! 0,0,0,0,0,0,0]; %! Rt=logical(Rt); %!assert(poly2mask(xs,ys,16,14),Rs); # rectangle %!assert(poly2mask(xs,ys,8,7),Rs(1:8,1:7)); # clipped %!assert(poly2mask(xs-7,ys-8,8,7),Rs(9:16,8:14)); # more clipping %!assert(poly2mask(xt,yt,5,7),Rt); # triangle %!assert(poly2mask(xt,yt,3,3),Rt(1:3,1:3)); # clipped %!# Concave polygons %!test %! x=[3,3,5,5,8,8,10,10]; %! y=[4,12,12,8,8,11,11,4]; %! R=zeros(16,14); %! R(5:12,4:5)=1; %! R(5:8,6:8)=1; %! R(5:11,9:10)=1; %! R=logical(R); %! assert(poly2mask(x,y,16,14), R); %!# Complex polygons %!test %! x=[1,5,1,5]; %! y=[1,1,4,4]; %! R=[0,0,0,0,0,0; %! 0,0,1,1,0,0; %! 0,0,1,1,0,0; %! 0,1,1,1,1,0; %! 0,0,0,0,0,0]; %! R=logical(R); %! assert(poly2mask(x,y,5,6), R); image-2.4.1/inst/PaxHeaders.6632/bwhitmiss.m0000644000000000000000000000013212561122761015424 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwhitmiss.m0000644000175000017500000000505312561122761020252 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{bw2} = bwhitmiss (@var{bw1}, @var{se1}, @var{se1}) ## @deftypefnx{Function File} @var{bw2} = bwhitmiss (@var{bw1}, @var{interval}) ## Perform the binary hit-miss operation. ## ## If two structuring elements @var{se1} and @var{se1} are given, the hit-miss ## operation is defined as ## @example ## bw2 = imerode (bw1, se1) & imerode (! bw1, se2); ## @end example ## If instead an 'interval' array is given, two structuring elements are computed ## as ## @example ## se1 = (interval == 1) ## se2 = (interval == -1) ## @end example ## and then the operation is defined as previously. ## @seealso{bwmorph} ## @end deftypefn function bw = bwhitmiss(im, varargin) ## Checkinput if (nargin != 2 && nargin != 3) print_usage(); endif if (! isreal(im)) error("bwhitmiss: first input argument must be a real matrix"); endif ## Get structuring elements if (nargin == 2) # bwhitmiss (im, interval) interval = varargin{1}; if (!isreal(interval)) error("bwhitmiss: second input argument must be a real matrix"); endif if (!all( (interval(:) == 1) | (interval(:) == 0) | (interval(:) == -1) )) error("bwhitmiss: second input argument can only contain the values -1, 0, and 1"); endif se1 = (interval == 1); se2 = (interval == -1); else # bwhitmiss (im, se1, se2) se1 = varargin{1}; se2 = varargin{2}; if (!all((se1(:) == 1) | (se1(:) == 0)) || !all((se2(:) == 1) | (se2(:) == 0))) error("bwhitmiss: structuring elements can only contain zeros and ones."); endif endif ## Perform filtering bw = imerode (im, se1) & imerode (! im, se2); endfunction %!test %! bw1 = repmat ([0 1 0 1 1], [3 1]); %! bw2 = repmat ([0 1 0 0 0], [3 1]); %! assert (bwhitmiss (bw1, [1; 0; 1], [1 0 1]), logical (bw2)) %! assert (bwhitmiss (bw1, [0 1 0; -1 0 -1; 0 1 0]), logical (bw2)) image-2.4.1/inst/PaxHeaders.6632/isrgb.m0000644000000000000000000000013212561122761014521 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/isrgb.m0000644000175000017500000000451112561122761017345 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2004 Josep Mones i Teixidor ## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} isrgb (@var{img}) ## Return true if @var{img} is a RGB image. ## ## A variable can be considered a RGB image if it is a non-sparse ## matrix of size @nospell{MxNx3xK} and: ## ## @itemize @bullet ## @item is of class double and all values are in the range [0, 1] or NaN; ## @item is of class uint8, or uint16. ## @end itemize ## ## @strong{Note:} despite their suggestive names, the functions isbw, ## isgray, isind, and isrgb, are ambiguous since it is not always possible ## to distinguish between those image types. For example, an uint8 matrix ## can be both a grayscale and indexed image. They are good to dismiss ## input as an invalid image type, but not for identification. ## ## @seealso{rgb2gray, rgb2ind, isbw, isgray, isind} ## @end deftypefn function bool = isrgb (img) if (nargin != 1) print_usage; endif bool = false; if (isimage (img) && ndims (img) < 5 && size (img, 3) == 3) switch (class (img)) case "double" bool = ispart (@is_double_image, img); case {"uint8", "uint16"} bool = true; endswitch endif endfunction %!# Non-matrix %!assert(isrgb("this is not a RGB image"),false); %!# Double matrix tests %!assert(isrgb(rand(5,5)),false); %!assert(isrgb(rand(5,5,1,5)),false); %!assert(isrgb(rand(5,5,3,5)),true); %!assert(isrgb(rand(5,5,3)),true); %!assert(isrgb(ones(5,5,3)),true); %!assert(isrgb(ones(5,5,3)+.0001),false); %!assert(isrgb(zeros(5,5,3)-.0001),false); %!assert(isrgb(logical(round(rand(5,5,3)))),false); image-2.4.1/inst/PaxHeaders.6632/graythresh.m0000644000000000000000000000013212561122761015573 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/graythresh.m0000644000175000017500000007430312561122761020425 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2004 Antti Niemistö ## Copyright (C) 2007 Søren Hauberg ## Copyright (C) 2012-2013 Carnë Draug ## ## 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 3 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{level}, @var{sep}] =} graythresh (@var{img}) ## @deftypefnx {Function File} {[@var{level}, @var{sep}] =} graythresh (@var{img}, @var{method}, @var{options}) ## @deftypefnx {Function File} {[@var{level}, @var{sep}] =} graythresh (@var{hist}, @dots{}) ## Compute global image threshold. ## ## Given an image @var{img} finds the optimal threshold value @var{level} for ## conversion to a binary image with @code{im2bw}. Color images are converted ## to grayscale before @var{level} is computed. An image histogram @var{hist} ## can also be used to allow for preprocessing of the histogram. ## ## The optional argument @var{method} is the algorithm to be used (default's to ## Otsu). Some methods may have other @var{options} and/or return an extra ## value @var{sep} (see each entry for details). The available @var{method}s are: ## ## @table @asis ## @item Otsu (default) ## Implements Otsu's method as described in @cite{Nobuyuki Otsu (1979). "A ## threshold selection method from gray-level histograms", IEEE Trans. Sys., ## Man., Cyber. 9 (1): 62-66}. This algorithm chooses the threshold to minimize ## the intraclass variance of the black and white pixels. ## ## The second output, @var{sep} represents the ``goodness'' (or separability) of ## the threshold at @var{level}. It is a value within the range [0 1], the ## lower bound (zero) being attainable by, and only by, histograms having a ## single constant gray level, and the upper bound being attainable by, and only ## by, two-valued pictures. ## ## @item concavity ## Find a global threshold for a grayscale image by choosing the threshold to ## be in the shoulder of the histogram @cite{A. Rosenfeld, and P. De La Torre ## (1983). "Histogram concavity analysis as an aid in threshold selection", IEEE ## Transactions on Systems, Man, and Cybernetics, 13: 231-235}. ## ## @item intermodes ## This assumes a bimodal histogram and chooses the threshold to be the mean of ## the two peaks of the bimodal histogram @cite{J. M. S. Prewitt, and M. L. ## Mendelsohn (1966). "The analysis of cell images", Annals of the New York ## Academy of Sciences, 128: 1035-1053}. ## ## Images with histograms having extremely unequal peaks or a broad and flat ## valley are unsuitable for this method. ## ## @item intermeans ## Iterative procedure based on the iterative intermeans algorithm of @cite{T. ## Ridler, and S. Calvard (1978). "Picture thresholding using an iterative ## selection method", IEEE Transactions on Systems, Man, and Cybernetics, 8: 630-632} ## and @cite{H. J. Trussell (1979). "Comments on 'Picture thresholding using an ## iterative selection method'", IEEE Transactions on Systems, Man, and Cybernetics, ## 9: 311}. ## ## Note that several implementations of this method exist. See the source code ## for details. ## ## @item MaxEntropy ## Implements Kapur-Sahoo-Wong (Maximum Entropy) thresholding method based on the ## entropy of the image histogram @cite{J. N. Kapur, P. K. Sahoo, and A. C. K. Wong ## (1985). "A new method for gray-level picture thresholding using the entropy ## of the histogram", Graphical Models and Image Processing, 29(3): 273-285}. ## ## @item MaxLikelihood ## Find a global threshold for a grayscale image using the maximum likelihood ## via expectation maximization method @cite{A. P. Dempster, N. M. Laird, and D. B. ## Rubin (1977). "Maximum likelihood from incomplete data via the EM algorithm", ## Journal of the Royal Statistical Society, Series B, 39:1-38}. ## ## @item mean ## The mean intensity value. It is mostly used by other methods as a first guess ## threshold. ## ## @item MinError ## An iterative implementation of Kittler and Illingworth's Minimum Error ## thresholding @cite{J. Kittler, and J. Illingworth (1986). "Minimum error ## thresholding", Pattern recognition, 19: 41-47}. ## ## This implementation seems to converge more often than the original. ## Nevertheless, sometimes the algorithm does not converge to a solution. In ## that case a warning is displayed and defaults to the initial estimate of the ## mean method. ## ## @item minimum ## This assumes a bimodal histogram and chooses the threshold to be in the ## valley of the bimodal histogram. This method is also known as the mode ## method @cite{J. M. S. Prewitt, and M. L. Mendelsohn (1966). "The analysis of ## cell images", Annals of the New York Academy of Sciences, 128: 1035-1053}. ## ## Images with histograms having extremely unequal peaks or a broad and flat ## valley are unsuitable for this method. ## ## @item moments ## Find a global threshold for a grayscale image using moment preserving ## thresholding method @cite{W. Tsai (1985). "Moment-preserving thresholding: ## a new approach", Computer Vision, Graphics, and Image Processing, 29: 377-393} ## ## @item percentile ## Assumes a specific fraction of pixels (set at @var{options}) to be background. ## If no value is given, assumes 0.5 (equal distribution of background and foreground) ## @cite{W Doyle (1962). "Operation useful for similarity-invariant pattern ## recognition", Journal of the Association for Computing Machinery 9: 259-267} ## @end table ## ## @seealso{im2bw} ## @end deftypefn ## Notes: ## * The following methods were adapted from http://www.cs.tut.fi/~ant/histthresh/ ## intermodes percentile minimum ## MaxEntropy MaxLikelihood intermeans ## moments minerror concavity ## * Carnë Draug implemented and vectorized the Otsu's method ## * Carnë Draug vectorized percentile and moments. ## * missing methods from ImageJ ## Yen triangle RenyiEntropy ## Shanbhag Li Huang ## ImageJ function [varargout] = graythresh (img, algo = "otsu", varargin) ## Input checking if (nargin < 1 || nargin > 3) print_usage(); elseif (nargin > 2 && !any (strcmpi (algo, {"percentile"}))) error ("graythresh: algorithm `%s' does not accept any options.", algo); else hist_in = false; ## If the image is RGB convert it to grayscale if (isrgb (img)) img = rgb2gray (img); elseif (isgray (img)) ## do nothing elseif (isvector (img) && !issparse (img) && isreal (img) && all (img >= 0)) hist_in = true; ihist = img; else error ("graythresh: input must be an image or an histogram."); endif endif ## the "mean" is the simplest of all, we can get rid of it right here if (strcmpi (algo, "mean")) varargout{1} = mean (im2double(img)(:)); return endif ## we only need to do this if the input is an image. If an histogram, is ## supplied, no need to do any of this if (!hist_in) ## if image is uint we do nothing. If it's int, then we convert to uint since ## it may mess up calculations later. If it's double we need some bins so we ## choose uint8 by default... but should we adjust the histogram before? if (isa (img, "uint16") || isa (img, "uint8")) ## do nothing elseif (isa (img, "int16")) img = im2uint16 (img); img_max = 65535; else img = im2uint8 (img); endif ihist = hist (img(:), 0:intmax (class (img))); endif switch tolower (algo) case {"concavity"}, thresh = concavity (ihist); case {"intermeans"}, thresh = intermeans (ihist, floor (mean (img (:)))); case {"intermodes"}, thresh = intermodes (ihist); case {"maxentropy"}, thresh = maxentropy (ihist); case {"maxlikelihood"}, thresh = maxlikelihood (ihist); case {"minerror"}, thresh = minerror_iter (ihist, floor (mean (img (:)))); case {"minimum"}, thresh = minimum (ihist); case {"moments"}, thresh = moments (ihist); case {"otsu"}, thresh = otsu (ihist, nargout > 1); case {"percentile"}, thresh = percentile (ihist, varargin{:}); otherwise, error ("graythresh: unknown method '%s'", algo); endswitch ## normalize the threshold value to the [0 1] range thresh{1} = double (thresh{1}) / (numel (ihist) - 1); ## some algorithms may return more than one value... for i = 1:numel (thresh) varargout{i} = thresh{i}; endfor endfunction function [thresh] = otsu (ihist, compute_good) ## this method is quite well explained at ## http://www.labbookpages.co.uk/software/imgProc/otsuThreshold.html ## ## It does not, however, explain how to compute the goodness of threshold and ## there's not many pages explaining it either. For that, one really needs to ## check the paper. ## ## The implementation on the link above assumes that threshold is to be ## made for values "greater or equal than" but that is not the case (in im2bw ## and also not ImageJ) so we subtract 1 at the end. bins = 0:(numel (ihist) - 1); total = sum (ihist); ## b = black, w = white b_totals = cumsum ([0 ihist(1:end-1)]); b_weights = b_totals / total; b_means = [0 cumsum(bins(1:end-1) .* ihist(1:end-1))] ./ b_totals; w_totals = total - b_totals; w_weights = w_totals / total; w_means = (cumsum (bins(end:-1:1) .* ihist(end:-1:1)) ./ w_totals(end:-1:1))(end:-1:1); ## between class variance (its maximum is the best threshold) bcv = b_weights .* w_weights .* (b_means - w_means).^2; ## in case there's more than one place with best maximum (for example, a group ## of empty bins, we select the one in the center (this is compatible with ImageJ) thresh{1} = ceil (mean (find (bcv == max (bcv)))) - 2; ## we subtract 2, once for the 1 based indexes and another for the greater ## than or equal problem if (compute_good) ## basically we need to divide the between class variance by the total ## variance which is a single value, independent of the threshold. From the ## paper, last of the equation 12, eta = sigma²b / sigma²t ##(where b = between and t = total) norm_hist = ihist / total; total_mean = sum (bins .* norm_hist); total_variance = sum (((bins - total_mean).^2) .* norm_hist); thresh{2} = max (bcv) / total_variance; endif endfunction function level = moments (y) n = numel (y) - 1; ## The threshold is chosen such that partial_sumA(y,t)/partial_sumA(y,n) ## is closest to x0. sumY = sum (y); Avec = cumsum (y) / sumY; sumB = partial_sumB (y,n); sumC = partial_sumC (y,n); sumD = partial_sumD (y,n); ## The following finds x0. x2 = (sumB*sumC - sumY*sumD) / (sumY*sumC - sumB^2); x1 = (sumB*sumD - sumC^2) / (sumY*sumC - sumB^2); x0 = .5 - (sumB/sumY + x2/2) / sqrt (x2^2 - 4*x1); ## And finally the threshold [~, ind] = min (abs (Avec-x0)); level{1} = ind-1; endfunction function T = maxentropy(y) n = numel (y) - 1; warning ("off", "Octave:divide-by-zero", "local"); ## The threshold is chosen such that the following expression is minimized. sumY = sum (y); negY = negativeE (y, n); for j = 0:n sumA = partial_sumA (y, j); negE = negativeE (y, j); sum_diff = sumY - sumA; vec(j+1) = negE/sumA - log10 (sumA) + (negY-negE)/(sum_diff) - log10 (sum_diff); end [~,ind] = min (vec); T{1} = ind-1; endfunction function [T] = intermodes (y) ## checked with ImageJ and is slightly different but not by much n = numel (y) - 1; % Smooth the histogram by iterative three point mean filtering. iter = 0; while ~bimodtest(y) h = ones(1,3)/3; y = conv2(y,h,'same'); iter = iter+1; % If the histogram turns out not to be bimodal, set T to zero. if iter > 10000; T{1} = 0; return end end % The threshold is the mean of the two peaks of the histogram. ind = 0; for k = 2:n if y(k-1) < y(k) && y(k+1) < y(k) ind = ind+1; TT(ind) = k-1; end end T{1} = floor(mean(TT)); endfunction ## The threshold is chosen such that 50% (in case of p = 0.5) of ## pixels lie in each category. function [T] = percentile (y, p = 0.5) Avec = cumsum (y) / sum (y); [~, ind] = min (abs (Avec - p)); T{1} = ind -1; endfunction function T = minimum(y) n = numel (y) - 1; % Smooth the histogram by iterative three point mean filtering. iter = 0; while ~bimodtest(y) h = ones(1,3)/3; y = conv2(y,h,'same'); iter = iter+1; % If the histogram turns out not to be bimodal, set T to zero. if iter > 10000; T{1} = 0; return end end peakfound = false; for k = 2:n if y(k-1) < y(k) && y(k+1) < y(k) peakfound = true; end if peakfound && y(k-1) >= y(k) && y(k+1) >= y(k) T{1} = k-1; return end end endfunction function [Tout] = minerror_iter (y, T) n = numel (y) - 1; Tprev = NaN; warning ("off", "Octave:divide-by-zero", "local"); sumA = partial_sumA (y, n); sumB = partial_sumB (y, n); sumC = partial_sumC (y, n); while T ~= Tprev % Calculate some statistics. sumAT = partial_sumA (y, T); sumBT = partial_sumB (y, T); sumCT = partial_sumC (y, T); sumAdiff = sumA - sumAT; mu = sumBT/sumAT; nu = (sumB-sumBT)/(sumAdiff); p = sumAT/sumA; q = (sumAdiff) / sumA; sigma2 = sumCT/sumAT-mu^2; tau2 = (sumC-sumCT) / (sumAdiff) - nu^2; % The terms of the quadratic equation to be solved. w0 = 1/sigma2-1/tau2; w1 = mu/sigma2-nu/tau2; w2 = mu^2/sigma2 - nu^2/tau2 + log10((sigma2*q^2)/(tau2*p^2)); % If the next threshold would be imaginary, return with the current one. sqterm = w1^2-w0*w2; if sqterm < 0 warning('MINERROR:NaN','Warning: th_minerror_iter did not converge.') break endif % The updated threshold is the integer part of the solution of the % quadratic equation. Tprev = T; T = floor((w1+sqrt(sqterm))/w0); % If the threshold turns out to be NaN, return with the previous threshold. if isnan(T) warning('MINERROR:NaN','Warning: th_minerror_iter did not converge.') T = Tprev; end endwhile Tout{1} = T; endfunction #{ ## this is an implementation of the original minerror algorithm but seems ## to converge less often than the iterative version. This one is also from the ## HistThresh toolbox function T = th_minerror(I,n) if nargin == 1 n = 255; end I = double(I); % Calculate the histogram. y = hist(I(:),0:n); % The threshold is chosen such that the following expression is minimized. for j = 0:n mu = partial_sumB(y,j)/partial_sumA(y,j); nu = (partial_sumB(y,n)-partial_sumB(y,j))/(partial_sumA(y,n)-partial_sumA(y,j)); p = partial_sumA(y,j)/partial_sumA(y,n); q = (partial_sumA(y,n)-partial_sumA(y,j)) / partial_sumA(y,n); sigma2 = partial_sumC(y,j)/partial_sumA(y,j)-mu^2; tau2 = (partial_sumC(y,n)-partial_sumC(y,j)) / (partial_sumA(y,n)-partial_sumA(y,j)) - nu^2; vec(j+1) = p*log10(sqrt(sigma2)/p) + q*log10(sqrt(tau2)/q); end vec(vec==-inf) = NaN; [minimum,ind] = min(vec); T = ind-1; endfunction #} function Tout = maxlikelihood (y) n = numel (y) - 1; ## initial estimate for the threshold is found with the minimum algorithm T = minimum (y){1}; sumY = sum (y); sumB = partial_sumB (y, n); sumC = partial_sumC (y, n); sumAT = partial_sumA (y, T); sumBT = partial_sumB (y, T); sumCT = partial_sumC (y, T); ## initial values for the statistics mu = sumBT / sumAT; nu = (sumB - sumBT) / (sumY - sumAT); p = sumAT / sumY; q = (sumY - sumAT) / sumY; sigma2 = sumCT / sumAT - mu^2; tau2 = (sumC - sumCT) / (sumY - sumAT) - nu^2; ## Return if sigma2 or tau2 are zero, to avoid division by zero if (sigma2 == 0 || tau2 == 0) Tout{1} = T; return endif do ## we store the previous values for comparison at the end (we will stop when ## they stop changing) mu_prev = mu; nu_prev = nu; p_prev = p; q_prev = q; sigma2_prev = nu; tau2_prev = nu; for i = 0:n phi(i+1) = p/sqrt((sigma2)) * exp(-((i-mu)^2) / (2*sigma2)) / ... (p/sqrt(sigma2) * exp(-((i-mu)^2) / (2*sigma2)) + ... (q/sqrt(tau2)) * exp(-((i-nu)^2) / (2*tau2))); endfor ind = 0:n; gamma = 1-phi; F = phi*y'; G = gamma*y'; mu = ind.*phi*y'/F; nu = ind.*gamma*y'/G; p = F / sumY; q = G / sumY; sigma2 = ind.^2.*phi*y'/F - mu^2; tau2 = ind.^2.*gamma*y'/G - nu^2; until (abs (mu - mu_prev) <= eps || abs (nu - nu_prev) <= eps || ... abs (p - p_prev) <= eps || abs (q - q_prev) <= eps || ... abs (sigma2 - sigma2_prev) <= eps || abs (tau2 - tau2_prev) <= eps) ## the terms of the quadratic equation to be solved w0 = 1/sigma2-1/tau2; w1 = mu/sigma2-nu/tau2; w2 = mu^2/sigma2 - nu^2/tau2 + log10((sigma2*q^2)/(tau2*p^2)); ## If the threshold would be imaginary, return with threshold set to zero sqterm = w1^2-w0*w2; if (sqterm < 0) Tout{1} = 0; return endif ## The threshold is the integer part of the solution of the quadratic equation Tout{1} = floor((w1+sqrt(sqterm))/w0); endfunction function Tout = intermeans (y, T) n = numel (y) - 1; Tprev = NaN; % The threshold is found iteratively. In each iteration, the means of the % pixels below (mu) the threshold and above (nu) it are found. The % updated threshold is the mean of mu and nu. sumY = sum (y); sumB = partial_sumB (y, n); while T ~= Tprev sumAT = partial_sumA (y, T); sumBT = partial_sumB (y, T); mu = sumBT/sumAT; nu = (sumB-sumBT)/(sumY-sumAT); Tprev = T; T = floor((mu+nu)/2); end Tout{1} = T; endfunction function T = concavity (h) n = numel (h) - 1; H = hconvhull(h); % Find the local maxima of the difference H-h. lmax = flocmax(H-h); % Find the histogram balance around each index. for k = 0:n E(k+1) = hbalance(h,k); end % The threshold is the local maximum with highest balance. E = E.*lmax; [dummy ind] = max(E); T{1} = ind-1; endfunction ################################################################################ ## Auxiliary functions from HistThresh toolbox http://www.cs.tut.fi/~ant/histthresh/ ################################################################################ ## partial sums from C. A. Glasbey, "An analysis of histogram-based thresholding ## algorithms," CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993. function x = partial_sumA (y, j) x = sum (y(1:j+1)); endfunction function x = partial_sumB (y, j) ind = 0:j; x = ind*y(1:j+1)'; endfunction function x = partial_sumC (y, j) ind = 0:j; x = ind.^2*y(1:j+1)'; endfunction function x = partial_sumD (y, j) ind = 0:j; x = ind.^3*y(1:j+1)'; endfunction ## Test if a histogram is bimodal. function b = bimodtest(y) len = length(y); b = false; modes = 0; % Count the number of modes of the histogram in a loop. If the number % exceeds 2, return with boolean return value false. for k = 2:len-1 if y(k-1) < y(k) && y(k+1) < y(k) modes = modes+1; if modes > 2 return end end end % The number of modes could be less than two here if modes == 2 b = true; end endfunction ## Find the local maxima of a vector using a three point neighborhood. function y = flocmax(x) % y binary vector with maxima of x marked as ones len = length(x); y = zeros(1,len); for k = 2:len-1 [dummy,ind] = max(x(k-1:k+1)); if ind == 2 y(k) = 1; end end endfunction ## Calculate the balance measure of the histogram around a histogram index. function E = hbalance(y,ind) % y histogram % ind index about which balance is calculated % % Out: % E balance measure % % References: % % A. Rosenfeld and P. De La Torre, "Histogram concavity analysis as an aid % in threshold selection," IEEE Transactions on Systems, Man, and % Cybernetics, vol. 13, pp. 231-235, 1983. % % P. K. Sahoo, S. Soltani, and A. K. C. Wong, "A survey of thresholding % techniques," Computer Vision, Graphics, and Image Processing, vol. 41, % pp. 233-260, 1988. n = length(y)-1; E = partial_sumA(y,ind)*(partial_sumA(y,n)-partial_sumA(y,ind)); endfunction ## Find the convex hull of a histogram. function H = hconvhull(h) % In: % h histogram % % Out: % H convex hull of histogram % % References: % % A. Rosenfeld and P. De La Torre, "Histogram concavity analysis as an aid % in threshold selection," IEEE Transactions on Systems, Man, and % Cybernetics, vol. 13, pp. 231-235, 1983. len = length(h); K(1) = 1; k = 1; % The vector K gives the locations of the vertices of the convex hull. while K(k)~=len theta = zeros(1,len-K(k)); for i = K(k)+1:len x = i-K(k); y = h(i)-h(K(k)); theta(i-K(k)) = atan2(y,x); end maximum = max(theta); maxloc = find(theta==maximum); k = k+1; K(k) = maxloc(end)+K(k-1); end % Form the convex hull. H = zeros(1,len); for i = 2:length(K) H(K(i-1):K(i)) = h(K(i-1))+(h(K(i))-h(K(i-1)))/(K(i)-K(i-1))*(0:K(i)-K(i-1)); end endfunction ## Entropy function. Note that the function returns the negative of entropy. function x = negativeE(y,j) ## used by the maxentropy method only y = y(1:j+1); y = y(y~=0); x = sum(y.*log10(y)); endfunction ## these were tested with ImageJ %!shared img, histo %! ## this is the old default.img that came with GNU Octave. While the current %! ## is very very similar, is off just enough for us to get precision errors %! img = uint8 (reshape ([138 138 138 142 142 138 142 138 138 117 105 81 69 61 53 40 49 45 40 36 40 45 53 49 65 73 121 166 210 243 247 247 247 239 235 178 154 170 150 150 162 174 190 190 194 186 178 170 154 182 198 174 117 138 138 142 138 142 142 146 142 138 138 130 109 97 81 73 69 57 53 53 57 61 61 69 73 77 105 121 158 219 243 243 247 243 243 243 206 150 158 158 158 150 158 182 186 190 194 186 174 190 206 198 162 138 142 138 142 146 138 142 142 138 146 142 134 142 130 121 101 97 85 85 81 81 81 85 93 85 73 57 61 93 150 194 215 239 243 243 243 223 166 138 158 158 154 142 162 178 190 190 198 186 182 186 174 162 182 146 142 138 142 142 146 142 146 146 146 146 142 142 142 134 125 101 85 73 65 69 73 73 57 40 53 49 57 69 85 125 166 182 178 178 174 150 130 121 146 146 150 142 166 182 190 182 174 166 162 170 194 198 138 138 146 146 138 146 146 146 146 142 150 146 146 142 130 93 65 45 45 49 45 40 49 40 49 49 49 49 61 81 113 142 150 154 154 146 142 134 125 125 138 134 125 146 162 178 178 178 166 186 202 206 186 142 142 142 134 142 146 142 150 142 146 142 146 146 130 81 53 49 49 45 49 40 36 36 32 36 36 36 53 73 89 125 150 146 134 138 146 138 146 138 142 117 117 113 117 146 166 174 178 182 178 178 170 146 142 142 138 142 146 142 142 146 150 138 146 142 130 73 49 40 49 57 65 69 73 61 61 53 57 53 61 77 77 97 113 138 134 130 138 142 150 146 150 134 138 121 121 101 121 150 158 154 142 150 162 166 178 138 138 146 142 142 142 142 146 146 142 142 130 73 57 49 36 49 65 77 85 89 85 81 81 81 85 93 93 97 105 117 125 150 158 154 162 162 166 154 134 150 130 125 113 138 182 174 154 130 178 227 239 239 134 138 142 138 142 142 146 146 138 150 125 61 49 32 32 45 49 57 65 85 101 105 101 101 109 125 117 113 109 138 134 125 166 178 170 162 150 170 162 170 150 146 150 138 125 162 186 182 142 206 247 247 243 138 138 138 138 142 142 146 146 146 130 85 45 45 36 40 53 45 57 69 97 125 130 130 134 138 146 142 134 142 158 138 117 146 174 170 174 178 170 174 170 166 154 162 158 130 134 170 178 158 190 243 247 247 142 142 142 142 142 146 146 142 138 89 53 45 40 45 45 49 57 77 93 125 138 150 154 158 158 162 154 150 166 174 142 73 125 174 178 174 182 182 178 178 174 166 174 174 162 125 154 170 174 170 227 247 251 142 138 142 142 142 142 142 138 105 61 40 40 32 40 40 49 61 89 117 146 154 158 162 170 170 174 162 166 174 182 150 65 146 166 174 186 198 198 198 190 178 178 174 174 158 134 154 198 194 174 202 251 251 146 142 142 142 146 150 138 134 69 40 40 36 32 40 45 45 65 101 134 150 158 166 174 178 174 174 174 170 170 174 142 73 150 162 178 194 202 202 194 194 178 178 154 134 125 138 154 198 194 186 190 243 251 150 146 146 146 146 150 130 109 53 45 28 40 40 36 32 49 73 101 130 154 162 170 170 170 178 182 178 178 174 158 142 121 146 158 178 174 186 190 186 186 174 146 105 109 113 130 150 178 202 190 186 243 251 146 146 146 146 150 142 109 73 49 40 32 40 40 45 40 53 69 93 130 154 162 170 174 178 182 182 186 182 178 154 146 130 138 142 150 170 182 178 174 166 150 117 97 105 113 130 150 150 174 182 190 243 251 146 146 154 146 150 134 105 53 40 45 45 40 40 36 36 40 69 105 134 162 170 174 178 182 182 182 186 190 186 178 170 158 154 150 162 182 182 174 174 174 150 113 109 113 113 130 150 162 186 186 190 239 251 154 150 146 150 146 125 77 49 36 40 36 40 36 28 40 36 77 113 138 150 170 170 174 186 190 190 190 194 190 186 194 190 170 162 174 194 174 182 170 170 158 121 113 113 113 146 158 170 210 215 215 206 243 150 146 150 150 150 113 57 49 40 45 45 49 49 40 32 45 85 113 142 170 178 174 182 194 190 194 194 198 198 198 210 210 182 162 170 190 182 186 170 170 162 130 121 113 121 146 154 150 198 215 206 210 215 150 150 150 150 150 105 49 45 40 49 49 57 40 49 49 53 85 121 158 182 178 174 182 198 194 194 194 194 202 202 194 186 174 154 162 166 178 174 170 170 170 158 117 113 130 150 154 121 182 194 206 215 206 158 150 150 150 146 97 45 36 49 49 49 40 40 49 49 65 97 130 154 174 174 174 186 194 194 194 194 198 198 186 170 158 154 158 138 158 162 170 190 182 174 170 138 138 142 154 134 142 146 170 206 219 215 150 150 158 158 150 85 36 40 40 40 40 45 45 49 49 65 97 130 146 166 166 174 182 190 194 194 194 194 190 182 162 158 150 158 182 186 178 198 206 198 190 174 154 174 174 142 142 170 170 166 202 223 219 158 150 150 150 146 85 40 45 40 40 36 45 53 45 49 53 93 117 130 154 162 174 190 186 194 194 194 190 186 178 162 162 170 174 182 198 210 206 210 198 198 182 170 178 174 158 154 194 194 174 198 210 215 150 154 158 150 150 85 49 45 40 40 32 36 53 40 45 53 81 109 142 158 158 174 178 182 190 190 194 190 190 178 170 174 178 186 190 190 206 215 202 206 194 186 178 182 174 154 170 198 210 186 186 202 215 150 154 150 154 150 97 45 40 40 40 36 36 45 40 45 73 89 113 142 158 158 174 174 182 186 186 194 186 182 178 174 170 105 166 206 186 190 202 198 194 190 182 182 174 166 154 162 198 215 202 182 202 219 154 150 154 150 146 117 61 45 45 45 36 53 53 49 53 77 93 101 125 158 162 174 174 178 174 186 190 182 182 186 182 182 77 125 198 194 186 190 190 178 178 178 162 162 162 154 186 210 227 210 190 206 223 154 150 154 150 154 138 65 45 45 45 40 49 49 40 53 65 77 89 113 150 158 166 166 170 178 182 186 182 170 170 170 162 81 117 186 190 186 182 178 186 174 166 162 150 130 154 194 227 227 219 202 202 219 154 154 150 154 146 146 89 45 40 45 40 49 49 36 40 57 65 89 109 138 146 158 158 170 170 178 182 178 162 150 158 154 113 146 186 182 178 182 178 170 170 162 146 138 138 146 202 223 231 219 210 190 215 130 130 130 130 130 130 109 45 53 40 32 36 40 45 53 61 65 81 97 117 130 138 150 158 158 178 170 162 158 138 142 150 146 166 178 174 174 170 170 170 162 158 138 117 117 142 202 223 239 223 215 186 206 61 61 65 69 69 65 57 36 40 36 32 40 40 53 57 53 57 69 93 105 109 130 138 142 154 162 150 138 142 125 121 150 162 170 170 166 170 170 170 166 162 138 121 113 130 170 202 223 227 231 202 178 182 45 49 45 40 40 40 45 45 45 45 36 40 32 49 61 61 57 65 73 81 101 109 121 130 142 146 121 89 93 117 113 134 154 174 166 162 166 170 170 162 154 150 142 150 223 186 194 215 231 227 206 182 174 49 40 45 45 49 49 45 49 49 49 49 40 36 45 57 69 65 61 65 69 85 93 109 109 117 109 89 57 57 81 97 113 154 162 166 162 170 158 158 162 154 162 174 231 239 178 186 210 231 239 210 194 178 49 36 49 45 49 49 49 45 45 49 49 36 40 40 45 36 53 53 53 57 57 69 69 73 69 61 57 45 45 65 89 105 125 142 146 150 150 154 162 170 174 223 235 247 231 178 178 206 227 227 223 198 190 40 53 36 45 40 40 40 40 45 40 40 45 45 45 45 40 53 49 49 45 53 45 32 36 36 36 36 40 49 45 61 73 89 93 97 113 125 142 186 202 239 239 243 251 239 198 166 194 215 235 227 215 202 40 45 36 32 36 40 40 45 40 40 45 49 45 49 45 49 40 40 45 49 40 45 45 45 49 49 32 40 49 40 49 57 69 81 101 134 170 206 235 243 243 239 247 251 247 210 170 186 202 231 231 227 210 49 45 49 40 40 40 49 45 40 40 45 45 45 40 45 45 45 49 40 49 40 49 45 45 36 40 40 45 45 45 45 65 121 150 210 239 243 243 247 243 243 247 251 251 239 223 178 174 194 219 239 231 219 36 45 45 40 40 49 40 45 49 49 40 40 45 49 40 40 45 49 45 40 49 45 40 40 40 49 40 45 40 49 49 121 162 215 247 247 247 247 247 243 247 251 251 251 247 239 223 194 186 202 215 210 210 36 45 45 40 40 49 40 45 32 36 49 36 45 49 40 40 45 40 36 40 45 45 40 40 40 36 45 32 40 49 57 121 142 215 243 247 243 247 243 247 251 251 251 251 247 247 247 227 186 194 190 190 182 40 32 45 32 45 40 45 45 49 45 40 45 49 36 40 45 32 40 45 45 49 45 45 45 45 53 49 53 45 45 40 69 97 186 239 243 247 247 247 251 251 251 251 251 243 243 231 202 202 206 206 186 170 53 40 40 40 40 40 36 32 32 36 45 53 49 32 36 32 36 32 40 49 40 40 45 40 40 53 45 49 49 40 32 40 49 138 219 235 247 247 251 251 251 251 251 247 243 235 198 206 210 198 190 186 186 73 69 61 57 61 49 53 40 49 45 40 49 49 49 57 57 53 49 53 53 45 40 45 40 45 49 45 49 45 40 32 53 69 101 215 231 247 247 247 247 251 251 251 243 235 219 194 202 202 186 186 190 194], [53 40])); %!assert (graythresh (img, "percentile"), 142/255); %!assert (graythresh (img, "percentile", 0.5), 142/255); %!assert (graythresh (img, "moments"), 142/255); %!assert (graythresh (img, "minimum"), 93/255); %!assert (graythresh (img, "maxentropy"), 150/255); %!assert (graythresh (img, "intermodes"), 99/255); %!assert (graythresh (img, "otsu"), 115/255); %! histo = hist (img(:), 0:255); %!assert (graythresh (histo, "otsu"), 115/255); ## for the mean our results differ from matlab because we do not calculate it ## from the histogram. Our results should be more accurate. %!assert (graythresh (img, "mean"), 0.51445615982, 0.000000001); # here our results differ from ImageJ image-2.4.1/inst/PaxHeaders.6632/ycbcr2rgb.m0000644000000000000000000000013212561122761015272 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/inst/ycbcr2rgb.m0000644000175000017500000000414312561122761020117 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{cmap} =} ycbcr2rgb (@var{YCbCrmap}) ## @deftypefnx {Function File} {@var{RGB} =} ycbcr2rgb (@var{YCbCr}) ## @deftypefnx {Function File} {@dots{} =} ycbcr2rgb (@dots{}, [@var{Kb} @var{Kr}]) ## @deftypefnx {Function File} {@dots{} =} ycbcr2rgb (@dots{}, @var{standard}) ## Convert YCbCr color space to RGB. ## ## The conversion changes the image @var{YCbCr} or colormap @var{YCbCrmap}, ## from the YCbCr (luminance, chrominance blue, and chrominance red) ## color space to RGB values. @var{YCbCr} must be of class double, single, ## uint8, or uint16. ## ## The formula used for the conversion is dependent on two constants, @var{Kb} ## and @var{Kr} which can be specified individually, or according to existing ## standards: ## ## @table @asis ## @item "601" (default) ## According to the ITU-R BT.601 (formerly CCIR 601) standard. Its values ## of @var{Kb} and @var{Kr} are 0.114 and 0.299 respectively. ## @item "709" (default) ## According to the ITU-R BT.709 standard. Its values of @var{Kb} and ## @var{Kr} are 0.0722 and 0.2116 respectively. ## @end table ## ## @seealso{hsv2rgb, ntsc2rgb, rgb2hsv, rgb2ntsc, rgb2ycbcr} ## @end deftypefn function rgb = ycbcr2rgb (ycbcr, standard = "601") if (nargin < 1 || nargin > 2) print_usage (); endif rgb = ycbcrfunc ("ycbcr2rgb", ycbcr, standard); endfunction %!assert (ycbcr2rgb (rgb2ycbcr (jet (10))), jet (10), 0.00001); image-2.4.1/inst/PaxHeaders.6632/imattributes.m0000644000000000000000000000013212561122761016127 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imattributes.m0000644000175000017500000001214712561122761020757 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imattributes () ## @deftypefnx {Function File} {} imattributes (@var{himage}) ## Get information about image attributes. ## ## Return attributes for the image in the current figure or in the image ## handle @var{himage}. Returns a struct with the fields: ## ## @table @asis ## @item @qcode{"Width"} ## Number of columns. ## ## @item @qcode{"Height"} ## Number of rows. ## ## @item @qcode{"Class"} ## Note that some classes are converted to double for display. ## ## @item @qcode{"Image type"} ## One of @qcode{"binary"}, @qcode{"truecolor"}, @qcode{"intensity"}, or ## @qcode{"indexed"}. ## ## @item @qcode{"Minimum intensity"} ## @itemx @qcode{"Maximum intensity"} ## These values are not returned for images of type @qcode{"truecolor"} ## and @qcode{"binary"}. ## ## For indexed images, the returned values are the lowest and highest index ## for the colormap, @emph{not} the used index for the lowest or highest ## intensity or their values. This weird behaviour is kept for Matlab ## compatibility. ## @end table ## ## This function is meant to be used in an interactive session, and not ## programatically. The properties of an image should be measured from the ## image variable itself not from the figure object. In addition this ## function is purposely Matlab incompatible on their return value which ## returns a cell array of strings which is only useful for display. ## ## @end deftypefn function attr = imattributes (imgh = gcf ()) if (nargin > 1) print_usage (); elseif (isa (imgh, "imagemodel")) ## FIXME we don't even have a imagemodel class yet but when we do, this ## is already here error ("imattributes: support for imagemodel objects not yet implemented"); endif while (! isempty (get (imgh, "children"))) imgh = get (imgh, "children"); endwhile cdata = get (imgh, "cdata"); cdatamapping = get (imgh, "cdatamapping"); if (isbool (cdata)) img_type = "binary"; elseif (ndims (cdata) == 3) img_type = "truecolor"; elseif (strcmpi (cdatamapping, "direct")) img_type = "indexed"; else img_type = "intensity"; endif ## Implementation note: this function returns a struct while Matlab returns ## a cell array of strings (even for the numeric values). It is completely ## useless in programs, so I can only assume it is meant to be used ## interactively. If so, a cell array is useless for us because Octave does ## not display cell arrays columns aligned but a struct looks good. attr = struct ( "Width (columns)", columns (cdata), "Height (rows)", rows (cdata), "Class", class (cdata), "Image type", img_type ); ## Matlab compatibility: for indexed images, we still give the lowest ## and highest index to the colormap. if (! any (strcmp (img_type, {"binary", "truecolor"}))) attr = setfield (attr, "Minimum intensity", min (cdata(:))); attr = setfield (attr, "Maximum intensity", max (cdata(:))); endif endfunction %!shared x, map, img, rgb, bw %! [x, map] = imread ("default.img"); %! rgb = ind2rgb (x, map); %! img = ind2gray (x, map); %! bw = im2bw (img); %!test %! h = imshow (img); %! a = imattributes (h); %! assert ([a.("Height (rows)") a.("Width (columns)")], [53 40]); %! assert (a.Class, "uint8"); %! assert (a.("Image type"), "intensity"); %! assert (a.("Minimum intensity"), uint8 (28)); %! assert (a.("Maximum intensity"), uint8 (250)); ## FIXME this is a bug upstream, the original class is not always preserved %!xtest %! h = imshow (rgb); %! a = imattributes (h); %! assert ([a.("Height (rows)") a.("Width (columns)")], [53 40]); %! assert (a.Class, "uint8"); %! assert (a.("Image type"), "truecolor"); %! assert (isfield (a, "Minimum intensity"), false); %! assert (isfield (a, "Maximum intensity"), false); %!test %! h = imshow (bw); %! a = imattributes (h); %! assert ([a.("Height (rows)") a.("Width (columns)")], [53 40]); %! assert (a.Class, "logical"); %! assert (a.("Image type"), "binary"); %! assert (isfield (a, "Minimum intensity"), false); %! assert (isfield (a, "Maximum intensity"), false); %!test %! h = imshow (x, map); %! a = imattributes (h); %! assert ([a.("Height (rows)") a.("Width (columns)")], [53 40]); %! assert (a.Class, "uint8"); %! assert (a.("Image type"), "indexed"); %! assert (a.("Minimum intensity"), uint8 (0)); %! assert (a.("Maximum intensity"), uint8 (55)); %!test %! h = imshow (img); %! a1 = imattributes (); %! a2 = imattributes (h); %! assert (a1, a2); image-2.4.1/inst/PaxHeaders.6632/blockproc.m0000644000000000000000000000013212561122761015371 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/blockproc.m0000644000175000017500000001400712561122761020216 0ustar00carandraugcarandraug00000000000000## 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 3 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} = } blockproc (@var{A}, [@var{m},@var{n}], @var{fun}) ## @deftypefnx {Function File} {@var{B} = } blockproc (@var{A}, [@var{m},@var{n}], @var{fun}, @dots{}) ## @deftypefnx {Function File} {@var{B} = } blockproc (@var{A}, [@var{m},@var{n}], [@var{mborder},@var{nborder}], @var{fun}, @dots{}) ## @deftypefnx {Function File} {@var{B} = } blockproc (@var{A}, 'indexed', @dots{}) ## Processes image in blocks using user-supplied function. ## ## @code{B=blockproc(A,[m,n],fun)} divides image @var{A} in ## @var{m}-by-@var{n} blocks, and passes them to user-supplied function ## @var{fun}, which result is concatenated to build returning matrix ## @var{B}. If padding is needed to build @var{m}-by-@var{n}, it is added ## at the bottom and right borders of the image. 0 is used as a padding ## value. ## ## @code{B=blockproc(A,[m,n],fun, @dots{})} behaves as described above but ## passes extra parameters to function @var{fun}. ## ## @code{B=blockproc(A,[m,n],[mborder,nborder],fun, @dots{})} behaves as ## described but uses blocks which overlap with neighbour blocks. ## Overlapping dimensions are @var{mborder} vertically and @var{nborder} ## horizontally. This doesn't change the number of blocks in an image ## (which depends only on size(@var{A}) and [@var{m},@var{n}]). Adding a ## border requires extra padding on all edges of the image. 0 is used as ## a padding value. ## ## @code{B=blockproc(A,'indexed', @dots{})} assumes that @var{A} is an indexed ## image, so it pads the image using proper value: 0 for uint8 and ## uint16 images and 1 for double images. Keep in mind that if 'indexed' ## is not specified padding is always done using 0. ## ## @seealso{colfilt,inline,bestblk} ## @end deftypefn function B = blockproc(A, varargin) if(nargin<3) print_usage; endif ## check 'indexed' presence indexed=false; p=1; if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) 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("blockproc: expected [m,n] but param is not a vector."); endif if(length(varargin{p})!=2) error("blockproc: expected [m,n] but param has wrong length."); endif sblk=varargin{p}(:); p+=1; ## check [mborder,nborder] if(nargin ## ## 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 3 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} {} edgetaper (@var{img}, @var{psf}) ## Blur border (edges) of image to prevent ringing artifacts. ## ## @emph{Warning}: this function is not @sc{Matlab} compatible and ## is likely to change in the future. ## ## @end deftypefn function imgt = edgetaper (img, psf) if (nargin != 2) print_usage (); elseif (! isnumeric (img)) error ("edgetaper: IMG must be numeric") elseif (! isnumeric (psf)) error ("edgetaper: PSF must be numeric") endif img_size = size (img); psf_size = size (psf); n = max (numel (img_size), numel (psf_size)); img_size = postpad (img_size(:), n, 1); psf_size = postpad (psf_size(:), n, 1); ## beware of psf_size = [16 16 1 8] paired with img_size [512 512 1 50] ## which are valid, singleton dimensions do not count for this check if (any ((psf_size > (img_size / 2)) & (psf_size > 1))) error ("edgetaper: PSF must be smaller than half of IMG dimensions") endif psf = psf ./ sum (psf(:)); # we use it for blurring so the sum must be 1 ## FIXME this function is not Matlab compatible. I have no clue what ## Matlab is doing but is definitely not what they claim on the ## documentation. There are no references for the function and ## the documentation is sparse and incorrect. ## ## I have found papers that compare their method for reducing ## boundary artifacts against Matlab's edgetaper but even they ## do not comment it. ## ## It an implementation of edgetaper that is close to Matlab's ## documentation for the function. If anyone has patience, please ## fix this. ## ## Some questions about it: ## ## 1. the autocorrelation of the PSF is twice the size of the PSF ## but it will still be way smaller than the image. How can it be ## used to make a weighted mean between the blurred and the original ## image? We pretty much split it and only use it on the borders ## but looks like we end up with an image too blurred. ## ## 2. how do they blur the image? I will guess they pad the ## image but how? ## ## Note: always test this function with input as double precision ## since it returns the same class as input and may hide our ## differences. blurred = fftconvn (img, psf, "same"); xpsf = normalized_autocorrelation (psf); ## The following will expand a ND matrix into a larger size ## repeating the center elements, e.g., ## ## 1 2 2 2 3 ## 1 2 3 4 5 5 5 6 ## 4 5 6 => 4 5 5 5 6 ## 7 8 9 4 5 5 5 6 ## 7 8 8 8 9 ## note the xpsf will always have odd sizes (2*psf_size +1) xdims = ndims (xpsf); xpsf_size = size (xpsf)(:); idim = arrayfun (@(c, n, f) [1:c repmat(c, [1 n]) c:f], ceil (xpsf_size /2), img_size(1:xdims) - xpsf_size -1, xpsf_size, "UniformOutput", false); subs = cell (xdims, 1); [subs{:}] = ndgrid (idim{:}); inds = sub2ind (xpsf_size, subs{:}); weights = xpsf(inds); imgt = (img .* weights) + (blurred .* (1 - weights)); imgt = cast (imgt, class (img)); endfunction function acn = normalized_autocorrelation (psf) idx = arrayfun (@colon, size (psf), repmat (-1, [1 ndims(psf)]), repmat (1, [1 ndims(psf)]), "UniformOutput", false); ac = convn (psf, conj (psf(idx{:}))); acn = ac / max (ac(:)); endfunction %!assert (class (edgetaper (rand (100), rand (16))), "double") %!assert (class (edgetaper (randi (255, 100, "uint8"), rand (16))), "uint8") image-2.4.1/inst/PaxHeaders.6632/imbothat.m0000644000000000000000000000013212561122761015222 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imbothat.m0000644000175000017500000001574512561122761020061 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2005 Carvalho-Mariel ## Copyright (C) 2010-2013 Carnë Draug ## ## 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 3 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} {} imbothat (@var{img}, @var{SE}) ## Perform morphological bottom hat filtering. ## ## The matrix @var{img} must be numeric while @var{SE} can be a: ## @itemize @bullet ## @item ## strel object; ## @item ## array of strel objects as returned by `@@strel/getsequence'; ## @item ## matrix of 0's and 1's. ## @end itemize ## ## A bottom hat transform corresponds to the difference between the closing ## of @var{img} and @var{img} itself, i.e., it is equivalent to: ## @example ## imclose (img, se) - img; ## @end example ## ## A bottom-hat transform is also known as 'black', or 'closing', top-hat ## transform. ## ## @seealso{imerode, imdilate, imopen, imclose, imtophat, mmgradm} ## @end deftypefn function black = imbothat (img, se) if (nargin != 2) print_usage (); elseif (! isimage (img)) error("imbothat: IMG must be a numeric matrix"); endif se = prepare_strel ("imbothat", se); ## Perform filtering ## Note that in case that the transform is to applied to a logical image, ## subtraction must be handled in a different way (x & !y) instead of (x - y) ## or it will return a double precision matrix if (islogical (img)) black = imclose (img, se) & ! img; else black = imclose (img, se) - img; endif endfunction %!assert (imbothat (ones (3), [1 1; 0 1]), zeros (3)); %!assert (imbothat (true (3), [1 1; 0 1]), false (3)); %!shared in, out, se %! in = [ 0 0 0 1 1 1 0 0 1 1 %! 0 1 0 1 1 1 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 0 %! 0 1 1 1 1 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 1 1 1 %! 0 0 0 0 1 0 1 0 1 0 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 0 1 1 1 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! %! out = [ 1 1 1 0 0 0 1 1 0 0 %! 1 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 1 %! 1 0 0 0 0 0 0 0 0 1 %! 0 0 0 0 1 0 0 0 0 1 %! 0 0 0 1 1 1 1 0 0 0 %! 0 0 0 1 0 1 0 1 0 1 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 1 0 0 0]; %!assert (imbothat (logical (in), ones (3)), logical (out)); %! %! out = [ 7 0 15 8 1 6 0 13 6 24 %! 0 8 9 2 0 0 16 7 0 23 %! 89 7 0 41 39 7 12 7 0 23 %! 8 1 69 40 58 1 6 2 0 43 %! 7 0 63 59 52 0 0 0 14 32 %! 62 55 6 7 0 7 0 23 16 1 %! 56 74 0 2 0 0 16 14 7 0 %! 0 73 69 0 0 19 15 8 1 0 %! 8 6 0 0 6 13 9 2 0 6 %! 7 0 0 19 0 14 7 0 23 0]; %!assert (imbothat (magic (10), ones (3)), out); %!assert (imbothat (uint8 (magic (10)), strel ("square", 3)), uint8 (out)); %! %! ## using a se that will be decomposed in 2 pieces %! out =[ 7 0 87 66 59 7 0 19 12 30 %! 0 13 81 60 58 1 19 13 6 29 %! 89 12 0 54 52 20 18 7 0 23 %! 8 6 69 53 71 14 12 2 0 43 %! 7 0 63 73 66 14 7 0 23 41 %! 76 69 14 7 0 30 23 46 39 7 %! 70 88 9 2 0 24 42 40 33 6 %! 14 87 80 0 0 43 41 34 27 0 %! 84 82 0 0 19 37 35 28 26 19 %! 89 82 0 20 13 36 29 22 45 13]; %!assert (imbothat (magic (10), ones(5)), out); %! %! ## using a weird non-symmetric and even-size se %! out =[ 0 0 15 8 1 3 0 7 0 18 %! 0 8 53 59 0 0 14 13 0 17 %! 84 0 0 40 38 6 13 6 0 23 %! 2 0 42 47 58 0 6 0 0 41 %! 0 0 62 59 52 0 0 0 16 35 %! 6 58 13 6 0 3 19 19 35 1 %! 0 18 0 0 0 0 15 13 6 0 %! 0 17 69 0 0 17 17 8 0 0 %! 8 67 0 0 0 15 9 2 0 6 %! 7 0 0 17 10 42 7 0 19 0]; %!assert (imbothat (magic (10), [1 0 0 0; 1 1 1 0; 0 1 0 1]), out); %! %! ## N dimensional and weird se %! in = reshape (magic(16), [4 8 4 2]); %! se = ones (3, 3, 3); %! se(:,:,1) = [1 0 1; 0 1 1; 0 0 0]; %! se(:,:,3) = [1 0 1; 0 1 1; 0 0 1]; %! out = zeros (size (in)); %! out(:,:,1,1) = [ %! 0 17 81 145 237 146 64 0 %! 205 128 64 0 0 37 83 147 %! 175 111 47 0 0 64 117 181 %! 0 64 128 209 173 109 45 0]; %! out(:,:,2,1) = [ %! 235 142 78 18 0 23 69 133 %! 0 35 103 163 215 128 46 0 %! 0 64 128 195 183 123 48 0 %! 153 93 43 0 14 78 146 215]; %! out(:,:,3,1) = [ %! 0 25 89 153 229 142 64 0 %! 201 128 64 0 0 41 91 155 %! 167 103 57 0 0 64 125 189 %! 0 64 146 217 165 101 37 0]; %! out(:,:,4,1) = [ %! 227 142 78 14 0 31 77 141 %! 0 43 107 171 211 128 46 0 %! 0 64 128 203 179 115 48 0 %! 149 99 35 0 18 82 146 223]; %! out(:,:,1,2) = [ %! 0 33 97 161 221 146 64 0 %! 189 125 61 0 0 53 99 163 %! 159 95 31 0 0 64 128 197 %! 0 64 128 225 157 93 29 0]; %! out(:,:,2,2) = [ %! 219 142 78 18 0 39 85 149 %! 0 51 119 179 199 128 46 0 %! 0 64 128 211 167 107 43 0 %! 137 77 27 0 14 78 146 231]; %! out(:,:,3,2) = [ %! 0 41 105 169 213 142 64 0 %! 185 121 64 0 0 57 107 171 %! 151 87 41 0 0 64 128 205 %! 0 64 146 233 149 85 21 0]; %! out(:,:,4,2) = [ %! 211 142 78 14 0 47 93 157 %! 0 59 123 187 195 128 46 0 %! 0 64 128 219 163 99 35 0 %! 133 83 19 0 18 82 146 239]; %!assert (imbothat (in, se), out); image-2.4.1/inst/PaxHeaders.6632/imadd.m0000644000000000000000000000013212561122761014471 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imadd.m0000644000175000017500000000715112561122761017320 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} imadd (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{out} =} imadd (@var{a}, @var{b}, @var{class}) ## Add image or constant to an image. ## ## If @var{a} and @var{b} are two images of same size and class, the images are ## added. Alternatively, if @var{b} is a floating-point scalar, its value is added ## to the image @var{a}. ## ## The class of @var{out} will be the same as @var{a} unless @var{a} is logical ## in which case @var{out} will be double. Alternatively, it can be ## specified with @var{class}. ## ## @emph{Note 1}: you can force output class to be logical by specifying ## @var{class}. This is incompatible with @sc{matlab} which will @emph{not} honour ## request to return a logical matrix. ## ## @emph{Note 2}: the values are truncated to the maximum value of the output ## class. ## @seealso{imabsdiff, imcomplement, imdivide, imlincomb, immultiply, imsubtract} ## @end deftypefn function img = imadd (img, val, out_class = class (img)) if (nargin < 2 || nargin > 3) print_usage; endif [img, val] = imarithmetics ("imadd", img, val, out_class); ## output class is the same as input img, unless img is logical in which case ## it should be double. Tested in matlab by Freysh at ##matlab: ## - if you imadd 2 logical matrix, it's not the union. You actually get values of 2 ## - the previous is true even if you specify "logical" as output class. It does ## not honors the request, output will be double class anyway, not even a ## warning will be issued (but we in octave are nicer and will) ## - you can specify smaller integer types for output than input and values ## are truncated. Input uint16 and request uint8, it will be respected ## this is matlab imcompatible on purpose. We are compatible and return double ## anyway, even if both input are logical (and wether this is correct is ## already debatable), but if the user forcedly requests output class to be ## logical, then he must be expecting it (matlab returns double anyway and ## ignores request). if (nargin > 2 && strcmpi (out_class, "logical")) img = img | val; else img = img + val; endif endfunction %!assert (imadd (uint8 ([23 250]), uint8 ([23 250])), uint8 ([46 255])); # default to first class and truncate %!assert (imadd (uint8 ([23 250]), 10), uint8 ([33 255])); # works adding a scalar %!assert (imadd (uint8 ([23 250]), uint8 ([23 250]), "uint16"), uint16 ([46 500])); # defining output class works %!assert (imadd (logical ([ 1 0]), logical ([ 1 1])), double ([ 2 1])); # return double for two logical images %!assert (imadd (logical ([ 1 0]), logical ([ 1 1]), "logical"), logical ([ 1 1])); # this is matlab incompatible on purpose %!fail ("imadd (uint8 ([23 250]), uint16 ([23 250]))"); # input need to have same class image-2.4.1/inst/PaxHeaders.6632/bwpropfilt.m0000644000000000000000000000013212561122761015603 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwpropfilt.m0000644000175000017500000001072012561122761020426 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} bwpropfilt (@var{bw}, @var{attrib}) ## @deftypefnx {Function File} {} bwpropfilt (@var{bw}, @var{I}, @var{attrib}) ## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{range}) ## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}) ## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @var{n}, @var{keep}) ## @deftypefnx {Function File} {} bwpropfilt (@dots{}, @dots{}, @var{conn}) ## Filter objects from image based on their properties. ## ## Returns a logical matrix with the objects of @var{bw} filtered based ## on the specific property @var{attrib}. The possible values for @var{attrib} ## are all the properties from @command{regionprops} that return a scalar ## value, e.g., Area, Extent, and MaxIntensity, but not PixelValues, basic, and ## BoundingBox. For certain attributes, such as MaxIntensity and ## WeightedCentroid, the grayscale image @var{I} must also be specified. ## ## To filter objects with a value on a specific interval, @var{range} must be ## a two-element vector with the interval @code{[@var{low} @var{high}]} ## (values are inclusive). ## ## Alternatively, a scalar @var{n} will select the objects with the N highest ## values. The @var{keep} option defaults to @qcode{"largest"} but can also ## be set to @qcode{"smallest"} to select the N objects with lower values. ## ## The last optional argument, @var{conn}, can be a connectivity matrix, or ## the number of elements connected to the center (see @command{conndef}). ## ## @seealso{bwareaopen, bwareafilt, bwlabel, bwlabeln, bwconncomp, regionprops} ## @end deftypefn function bwfiltered = bwpropfilt (bw, varargin) if (nargin < 3 || nargin > 6) print_usage (); endif if (ischar (varargin{1})) no_gray = true; attrib = varargin{1}; next_idx = 2; else no_gray = false; img = varargin{1}; attrib = varargin{2}; next_idx = 3; endif valid_nargin = @(x) numel (varargin) >= x; if (isscalar (varargin{next_idx})) ## Get the N largest or smallest in_range = false; n_keep = varargin{next_idx}; next_idx++; if (valid_nargin (next_idx) && ischar (varargin{next_idx})) keep = tolower (varargin{next_idx}); if (! any (strcmpi (keep, {"largest", "smallest"}))) error ("bwpropfilt: KEEP must be `largest' or `smallest'"); endif next_idx++; else keep = "largest"; endif elseif (numel (varargin{next_idx}) == 2) in_range = true; range = varargin{next_idx}; next_idx++; else error ("bwpropfilt: N and RANGE must have 1 or 2 elements respectively"); endif if (valid_nargin (next_idx)) conn = conndef (varargin{next_idx++}); if (valid_nargin (next_idx)) print_usage (); endif else ## Non-documented default conn = conndef (ndims (bw), "maximal"); endif ## FIXME: we need to call bwconncomp with our specific connectivity and ## then pass its struct to regionprops. That may be faster but is ## not yet implemented so we call labelmatrix labeled = labelmatrix (bwconncomp (bw, conn)); if (no_gray) stats = regionprops (labeled, {"PixelIdxList", attrib}); else stats = regionprops (labeled, img, {"PixelIdxList", attrib}); endif n_objs = numel (stats); idxs = {stats.PixelIdxList}; attribs = [stats.(attrib)]; if (in_range) filtered_idxs = idxs(attribs >= range(1) & attribs <= range(2)); else [~, sorted_idxs] = sort (attribs, "descend"); switch (keep) case "largest", filtered_idxs = idxs(sorted_idxs(1:min (n_keep, n_objs))); case "smallest", filtered_idxs = idxs(sorted_idxs(max (1, n_objs - n_keep +1):end)); endswitch endif bwfiltered = false (size (bw)); bwfiltered(cat (1, filtered_idxs{:})(:)) = true; endfunction image-2.4.1/inst/PaxHeaders.6632/edge.m0000644000000000000000000000013212561122761014317 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/edge.m0000644000175000017500000004646012561122761017154 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999 Andy Adler ## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{bw} =} edge (@var{im}, @var{method}) ## @deftypefnx{Function File} {@var{bw} =} edge (@var{im}, @var{method}, @var{arg1}, @var{arg2}) ## @deftypefnx{Function File} {[@var{bw}, @var{thresh}] =} edge (@dots{}) ## Detect edges in the given image using various methods. The first input @var{im} ## is the gray scale image in which edges are to be detected. The second argument ## controls which method is used for detecting the edges. The rest of the input ## arguments depend on the selected method. The first output @var{bw} is a ## @code{logical} image containing the edges. Most methods also returns an automatically ## computed threshold as the second output. ## ## The @var{method} input argument can any of the following strings (the default ## value is "Sobel") ## ## @table @asis ## @item "Sobel" ## Finds the edges in @var{im} using the Sobel approximation to the ## derivatives. Edge points are defined as points where the length of ## the gradient exceeds a threshold and is larger than it's neighbours ## in either the horizontal or vertical direction. The threshold is passed to ## the method in the third input argument @var{arg1}. If one is not given, a ## threshold is automatically computed as 4*@math{M}, where @math{M} is the mean ## of the gradient of the entire image. The optional 4th input argument controls ## the direction in which the gradient is approximated. It can be either ## "horizontal", "vertical", or "both" (default). ## ## @item "Prewitt" ## Finds the edges in @var{im} using the Prewitt approximation to the ## derivatives. This method works just like "Sobel" except a different approximation ## the gradient is used. ## ## @item "Roberts" ## Finds the edges in @var{im} using the Roberts approximation to the ## derivatives. Edge points are defined as points where the length of ## the gradient exceeds a threshold and is larger than it's neighbours ## in either the horizontal or vertical direction. The threshold is passed to ## the method in the third input argument @var{arg1}. If one is not given, a ## threshold is automatically computed as 6*@math{M}, where @math{M} is the mean ## of the gradient of the entire image. The optional 4th input argument can be ## either "thinning" (default) or "nothinning". If it is "thinning" a simple ## thinning procedure is applied to the edge image such that the edges are only ## one pixel wide. If @var{arg2} is "nothinning", this procedure is not applied. ## ## @item "Kirsch" ## Finds the edges in @var{im} using the Kirsch approximation to the ## derivatives. Edge points are defined as points where the length of ## the gradient exceeds a threshold and is larger than it's neighbours ## in either the horizontal or vertical direction. The threshold is passed to ## the method in the third input argument @var{arg1}. If one is not given, a ## threshold is automatically computed as @math{M}, where @math{M} is the mean ## of the gradient of the entire image. The optional 4th input argument controls ## the direction in which the gradient is approximated. It can be either ## "horizontal", "vertical", or "both" (default). ## ## @item "LoG" ## Finds edges in @var{im} by convolving with the Laplacian of Gaussian (LoG) ## filter, and finding zero crossings. Only zero crossings where the ## filter response is larger than an automatically computed threshold are retained. ## The threshold is passed to the method in the third input argument @var{arg1}. ## If one is not given, a threshold is automatically computed as 0.75*@math{M}, ## where @math{M} is the mean of absolute value of LoG filter response. The ## optional 4th input argument sets the spread of the LoG filter. By default ## this value is 2. ## ## @item "Zerocross" ## Finds edges in the image @var{im} by convolving it with the user-supplied filter ## @var{arg2} and finding zero crossings larger than the threshold @var{arg1}. If ## @var{arg1} is [] a threshold is computed as the mean value of the absolute ## filter response. ## ## @item "Canny" ## Finds edges using the Canny edge detector. The optional third input argument ## @var{arg1} sets the thresholds used in the hysteresis thresholding. If ## @var{arg1} is a two dimensional vector it's first element is used as the lower ## threshold, while the second element is used as the high threshold. If, on the ## other hand, @var{arg1} is a single scalar it is used as the high threshold, ## while the lower threshold is 0.4*@var{arg1}. The optional 4th input argument ## @var{arg2} is the spread of the low-pass Gaussian filter that is used to smooth ## the input image prior to estimating gradients. By default this scale parameter ## is 2. ## ## @item "Lindeberg" ## Finds edges using in @var{im} using the differential geometric single-scale edge ## detector given by Tony Lindeberg. The optional third input argument @var{arg1} ## is the scale (spread of Gaussian filter) at which the edges are computed. By ## default this 2. ## ## @item "Andy" ## A.Adler's idea (c) 1999. Somewhat based on the canny method. The steps are ## @enumerate ## @item ## Do a Sobel edge detection and to generate an image at ## a high and low threshold. ## @item ## Edge extend all edges in the LT image by several pixels, ## in the vertical, horizontal, and 45 degree directions. ## Combine these into edge extended (EE) image. ## @item ## Dilate the EE image by 1 step. ## @item ## Select all EE features that are connected to features in ## the HT image. ## @end enumerate ## ## The parameters for the method is given in a vector: ## @table @asis ## @item params(1)==0 or 4 or 8 ## Perform x connected dilatation (step 3). ## @item params(2) ## Dilatation coefficient (threshold) in step 3. ## @item params(3) ## Length of edge extention convolution (step 2). ## @item params(4) ## Coefficient of extention convolution in step 2. ## @end table ## defaults = [8, 1, 3, 3] ## ## @end table ## ## @seealso{fspecial, nonmax_supress} ## @end deftypefn function [bw, out_threshold, g45_out, g135_out] = edge (im, method, varargin) ## Get the image if (nargin == 0) error("edge: not enough input arguments"); endif if ( !isgray(im) ) error("edge: first input must be a gray-scale image"); endif ## Get the method if (nargin == 1) method = "Sobel"; endif if (!ischar(method)) error("edge: second argument must be a string"); endif method = lower(method); ## Perform the actual edge detection switch (method) ##################################### ## S O B E L ##################################### case "sobel" ## Get the direction argument direction = get_direction(varargin{:}); ## Create filters; h1 = fspecial("sobel"); # horizontal h3 = h1'; # vertical ## Compute edge strength switch(direction) case "horizontal" strength = abs( conv2(im, h1, "same") ); case "vertical" strength = abs( conv2(im, h3, "same") ); case "both" strength = sqrt( conv2(im, h1, "same").^2 + ... conv2(im, h3, "same").^2 ); endswitch ## Get threshold if (nargin > 2 && isscalar(varargin{1})) thresh = varargin{1}; else thresh = 2*mean(strength(:)); endif ## Perform thresholding and simple thinning strength(strength<=thresh) = 0; bw = simple_thinning(strength); ##################################### ## P R E W I T T ##################################### case "prewitt" ## Get the direction argument direction = get_direction(varargin{:}); ## Create filters; h1 = fspecial("prewitt"); # vertical h3 = h1'; # horizontal ## Compute edge strength switch(direction) case "vertical" strength = abs( conv2(im, h1, "same") ); case "horizontal" strength = abs( conv2(im, h3, "same") ); case "both" strength = sqrt( conv2(im, h1, "same").^2 + ... conv2(im, h3, "same").^2 ); endswitch ## Get threshold if (nargin > 2 && isscalar(varargin{1})) thresh = varargin{1}; else thresh = 4*mean(strength(:)); endif ## Perform thresholding and simple thinning strength(strength<=thresh) = 0; bw = simple_thinning(strength); ##################################### ## K I R S C H ##################################### case "kirsch" ## Get the direction argument direction = get_direction(varargin{:}); ## Create filters; h1 = fspecial("kirsch"); # vertical h3 = h1'; # horizontal ## Compute edge strength switch(direction) case "vertical" strength = abs( conv2(im, h1, "same") ); case "horizontal" strength = abs( conv2(im, h3, "same") ); case "both" strength = sqrt( conv2(im, h1, "same").^2 + ... conv2(im, h3, "same").^2 ); endswitch ## Get threshold if nargin > 2 && isscalar(varargin{1}) thresh = varargin{1}; else thresh = mean(strength(:)); endif ## Perform thresholding and simple thinning strength(strength<=thresh) = 0; bw = simple_thinning(strength); ##################################### ## R O B E R T S ##################################### case "roberts" ## Get the thinning argument (option) if (nargin == 4) option = varargin{2}; if (!ischar(option)) error("edge: 'option' must be a string"); endif option = lower(option); if (!any(strcmp(option, {"thinning", "nothinning"}))) error("edge: 'option' must be either 'thinning', or 'nothinning'"); endif else option = "thinning"; endif ## Create filters; h1 = [1 0; 0 -1]; h2 = [0 1; -1 0]; ## Compute edge strength g45 = conv2(im, h1, "same"); g135 = conv2(im, h2, "same"); strength = abs( g45 ) + abs( g135 ); ## Get threshold if (nargin > 2 && isscalar(varargin{1})) thresh = varargin{1}; else thresh = 6*mean(strength(:)); endif ## Perform thresholding and simple thinning strength(strength<=thresh) = 0; if (strcmp(option, "thinning")) bw = simple_thinning(strength); else bw = (strength > 0); endif ## Check if g45 and g135 should be returned if (nargout == 4) g45_out = g45; g135_out = g135; endif ##################################### ## L A P L A C I A N O F G A U S S I A N ##################################### case "log" ## Get sigma if (nargin == 4 && isscalar(varargin{2})) sigma = varargin{2}; else sigma = 2; endif ## Create the filter s = ceil(3*sigma); %[x y] = meshgrid(-s:s); %f = (x.^2 + y.^2 - sigma^2) .* exp(-(x.^2 + y.^2)/(2*sigma^2)); %f = f/sum(f(:)); f = fspecial("log", 2*s+1, sigma); ## Perform convolution with the filter f g = conv2(im, f, "same"); ## Get threshold if (nargin > 2 && isscalar(varargin{1})) thresh = varargin{1}; else thresh = 0.75*mean(abs(g(:))); endif ## Find zero crossings zc = zerocrossings(g); bw = (abs(g) >= thresh) & zc; ##################################### ## Z E R O C R O S S I N G ##################################### case "zerocross" ## Get the filter if (nargin == 4 && isnumeric (varargin{2})) f = varargin{2}; else error("edge: a filter must be given as the fourth argument when 'zerocross' is used"); endif ## Perform convolution with the filter f g = conv2(im, f, "same"); ## Get threshold if (nargin > 2 && isscalar(varargin{1})) thresh = varargin{1}; else thresh = mean(abs(g(:))); endif ## Find zero crossings zc = zerocrossings(g); bw = (abs(g) >= thresh) & zc; ##################################### ## C A N N Y ##################################### case "canny" ## Get sigma if (nargin == 4 && isscalar(varargin{2})) sigma = varargin{2}; else sigma = 2; endif ## Change scale J = imsmooth(double(im), "Gaussian", sigma); ## Canny enhancer p = [1 0 -1]/2; Jx = conv2(J, p, "same"); Jy = conv2(J, p', "same"); Es = sqrt( Jx.^2 + Jy.^2 ); Eo = pi - mod (atan2 (Jy, Jx) - pi, pi); ## Get thresholds if (nargin > 2 && isscalar(varargin{1})) thresh = [0.4*varargin{1}, varargin{1}]; elseif (nargin > 2 && isnumeric (varargin{1}) && numel (varargin{1}) == 2) thresh = varargin{1}(:); else tmp = mean(abs(Es(:))); thresh = [0.4*tmp, tmp]; endif bw = nonmax_supress(Es, Eo, thresh(1), thresh(2)); ##################################### ## L I N D E B E R G ##################################### case "lindeberg" ## In case the user asks for more then 1 output argument ## we define thresh to be -1. thresh = -1; ## Get sigma if (nargin > 2 && isscalar(varargin{1})) sigma = varargin{1}; else sigma = 2; endif ## Filters for computing the derivatives Px = [-1 0 1; -1 0 1; -1 0 1]; Py = [1 1 1; 0 0 0; -1 -1 -1]; Pxx = conv2(Px, Px, "full"); Pyy = conv2(Py, Py, "full"); Pxy = conv2(Px, Py, "full"); Pxxx = conv2(Pxx, Px, "full"); Pyyy = conv2(Pyy, Py, "full"); Pxxy = conv2(Pxx, Py, "full"); Pxyy = conv2(Pyy, Px, "full"); ## Change scale L = imsmooth(double(im), "Gaussian", sigma); ## Compute derivatives Lx = conv2(L, Px, "same"); Ly = conv2(L, Py, "same"); Lxx = conv2(L, Pxx, "same"); Lyy = conv2(L, Pyy, "same"); Lxy = conv2(L, Pxy, "same"); Lxxx = conv2(L, Pxxx, "same"); Lyyy = conv2(L, Pyyy, "same"); Lxxy = conv2(L, Pxxy, "same"); Lxyy = conv2(L, Pxyy, "same"); ## Compute directional derivatives Lvv = Lx.^2.*Lxx + 2.*Lx.*Ly.*Lxy + Ly.^2.*Lyy; Lvvv = Lx.^3.*Lxxx + 3.*Lx.^2.*Ly.*Lxxy ... + 3.*Lx.*Ly.^2.*Lxyy + 3.*Ly.^3.*Lyyy; ## Perform edge detection bw = zerocrossings(Lvv) & Lvvv < 0; ##################################### ## A N D Y ##################################### case "andy" [bw, out_threshold] = andy (im, method, varargin{:}); otherwise error("edge: unsupported edge detector: %s", method); endswitch if (nargout > 1) out_threshold = thresh; endif endfunction ## An auxiliary function that parses the 'direction' argument from 'varargin' function direction = get_direction(varargin) if (nargin >= 2) direction = varargin{2}; if (!ischar(direction)) error("edge: direction must be a string"); endif direction = lower(direction); if (!any(strcmp(direction, {"horizontal", "vertical", "both"}))) error("edge :direction must be either 'horizontal', 'vertical', or 'both'"); endif else direction = "both"; endif endfunction ## An auxiliary function that performs a very simple thinning. ## Strength is an image containing the edge strength. ## bw contains a 1 in (r,c) if ## 1) strength(r,c) is greater than both neighbours in the ## vertical direction, OR ## 2) strength(r,c) is greater than both neighbours in the ## horizontal direction. ## Note the use of OR. function bw = simple_thinning(strength) [r c] = size(strength); x = ( strength > [ zeros(r,1) strength(:,1:end-1) ] & ... strength > [ strength(:,2:end) zeros(r,1) ] ); y = ( strength > [ zeros(1,c); strength(1:end-1,:) ] & ... strength > [ strength(2:end,:); zeros(1,c) ] ); bw = x | y; endfunction ## Auxiliary function. Finds the zero crossings of the ## 2-dimensional function f. (By Etienne Grossmann) function z = zerocrossings(f) z0 = f<0; ## Negative [R,C] = size(f); z = zeros(R,C); z(1:R-1,:) |= z0(2:R,:); ## Grow z(2:R,:) |= z0(1:R-1,:); z(:,1:C-1) |= z0(:,2:C); z(:,2:C) |= z0(:,1:C-1); z &= !z0; ## "Positive zero-crossings"? endfunction ## The 'andy' edge detector that was present in older versions of 'edge'. ## The function body has simply been copied from the old implementation. ## -- Søren Hauberg, march 11th, 2008 function [imout, thresh] = andy(im, method, thresh, param2) [n,m]= size(im); xx= 2:m-1; yy= 2:n-1; filt= [1 2 1;0 0 0; -1 -2 -1]/8; tv= 2; imo= conv2(im, rot90(filt), 'same').^2 + conv2(im, filt, 'same').^2; if nargin<3 || thresh==[]; thresh= sqrt( tv* mean(mean( imo(yy,xx) )) ); end # sum( imo(:)>thresh ) / prod(size(imo)) dilate= [1 1 1;1 1 1;1 1 1]; tt= 1; sz=3; dt=3; if nargin>=4 # 0 or 4 or 8 connected dilation if length(param2) > 0 if param2(1)==4 ; dilate= [0 1 0;1 1 1;0 1 0]; elseif param2(1)==0 ; dilate= 1; end end # dilation threshold if length(param2) > 2; tt= param2(2); end # edge extention length if length(param2) > 2; sz= param2(3); end # edge extention threshold if length(param2) > 3; dt= param2(4); end end fobliq= [0 0 0 0 1;0 0 0 .5 .5;0 0 0 1 0;0 0 .5 .5 0;0 0 1 0 0; 0 .5 .5 0 0;0 1 0 0 0;.5 .5 0 0 0;1 0 0 0 0]; fobliq= fobliq( 5-sz:5+sz, 3-ceil(sz/2):3+ceil(sz/2) ); xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; imht= ( imo >= thresh^2 * 2); # high threshold image imht(yy,xx)= imht(yy,xx) & ( xpeak | ypeak ); imht([1,n],:)=0; imht(:,[1,m])=0; % imlt= ( imo >= thresh^2 / 2); # low threshold image imlt= ( imo >= thresh^2 / 1); # low threshold image imlt(yy,xx)= imlt(yy,xx) & ( xpeak | ypeak ); imlt([1,n],:)=0; imlt(:,[1,m])=0; # now we edge extend the low thresh image in 4 directions imee= ( conv2( imlt, ones(2*sz+1,1) , 'same') > tt ) | ... ( conv2( imlt, ones(1,2*sz+1) , 'same') > tt ) | ... ( conv2( imlt, eye(2*sz+1) , 'same') > tt ) | ... ( conv2( imlt, rot90(eye(2*sz+1)), 'same') > tt ) | ... ( conv2( imlt, fobliq , 'same') > tt ) | ... ( conv2( imlt, fobliq' , 'same') > tt ) | ... ( conv2( imlt, rot90(fobliq) , 'same') > tt ) | ... ( conv2( imlt, flipud(fobliq) , 'same') > tt ); # imee(yy,xx)= conv2(imee(yy,xx),ones(3),'same') & ( xpeak | ypeak ); imee= conv2(imee,dilate,'same') > dt; # % ff= find( imht==1 ); % imout = bwselect( imee, rem(ff-1, n)+1, ceil(ff/n), 8); imout = imee; endfunction image-2.4.1/inst/PaxHeaders.6632/bwselect.m0000644000000000000000000000013212561122761015223 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwselect.m0000644000175000017500000000264212561122761020052 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999 Andy Adler ## ## 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 3 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{imout}, @var{idx}] =} bwselect(@var{im}, @var{cols}, @var{rows}, @var{connect}) ## Select connected regions in a binary image. ## ## @table @code ## @item @var{im} ## binary input image ## @item [@var{cols}, @var{rows}] ## vectors of starting points (x,y) ## @item @var{connect} ## connectedness 4 or 8. default is 8 ## @item @var{imout} ## the image of all objects in image im that overlap ## pixels in (cols,rows) ## @item @var{idx} ## index of pixels in imout ## @end table ## @end deftypefn function [imout, idx] = bwselect( im, cols, rows, connect ) if nargin<4 connect= 8; end [jnk,idx]= bwfill( ~im, cols,rows, connect ); imout= zeros( size(jnk) ); imout( idx ) = 1; image-2.4.1/inst/PaxHeaders.6632/imregionalmin.m0000644000000000000000000000013212561122761016245 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imregionalmin.m0000644000175000017500000000743012561122761021074 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imregionalmin (@var{img}) ## @deftypefnx {Function File} {} imregionalmin (@var{img}, @var{conn}) ## Compute regional minima. ## ## Returns a logical matrix, same size as the input @var{img}, with the ## regional minima. ## ## The optional argument @var{conn}, defines the connectivity. It can ## be a scalar value or a boolean matrix (see @code{conndef} for details). ## Defaults to @code{conndef (ndims (@var{img}), "maximal")} ## ## Regional minima should not be mistaken with local minima. Local minima ## are pixels whose value is less or equal to all of its neighbors. ## A regional minima is the connected component of pixels whose values are ## all less than the neighborhood of the minima (the connected component, ## not its individual pixels). ## All pixels belonging to a regional minima are local minima, but the ## inverse is not true. ## ## @seealso{imreconstruct, imregionalmax} ## @end deftypefn function bw = imregionalmin (img, conn) if (nargin < 1 || nargin > 2) print_usage (); endif if (nargin < 2) conn = conndef (ndims (img), "maximal"); else conn = conndef (conn); endif if (isfloat (img)) img = - img; else img = imcomplement (img); endif if (islogical (img)) bw = img; else ## we could probably still make this more efficient recon = imreconstruct (img, img + 1, conn); bw = (recon == img); endif endfunction %!test %! a = [ %! 7 3 9 3 10 3 %! 4 2 3 10 1 3 %! 1 4 6 9 4 10 %! 8 7 9 3 4 8 %! 5 9 3 3 8 9 %! 3 6 9 4 1 10]; %! %! a4 = logical ([ %! 0 0 0 1 0 0 %! 0 1 0 0 1 0 %! 1 0 0 0 0 0 %! 0 0 0 1 0 0 %! 0 0 1 1 0 0 %! 1 0 0 0 1 0]); %! assert (imregionalmin (a, 4), a4) %! assert (imregionalmin (uint8 (a), 4), a4) %! assert (imregionalmin (int8 (a), 4), a4) %! %! a8 = logical ([ %! 0 0 0 0 0 0 %! 0 0 0 0 1 0 %! 1 0 0 0 0 0 %! 0 0 0 0 0 0 %! 0 0 0 0 0 0 %! 1 0 0 0 1 0]); %! assert (imregionalmin (a), a8) %! assert (imregionalmin (a, 8), a8) %! assert (imregionalmin (uint8 (a), 8), a8) %! assert (imregionalmin (int8 (a), 8), a8) %!test %! a = [ %! 4 8 5 -1 8 7 %! -1 4 0 7 1 1 %! 6 1 2 6 7 0 %! 6 1 5 -2 5 9 %! 1 4 -1 0 0 2 %! 4 6 1 0 7 1]; %! %! a4 = logical ([ %! 0 0 0 1 0 0 %! 1 0 1 0 0 0 %! 0 1 0 0 0 1 %! 0 1 0 1 0 0 %! 1 0 1 0 0 0 %! 0 0 0 0 0 1]); %! assert (imregionalmin (a, 4), a4) %! assert (imregionalmin (int8 (a), 4), a4) %! %! a8 = logical ([ %! 0 0 0 1 0 0 %! 1 0 0 0 0 0 %! 0 0 0 0 0 1 %! 0 0 0 1 0 0 %! 0 0 0 0 0 0 %! 0 0 0 0 0 0]); %! assert (imregionalmin (a), a8) %! assert (imregionalmin (a, 8), a8) %! assert (imregionalmin (int8 (a), 8), a8) image-2.4.1/inst/PaxHeaders.6632/im2int16.m0000644000000000000000000000013212561122761014764 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2int16.m0000644000175000017500000000426512561122761017616 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012-2014 Carnë Draug ## ## 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 3 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} {} im2int16 (@var{img}) ## Convert image to int16. ## ## The conversion of @var{img} to a 16-bit signed integer, is dependent ## on the type of input image. The following input classes are supported: ## ## @table @samp ## @item uint8 or uint16 ## Values are rescaled to the range of the int16 class [-32768 32767]. ## ## @item logical ## True and false values are assigned a value of 32767 and -32768 respectively. ## ## @item double or single ## Values are truncated to the interval [0 1] and then rescaled to the range ## of values of the int16 class [-32768 32767]. ## ## @item int16 ## Returns the same image. ## ## @end table ## ## @seealso{im2bw, imcast, im2uint8, im2double, im2single, im2uint16} ## @end deftypefn function imout = im2int16 (img) if (nargin != 1) print_usage (); endif imout = imcast (img, "int16"); endfunction %!assert (im2int16 (int16 ([-2 2 3])), int16 ([-2 2 3])); %!assert (im2int16 (uint16 ([0 65535])), int16 ([-32768 32767])); %!assert (im2int16 ([false true]), int16 ([-32768 32767])); %!assert (im2int16 ([true false]), int16 ([32767 -32768])); %!assert (im2int16 (uint8 ([0 127 128 255])), int16 ([-32768 -129 128 32767])); %!assert (im2int16 ([0 1.4/65535 1.5/65535 2/65535 1]), int16 ([-32768 -32767 -32766 -32766 32767])); %!assert (im2int16 ([0 0.5 1]), int16 ([-32768 0 32767])); %!assert (im2int16 ([-1 0 1 2]), int16 ([-32768 -32768 32767 32767])); %!error im2int16 ([1 2], "indexed"); image-2.4.1/inst/PaxHeaders.6632/grayslice.m0000644000000000000000000000013212561122761015375 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/grayslice.m0000644000175000017500000001002212561122761020213 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} grayslice (@var{I}) ## @deftypefnx {Function File} {} grayslice (@var{I}, @var{n}) ## @deftypefnx {Function File} {} grayslice (@var{I}, @var{v}) ## Create indexed image from intensity image using multilevel thresholding. ## ## The intensity image @var{I} will be split into multiple threshold levels. ## For regularly spaced intervals, the number of levels can be specified as the ## numeric scalar @var{n} (defaults to 10), which will use the intervals: ## ## @tex ## \def\frac#1#2{{\begingroup#1\endgroup\over#2}} ## $$ \frac{1}{n}, \frac{2}{n}, \dots{}, \frac{n - 1}{n} $$ ## @end tex ## @ifnottex ## @verbatim ## 1 2 n-1 ## -, -, ..., --- ## n n n ## @end verbatim ## @end ifnottex ## ## For irregularly spaced intervals, the numeric vector @var{v} can be ## specified instead. The values in @var{v} must be in the range [0 1] ## independently of the class of @var{I}. These will be adjusted by ## @code{grayslice} according to the image. ## ## The output image will be of class uint8 if the number of levels is ## less than 256, otherwise it will be double. ## ## @seealso{im2bw, gray2ind} ## @end deftypefn function sliced = grayslice (I, n = 10) if (nargin < 1 || nargin > 2) print_usage (); endif if (isscalar (n) && isnumeric (n) && (fix (n) == n)) v = [1:(n-1)] / n; n = n-1; elseif (isvector (n)) ## Do NOT check if v is in the [0 1] interval v = n(:); n = numel (v); else error ("grayslice: V or N must be numeric vector or scalar respectively"); endif v = imcast (v, class (I)); ## Broadcasting has a much higher memory usage but performs a lot faster ## than a for loop. See cset a67048847848 for a more memory friendly ## version (performs ~5x times slower but the memory footprint is numel(v) ## times smaller for uint8 images) sliced_tmp = reshape (sum (v(:) < vec (I, 2)), size (I)); if (n <= 256) sliced_tmp = uint8 (sliced_tmp); else ## remember that indexed images of floating point class have indices base 1 sliced_tmp++; endif if (nargout < 1) imshow (sliced_tmp, jet (n)); else sliced = sliced_tmp; endif endfunction %!function gs = test_grayslice_vector (I, v) %! gs = zeros (size (I)); %! for idx = 1:numel (v) %! gs(I >= v(idx)) = idx; %! endfor %!endfunction %!function gs = test_grayslice_scalar (I, n) %! v = (1:(n-1)) / n; %! gs = test_grayslice_vector (I, v); %!endfunction %!shared I2d, I3d, I5d, double_corner %! I2d = rand (10, 10); %! I3d = rand (10, 10, 3); %! I5d = rand (10, 10, 4, 3, 5); %! %! double_corner = I2d; %! double_corner(I2d > 0.1 & I2d < 0.3) = -0.2; %! double_corner(I2d > 0.6 & I2d < 0.7) = 1.3; %!assert (grayslice (I2d), grayslice (I2d, 10)) %!assert (grayslice (I2d, 10), uint8 (test_grayslice_scalar (I2d, 10))) %!assert (grayslice (I2d, [0.3 0.5 0.7]), %! uint8 (test_grayslice_vector (I2d, [0.3 0.5 0.7]))) %!assert (grayslice (I3d, 10), uint8 (test_grayslice_scalar (I3d, 10))) %!assert (grayslice (I5d, 300), test_grayslice_scalar (I5d, 300)+1) %!assert (grayslice (I3d, [0.3 0.5 0.7]), %! uint8 (test_grayslice_vector (I3d, [0.3 0.5 0.7]))) ### FIXME investigate why this sometimes fails %!assert (grayslice (im2uint8 (I2d), 3), uint8 (test_grayslice_scalar (I2d, 3))) %!assert (grayslice (im2uint16 (I2d), 3), uint8 (test_grayslice_scalar (I2d, 3))) image-2.4.1/inst/PaxHeaders.6632/entropyfilt.m0000644000000000000000000000013212561122761015772 xustar0030 mtime=1438950897.726252238 30 atime=1438950897.726252238 30 ctime=1438950899.342252237 image-2.4.1/inst/entropyfilt.m0000644000175000017500000000672112561122761020623 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{E} =} entropyfilt (@var{im}) ## @deftypefnx{Function File} {@var{E} =} entropyfilt (@var{im}, @var{domain}) ## @deftypefnx{Function File} {@var{E} =} entropyfilt (@var{im}, @var{domain}, @var{padding}, @dots{}) ## Computes the local entropy in a neighbourhood around each pixel in an image. ## ## The entropy of the elements of the neighbourhood is computed as ## ## @example ## @var{E} = -sum (@var{P} .* log2 (@var{P}) ## @end example ## ## where @var{P} is the distribution of the elements of @var{im}. The distribution ## is approximated using a histogram with @var{nbins} cells. If @var{im} is ## @code{logical} then two cells are used. For other classes 256 cells ## are used. ## ## When the entropy is computed, zero-valued cells of the histogram are ignored. ## ## The neighbourhood is defined by the @var{domain} binary mask. Elements of the ## mask with a non-zero value are considered part of the neighbourhood. By default ## a 9 by 9 matrix containing only non-zero values is used. ## ## At the border of the image, extrapolation is used. By default symmetric ## extrapolation is used, but any method supported by the @code{padarray} function ## can be used. Since extrapolation is used, one can expect a lower entropy near ## the image border. ## ## @seealso{entropy, paddarray, stdfilt} ## @end deftypefn function retval = entropyfilt (I, domain = true (9), padding = "symmetric", varargin) ## Check input if (nargin == 0) error ("entropyfilt: not enough input arguments"); endif if (! isnumeric (I)) error ("entropyfilt: I must be numeric"); endif if (! isnumeric (domain) && ! islogical (domain)) error ("entropyfilt: DOMAIN must be a logical matrix"); endif domain = logical (domain); ## Get number of histogram bins if (islogical (I)) nbins = 2; else nbins = 256; endif ## Convert to 8 or 16 bit integers if needed switch (class (I)) case {"double", "single", "int16", "int32", "int64", "uint16", "uint32", "uint64"} min_val = double (min (I (:))); max_val = double (max (I (:))); if (min_val == max_val) retval = zeros (size (I)); return; endif I = (double (I) - min_val)./(max_val - min_val); I = uint8 (255 * I); case {"logical", "int8", "uint8"} ## Do nothing otherwise error ("entropyfilt: cannot handle images of class '%s'", class (I)); endswitch ## Pad image pad = floor (size (domain)/2); I = padarray (I, pad, padding, varargin {:}); even = (round (size (domain)/2) == size (domain)/2); idx = cell (1, ndims (I)); for k = 1:ndims (I) idx {k} = (even (k)+1):size (I, k); endfor I = I (idx {:}); ## Perform filtering retval = __spatial_filtering__ (I, domain, "entropy", I, nbins); endfunction image-2.4.1/inst/PaxHeaders.6632/immse.m0000644000000000000000000000013212561122761014525 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/immse.m0000644000175000017500000000354412561122761017356 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} immse (@var{x}, @var{y}) ## Compute mean squared error. ## ## Calculates the mean squared error (MSE), between the arrays @var{x} and ## @var{y}. @var{x} and @var{y} must be of same size and class. ## ## The returned value will be a scalar double, unless @var{x} and @var{y} ## are of class single in which case, it returns a scalar single. ## ## @seealso{psnr} ## @end deftypefn function [mse] = immse (x, y) if (nargin != 2) print_usage (); elseif (! size_equal (x, y)) error ("immse: X and Y must be of same size"); elseif (! strcmp (class (x), class (y))) error ("immse: X and Y must have same class"); end if (isinteger (x)) x = double (x); y = double (y); endif err = x - y; mse = sumsq (err(:)) / numel (err); endfunction %!error immse (rand (10), rand (12)) %!error immse (uint8 ([0 1 2 3]), uint16 ([0 1 2 3])) %!error immse (double ([0 1 2 3]), single ([0 1 2 3])) %!assert (immse (magic (5), magic (5)), 0) %!assert (immse (single (magic (5)), single (magic (5))), single (0)) %!assert (immse (uint8 (magic (5)), uint8 (magic (5))), 0) image-2.4.1/inst/PaxHeaders.6632/mean2.m0000644000000000000000000000013212561122761014415 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/mean2.m0000644000175000017500000000225012561122761017237 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## ## 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 3 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{m}=} mean2 (@var{I}) ## Compute the mean value of the 2D image @var{I}. ## ## Note that @var{m} will be of class double, independently of the input class. ## This is equivalent to @code{mean (I(:))}. ## ## @seealso{mean, std2} ## @end deftypefn function m = mean2 (I) if (nargin != 1) print_usage(); elseif (!isimage (I) || ndims (I) != 2) error("mean2: argument must be a 2D image"); endif m = mean (I(:)); endfunction image-2.4.1/inst/PaxHeaders.6632/imabsdiff.m0000644000000000000000000000013212561122761015337 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imabsdiff.m0000644000175000017500000000605212561122761020165 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} imabsdiff (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{out} =} imabsdiff (@var{a}, @var{b}, @var{class}) ## Return absolute difference of image or constant to an image. ## ## If @var{a} and @var{b} are two images of same size and class, returns the absolute ## difference between @var{b} and @var{a}. ## ## The class of @var{out} will be the same as @var{a} unless @var{a} is logical ## in which case @var{out} will be double. Alternatively, the class can be ## specified with @var{class}. ## ## @emph{Note 1}: you can force output class to be logical by specifying ## @var{class}. This is incompatible with @sc{matlab} which will @emph{not} honour ## request to return a logical matrix. ## ## @emph{Note 2}: the values are truncated to the mininum value of the output ## class. ## @seealso{imadd, imcomplement, imdivide, imlincomb, immultiply, imsubtract} ## @end deftypefn function img = imabsdiff (img, val, out_class = class (img)) if (nargin < 2 || nargin > 3) print_usage; endif ## we want to make subtraction as double so this is it [img, val] = imarithmetics ("imabsdiff", img, val, "double"); converter = str2func (tolower (out_class)); if (nargin < 3 && strcmp (out_class, "logical")) ## it is using logical as default. Use double instead. We only have this ## problem on this function because we are are not actually giving out_class ## to imarithmetics converter = @double; else converter = str2func (tolower (out_class)); endif img = converter (abs (img - val)); endfunction %!assert (imabsdiff (uint8 ([23 250]), uint8 ([26 50])), uint8 ([ 3 200])); # default to first class and abs works %!assert (imabsdiff (uint8 ([23 250]), uint8 ([24 50]), "uint16"), uint16 ([ 1 200])); # defining output class works (not in matlab) %!assert (imabsdiff (uint8 ([23 250]), uint8 ([24 255]), "int8"), int8 ([ 1 5])); # signed integers kinda work (not in matlab) %!assert (imabsdiff (logical ([ 1 0]), logical ([ 1 1])), double ([ 0 1])); # return double for two logical images %!fail ("imabsdiff (uint8 ([23 250]), 30"); # fails subtracting a scalar %!fail ("imabsdiff (uint8 ([23 250]), uint16 ([23 250]))"); # input need to have same class image-2.4.1/inst/PaxHeaders.6632/applylut.m0000644000000000000000000000013212561122761015265 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/applylut.m0000644000175000017500000000420312561122761020107 0ustar00carandraugcarandraug00000000000000## 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 3 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{A} =} applylut (@var{BW}, @var{LUT}) ## Uses lookup tables to perform a neighbour operation on binary images. ## ## A = applylut(BW,LUT) returns the result of a neighbour operation ## using the lookup table @var{LUT} which can be created by makelut. ## ## It first computes a matrix with the index of each element in the ## lookup table. To do this, it convolves the original matrix with a ## matrix which assigns each of the neighbours a bit in the resulting ## index. Then @var{LUT} is accessed to compute the result. ## ## @seealso{makelut} ## @end deftypefn function A = applylut (BW, LUT) if (nargin != 2) print_usage; endif nq=log2(length(LUT)); n=sqrt(nq); if (floor(n)!=n) error ("applylut: LUT length is not as expected. Use makelut to create it."); endif w=reshape(2.^[nq-1:-1:0],n,n); A=LUT(filter2(w,BW)+1); endfunction %!demo %! lut = makelut (inline ('sum (x (:)) >= 3', 'x'), 3); %! S = applylut (eye (5), lut); %! disp (S) %! ## Everything should be 0 despite a diagonal which doesn't reach borders. ## 2-by-2 test %!assert (prod (applylut (eye (3), makelut (@(x) x(1) == 1, 2)) == eye (3)), [1 1 1]); ## 3-by-3 test %!assert (prod (applylut (eye (3), makelut (@(x) x(2,2) == 1, 3)) == eye (3)), [1 1 1]); %!assert (prod (applylut (eye (3), makelut (@(x) x(3,3) == 1, 3)) == %! applylut (eye (3), makelut (@(x) x(2,2) == 1, 2))), %! [1 1 1]); image-2.4.1/inst/PaxHeaders.6632/tforminv.m0000644000000000000000000000013212561122761015257 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/inst/tforminv.m0000644000175000017500000000415112561122761020103 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{UV}] =} tforminv (@var{T}, @var{XY}) ## @deftypefnx {Function File} {[@var{U}, @var{V}] =} tforminvfwd (@var{T}, @var{X}, @var{Y}) ## ## Given to dimensionnal coordinates from one space, returns two ## dimensionnal coordinates in the other space, as defined in ## the transform structure @var{T}. Input and output coordinates ## may be gigen either as a n-by-2 arrays, or as two n-by-1 vectors. ## @seealso{maketform, cp2tform, tformfwd} ## @end deftypefn ## Author: Pantxo Diribarne function varargout = tforminv (T, varargin) if (nargin > 3 || nargin < 2) print_usage (); elseif (! istform (T)) error ("tforminv: expect a transform structure as first argument") elseif (nargin == 2) XX = varargin{1}; if (columns (XX) != 2) error ("tforminv: expect n-by-2 array as second argument") endif else if (!isvector (varargin{1}) || !isvector (varargin{2})) error ("tforminv: expect vectors as coordinates") elseif (!all (size (varargin{1}) == size (varargin{2}))) error ("tforminv: expect two vectors the same size") elseif (columns (varargin{1}) != 1) error ("tforminv: expect column vectors") endif XX = [varargin{1} varargin{2}]; endif UU = T.inverse_fcn(XX, T); if (nargin == 3) varargout{1} = UU(:,1); varargout{2} = UU(:,2); else varargout{1} = UU; endif endfunction image-2.4.1/inst/PaxHeaders.6632/bwmorph.m0000644000000000000000000000013212561122761015071 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwmorph.m0000644000175000017500000010565112561122761017724 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2004 Josep Mones i Teixidor ## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} bwmorph (@var{bw}, @var{operation}) ## @deftypefnx {Function File} {} bwmorph (@var{bw}, @var{operation}, @var{n}) ## Perform morphological operation on binary image. ## ## For a binary image @var{bw}, performs the morphological @var{operation}, ## @var{n} times. All possible values of @var{operation} are listed on the ## table below. By default, @var{n} is 1. If @var{n} is @code{Inf}, the ## operation is continually performed until it no longer changes the image. ## ## In some operations, @var{bw} can be a binary matrix with any number of ## dimensions (see details on the table of operations). ## ## Note that the output will always be of class logical, independently of ## the class of @var{bw}. ## ## @table @samp ## @item bothat ## Performs a bottom hat operation, a closing operation (which is a ## dilation followed by an erosion) and finally subtracts the original ## image (see @code{imbothat}). @var{bw} can have any number of ## dimensions, and @code{strel ("hypercube", ndims (@var{bw}), 3)} is ## used as structuring element. ## ## @item bridge ## Performs a bridge operation. Sets a pixel to 1 if it has two nonzero ## neighbours which are not connected, so it "bridges" them. There are ## 119 3-by-3 patterns which trigger setting a pixel to 1. ## ## @item clean ## Performs an isolated pixel remove operation. Sets a pixel to 0 if all ## of its eight-connected neighbours are 0. @var{bw} can have any number ## of dimensions in which case connectivity is @code{(3^ndims(@var{bw})) -1}, ## i.e., all of the elements around it. ## ## @item close ## Performs closing operation, which is a dilation followed by erosion ## (see @code{imclose}). @var{bw} can have any number of dimensions, ## and @code{strel ("hypercube", ndims (@var{bw}), 3)} is used as ## structuring element. ## ## @item diag ## Performs a diagonal fill operation. Sets a pixel to 1 if that ## eliminates eight-connectivity of the background. ## ## @item dilate ## Performs a dilation operation (see @code{imdilate}). @var{bw} can have ## any number of dimensions, and ## @code{strel ("hypercube", ndims (@var{bw}), 3)} is used as ## structuring element. ## ## @item erode ## Performs an erosion operation (see @code{imerode}). @var{bw} can have ## any number of dimensions, and ## @code{strel ("hypercube", ndims (@var{bw}), 3)} is used as ## structuring element. ## ## @item fill ## Performs a interior fill operation. Sets a pixel to 1 if all ## four-connected pixels are 1. @var{bw} can have any number ## of dimensions in which case connectivity is @code{(2*ndims(@var{bw}))}. ## ## @item hbreak ## Performs a H-break operation. Breaks (sets to 0) pixels that are ## H-connected. ## ## @item majority ## Performs a majority black operation. Sets a pixel to 1 if the majority ## of the pixels (5 or more for a two dimensional image) in a 3-by-3 window ## is 1. If not set to 0. @var{bw} can have any number of dimensions in ## which case the window has dimensions @code{repmat (3, 1, ndims (@var{bw}))}. ## ## @item open ## Performs an opening operation, which is an erosion followed by a ## dilation (see @code{imopen}). @var{bw} can have any number of ## dimensions, and @code{strel ("hypercube", ndims (@var{bw}), 3)} ## is used as structuring element. ## ## @item remove ## Performs a iterior pixel remove operation. Sets a pixel to 0 if ## all of its four-connected neighbours are 1. @var{bw} can have any number ## of dimensions in which case connectivity is @code{(2*ndims(@var{bw}))}. ## ## @item shrink ## Performs a shrink operation. Sets pixels to 0 such that an object ## without holes erodes to a single pixel (set to 1) at or near its ## center of mass. An object with holes erodes to a connected ring lying ## midway between each hole and its nearest outer boundary. It preserves ## Euler number. ## ## @item skel ## Performs a skeletonization operation. It calculates a "median axis ## skeleton" so that points of this skeleton are at the same distance of ## its nearby borders. It preserver Euler number. Please read ## compatibility notes for more info. ## ## It uses the same algorithm as skel-pratt but this could change for ## compatibility in the future. ## ## @item skel-lantuejol ## Performs a skeletonization operation as described in Gonzalez & Woods ## "Digital Image Processing" pp 538-540. The text references Lantuejoul ## as author of this algorithm. ## ## It has the beauty of being a clean and simple approach, but skeletons ## are thicker than they need to and, in addition, not guaranteed to be ## connected. ## ## This algorithm is iterative. It will be applied the minimum value of ## @var{n} times or number of iterations specified in algorithm ## description. It's most useful to run this algorithm with @code{n=Inf}. ## ## @var{bw} can have any number of dimensions. ## ## @item skel-pratt ## Performs a skeletonization operation as described by William K. Pratt ## in "Digital Image Processing". ## ## @item spur ## Performs a remove spur operation. It sets pixel to 0 if it has only ## one eight-connected pixel in its neighbourhood. ## ## @item thicken ## Performs a thickening operation. This operation "thickens" objects ## avoiding their fusion. Its implemented as a thinning of the ## background. That is, thinning on negated image. Finally a diagonal ## fill operation is performed to avoid "eight-connecting" objects. ## ## @item thin ## Performs a thinning operation. When n=Inf, thinning sets pixels to 0 ## such that an object without holes is converted to a stroke ## equidistant from its nearest outer boundaries. If the object has ## holes it creates a ring midway between each hole and its near outer ## boundary. This differ from shrink in that shrink converts objects ## without holes to a single pixels and thin to a stroke. It preserves ## Euler number. ## ## @item tophat ## Performs a top hat operation, a opening operation (which is an ## erosion followed by a dilation) and finally subtracts the original ## image (see @code{imtophat}). @var{bw} can have any number of ## dimensions, and @code{strel ("hypercube", ndims (@var{bw}), 3)} ## is used as structuring element. ## @end table ## ## Some useful concepts to understand operators: ## ## Operations are defined on 3-by-3 blocks of data, where the pixel in ## the center of the block. Those pixels are numerated as follows: ## ## @multitable @columnfractions 0.05 0.05 0.05 ## @item X3 @tab X2 @tab X1 ## @item X4 @tab X @tab X0 ## @item X5 @tab X6 @tab X7 ## @end multitable ## ## @strong{Neighbourhood definitions used in operation descriptions:} ## @table @code ## @item 'four-connected' ## It refers to pixels which are connected horizontally or vertically to ## X: X1, X3, X5 and X7. ## @item 'eight-connected' ## It refers to all pixels which are connected to X: X0, X1, X2, X3, X4, ## X5, X6 and X7. ## @end table ## ## @strong{Compatibility notes:} ## @table @code ## @item 'skel' ## Algorithm used here is described in Pratt's book. When applying it to ## the "circles" image in MATLAB documentation, results are not the ## same. Perhaps MATLAB uses Blum's algorithm (for further info please ## read comments in code). ## @item 'skel-pratt' ## This option is not available in MATLAB. ## @item 'skel-lantuejoul' ## This option is not available in MATLAB. ## @item 'thicken' ## This implementation also thickens image borders. This can easily be ## avoided i necessary. MATLAB documentation doesn't state how it behaves. ## @end table ## ## References: ## W. K. Pratt, "Digital Image Processing" ## Gonzalez and Woods, "Digital Image Processing" ## ## @seealso{imdilate, imerode, imtophat, imbothat, makelut, applylut} ## @end deftypefn function bw2 = bwmorph (bw, operation, n = 1) if (nargin < 2 || nargin > 3) print_usage (); elseif (! isimage (bw)) error ("bwmorph: BW must be a binary image"); elseif (! ischar (operation)) error ("bwmorph: OPERATION must be a string"); elseif (! isnumeric (n) || ! isscalar (n)) error ("bwmorph: N must be a scalar number"); endif ## For undocumented Matlab compatibility if (n < 0) n = 1; endif ## Anything is valid, just convert it to logical bw = logical (bw); ## Some operations have no effect after being applied the first time. ## Those will set this to true and later set N to 1 (only exception is ## if N is set to 0 but even then we can't skip since we will display ## the image or return it depending on nargout) loop_once = false; post_morph = []; # post processing command (only if needed) switch (tolower (operation)) case "bothat" loop_once = true; se = strel ("hypercube", ndims (bw), 3); morph = @(x) imbothat (x, se); # case "branchpoints" # ## not implemented case "bridge" loop_once = true; ## see __bridge_lut_fun__ for rules ## lut = makelut ("__bridge_lut_fun__", 3); lut = logical ([0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); morph = @(x) applylut (x, lut); case "clean" ## Remove elements that are surrounded by false elements. So we ## create a hypercube kernel of side length 3 and values 1, and ## center value with the connectivity value. After convolution, ## only true elements with another one surrounding it, will have ## values above the connectivity (remember that the input matrix ## is binary). loop_once = true; kernel = ones (repmat (3, 1, ndims (bw))); connectivity = numel (kernel) -1; kernel(ceil (numel (kernel) /2)) = connectivity; # n-dimensional center morph = @(x) convn (x, kernel, "same") > connectivity; case "close" loop_once = true; se = strel ("hypercube", ndims (bw), 3); morph = @(x) imclose (x, se); case "diag" ## see __diagonal_fill_lut_fun__ for rules ## lut = makelut ("__diagonal_fill_lut_fun__", 3); lut = logical ([0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); morph = @(x) applylut (x, lut); case "dilate" se = strel ("hypercube", ndims (bw), 3); morph = @(x) imdilate (x, se); # case "endpoints" # ## not implemented case "erode" ## Matlab bwmorph acts different than their imerode. I'm unsure ## the cause of the bug but it seems to manifest on the image border ## only. It may be they have implemented this routines in both the ## im* functions, and in bwmorph. The rest of bwmorph that uses ## erosion (open, close, bothat, and tophat a least), suffer the ## same problem. We do not replicate the bug and use imerode. ## In 2013, Mathworks has confirmed this bug and will try to fix it ## for their next releases. So, do NOT fix this for "compatibility". se = strel ("hypercube", ndims (bw), 3); morph = @(x) imerode (x, se); case "fill" ## Fill elements that are surrounded by true elements (with ## connectivity 4 and its equivalent to N dimensions). ## So we create a hypercube kernel with the connected pixels as 1 ## and the center with the connectivity value. After convolution, ## only true elements, or elements surrounded by true elements ## will have a values >= connectivity. loop_once = true; kernel = conndef (ndims (bw), "minimal"); connectivity = nnz (kernel) -1; kernel(ceil (numel (kernel) /2)) = connectivity; morph = @(x) convn (x, kernel, "same") >= connectivity; case "hbreak" loop_once = true; ## lut = makelut (inline ("x(2,2)&&!(all(x==[1,1,1;0,1,0;1,1,1])||all(x==[1,0,1;1,1,1;1,0,1]))", "x"), 3); ## which is the same as lut = repmat ([false(16, 1); true(16, 1)], 16, 1); # identity lut([382 472]) = false; # the 2 exceptions morph = @(x) applylut (x, lut); case "majority" ## If the majority of the elements surrounding an element is true, ## it changes to true. We do this using convolution, with an ## hypercube kernel, any value of the convolution above the half ## number of elements becomes tru kernel = ones (repmat (3, 1, ndims (bw))); majority = numel (kernel) /2; morph = @(x) convn (x, kernel, "same") >= majority; case "open" loop_once = true; se = strel ("hypercube", ndims (bw), 3); morph = @(x) imopen (x, se); case "remove" ## Remove elements that are surrounded by true elements by 4 connectivity. ## We create a 4 connectivity kernel with -1 values, and a center with ## the number of -1 values. Only true elements can have positives values, ## with a maximum of 4 (or whatever is the connectivity value for that ## number of dimensions) from the kernel center, and -1 per each of the ## connectivity. If all are true, its value will go down to 0. loop_once = true; kernel = - conndef (ndims (bw), "minimal"); kernel(ceil (numel (kernel) /2)) = nnz (kernel) -1; morph = @(x) convn (x, kernel, "same") > 0; case "shrink" ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "S"); lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;1;0;1;1;1;1;0;1;0;0;1;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'S')", "m"), 3); lut2 = logical ([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;0;1;0;0;0;0;0;1;0; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;0;0;0;0;0;1;1;0;0;1;0; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;0;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); morph = @(x) x & applylut (applylut (x, lut1), lut2); case {"skel", "skel-pratt"} ## WARNING: Result doesn't look as MATLAB's sample. It has been ## WARNING: coded following Pratt's guidelines for what he calls ## WARNING: is a "reasonably close approximation". I couldn't find ## WARNING: any bug. ## WARNING: Perhaps MATLAB uses Blum's algorithm (which Pratt ## WARNING: refers to) in: H. Blum, "A Transformation for ## WARNING: Extracting New Descriptors of Shape", Symposium Models ## WARNING: for Perception of Speech and Visual Form, W. ## WARNING: Whaten-Dunn, Ed. MIT Press, Cambridge, MA, 1967. ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "K"); lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;1;1;1;1;0]); ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'K')", "m") ,3); lut2 = logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;1;0;0;0;1;0;1;1;0;0;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;1;0;0;1;1;0;0;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;0;1;0;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;1;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); morph = @(x) x & applylut (applylut (x, lut1), lut2); post_morph = @(x) bwmorph (x, "bridge"); case "skel-lantuejoul" ## This transform does not fit well in the same loop as the others, ## since each iteration requires values from the previous one. Because ## of this, we will set n to 0 in the end. However, we must take care ## to not touch the input image if n already is zero. if (n > 0) se = strel ("hypercube", ndims (bw), 3); bw_tmp = false (size (bw)); # skeleton result i = 1; while (i <= n) if (! any (bw(:))) ## If erosion from the previous result is 0-matrix then we are ## over because the top-hat transform below will also be a 0-matrix ## and we will be |= to a 0-matrix. break endif ebw = imerode (bw, se); ## the right hand side of |= is the top-hat transform. However, ## we are not using imtophat because we will also want the output ## of the erosion for the next iteration. This saves us calling ## imerode twice for the same thing. bw_tmp |= bw & ! imdilate (ebw, se); bw = ebw; i++; endwhile bw = bw_tmp; n = 0; # don't do anything else endif case "spur" ## lut = makelut(inline("xor(x(2,2),(sum((x&[0,1,0;1,0,1;0,1,0])(:))==0)&&(sum((x&[1,0,1;0,0,0;1,0,1])(:))==1)&&x(2,2))","x"),3); ## which is the same as lut = repmat ([false(16, 1); true(16,1)], 16, 1); # identity lut([18, 21, 81, 273]) = false; # 4 qualifying patterns morph = @(x) applylut (x, lut); case "thicken" ## This implementation also "thickens" the border. To avoid this, ## a simple solution could be to add a border of 1 to the reversed ## image. bw = bwmorph (! bw, "thin", n); loop_once = true; morph = @(x) bwmorph (x, "diag"); case "thin" ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "T"); lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;0;1;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'T')", "m"), 3); lut2 = logical ([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;0;1;0;1;1;0;0;0;0;1;0; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;0;0;0;0;1;1;0;0;1;0; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;1;0;0;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); morph = @(x) x & applylut (applylut (x, lut1), lut2); case "tophat" ## top hat filtering has no effect after being performed once ## (inherits this behaviour from closing and opening) loop_once = true; se = strel ("hypercube", ndims (bw), 3); morph = @(x) imtophat (x, se); otherwise error ("bwmorph: unknown OPERATION '%s' requested", operation); endswitch if (loop_once && n > 1) n = 1; endif bw2_tmp = bw; ## make sure bw2_tmp will exist later, even if n == 0 i = 1; while (i <= n) ## a for loop wouldn't work because n can be Inf bw2_tmp = morph (bw); if (isequal (bw, bw2_tmp)) ## if it doesn't change we don't need to process it further break endif bw = bw2_tmp; i++; endwhile ## process post processing commands if needed if (! isempty (post_morph) && n > 0) bw2_tmp = post_morph (bw2_tmp); endif if (nargout > 0) bw2 = bw2_tmp; else imshow (bw2_tmp); endif endfunction %!demo %! bwmorph (true (11), "shrink", Inf) %! # Should return 0 matrix with 1 pixel set to 1 at (6,6) ## Test skel-lantuejoul using Gozalez&Woods example (fig 8.39) %!test %! slBW = logical ([ 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 %! 0 0 1 1 0 0 0 %! 0 0 1 1 0 0 0 %! 0 0 1 1 1 0 0 %! 0 0 1 1 1 0 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 0 0 0 0]); %! %! rslBW = logical ([ 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 %! 0 0 1 1 0 0 0 %! 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 %! 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0]); %! assert (bwmorph (slBW, "skel-lantuejoul", 1), [rslBW(1:5,:); false(7, 7)]); %! assert (bwmorph (slBW, "skel-lantuejoul", 2), [rslBW(1:8,:); false(4, 7)]); %! assert (bwmorph (slBW, "skel-lantuejoul", 3), rslBW); %! assert (bwmorph (slBW, "skel-lantuejoul", Inf), rslBW); ## Test for bug #39293 %!test %! bw = [ %! 0 1 1 1 1 1 %! 0 1 1 1 1 1 %! 0 1 1 1 1 1 %! 1 1 1 1 1 1 %! 1 1 1 1 1 1 %! 1 1 1 1 1 1 %! 1 1 1 1 1 0 %! 1 1 1 1 1 0 %! 1 1 1 1 1 0]; %! %! final = logical ([ %! 0 1 0 0 0 1 %! 0 0 1 0 1 0 %! 0 0 0 1 0 0 %! 0 0 0 1 0 0 %! 0 0 1 1 0 0 %! 0 0 1 0 0 0 %! 0 0 1 0 0 0 %! 0 1 0 1 0 0 %! 1 0 0 0 1 0]); %! assert (bwmorph (bw, "skel", Inf), final) %! assert (bwmorph (bw, "skel", 3), final) %!error bwmorph ("not a matrix", "dilate") ## this makes sense to be an error but for Matlab compatibility, it is not %!assert (bwmorph (magic (10), "dilate"), imdilate (logical (magic (10)), ones (3))); %!test %! in = logical ([1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0 %! 1 1 1 0 1 0 1 1 1 1 0 1 0 1 0 0 0 0 0 0 %! 0 1 1 1 0 1 1 0 0 0 1 1 0 0 1 1 0 0 1 0 %! 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 %! 0 1 0 0 1 1 0 1 1 0 0 0 0 0 1 1 0 0 1 0 %! 0 0 1 1 1 1 1 0 0 1 0 1 1 1 0 0 1 0 0 1 %! 0 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 %! 1 0 1 1 1 0 1 1 0 1 0 0 1 1 1 0 0 1 0 0 %! 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 1 1 0 %! 1 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 1 1 0 0 %! 1 1 1 1 1 1 0 1 0 1 0 0 0 0 0 0 1 0 1 1 %! 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 %! 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0 0 1 0 1 1 %! 0 0 1 1 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 %! 0 0 1 0 0 0 0 0 0 1 0 0 1 1 1 1 0 0 0 0 %! 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 %! 0 1 0 0 0 1 1 0 1 1 0 0 1 1 1 0 1 1 1 1 %! 1 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 1 1 1 %! 0 0 1 1 0 1 1 1 1 0 0 0 0 1 1 0 1 1 1 1 %! 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1]); %! se = strel ("arbitrary", ones (3)); %! %! assert (bwmorph (in, "dilate"), imdilate (in, se)); %! assert (bwmorph (in, "dilate", 3), imdilate (imdilate (imdilate (in, se), se), se)); %! assert (bwmorph (in, "bothat"), imbothat (in, se)); %! assert (bwmorph (in, "tophat"), imtophat (in, se)); %! assert (bwmorph (in, "open"), imopen (in, se)); %! assert (bwmorph (in, "close"), imclose (in, se)); %!assert (bwmorph ([1 0 0; 1 0 1; 0 0 1], "bridge"), logical ([1 1 0; 1 1 1; 0 1 1])); %!assert (bwmorph ([0 0 0; 1 0 1; 0 0 1], "clean"), logical ([0 0 0; 0 0 1; 0 0 1])); %!assert (bwmorph ([0 0 0; 0 1 0; 0 0 0], "clean"), false (3)); %!assert (bwmorph ([0 1 0; 1 0 0; 0 0 0], "diag"), logical ([1 1 0; 1 1 0; 0 0 0])); %!test %! in = logical ([0 1 0 1 0 %! 1 1 1 0 1 %! 1 0 0 1 0 %! 1 1 1 0 1 %! 1 1 1 1 1]); %! out = logical ([0 1 0 1 0 %! 1 1 1 1 1 %! 1 0 0 1 0 %! 1 1 1 1 1 %! 1 1 1 1 1]); %! assert (bwmorph (in, "fill"), out); %!assert (bwmorph ([1 1 1; 0 1 0; 1 1 1], "hbreak"), logical ([1 1 1; 0 0 0; 1 1 1])); %!test %! in = logical ([0 1 0 0 0 %! 1 0 0 1 0 %! 1 0 1 0 0 %! 1 1 1 1 1 %! 1 1 1 1 1]); %! %! out = logical ([0 1 0 0 0 %! 1 0 0 1 0 %! 1 0 1 0 0 %! 1 1 0 1 1 %! 1 1 1 1 1]); %! assert (bwmorph (in, "remove"), out); %! %! out = logical ([0 1 0 0 0 %! 1 0 0 1 0 %! 1 0 1 0 0 %! 1 1 0 1 1 %! 1 1 1 1 1]); %! assert (bwmorph (in, "remove", Inf), out); %! %! ## tests for spur are failing (matlab incompatible) %! out = logical ([0 1 0 0 0 %! 1 0 0 0 0 %! 1 0 1 0 0 %! 1 1 1 1 1 %! 1 1 1 1 1]); %! assert (bwmorph (in, "spur"), out); %! %! out = logical ([0 1 0 0 0 %! 1 0 0 0 0 %! 1 0 0 0 0 %! 1 1 1 1 1 %! 1 1 1 1 1]); %! assert (bwmorph (in, "spur", Inf), out); ## bug #44396 %!test %! in = [ %! 0 0 0 1 0 %! 1 1 1 1 0 %! 0 0 1 1 0 %! 0 0 1 1 0 %! 0 0 0 1 0]; %! out = [ %! 0 0 0 0 0 %! 0 1 1 0 0 %! 0 0 0 1 0 %! 0 0 0 0 0 %! 0 0 0 0 0]; %! assert (bwmorph (in, "shrink"), logical (out)); image-2.4.1/inst/PaxHeaders.6632/im2uint8.m0000644000000000000000000000013212561122761015072 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2uint8.m0000644000175000017500000000616412561122761017724 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Søren Hauberg ## Copyright (C) 2012-2014 Carnë Draug ## ## 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 3 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} {} im2uint8 (@var{img}) ## @deftypefnx {Function File} {} im2uint8 (@var{img}, "indexed") ## Convert image to uint8. ## ## The conversion of @var{img} to an 8-bit unsigned integer, is dependent ## on the type of input image. The following input classes are supported ## for non-indexed images: ## ## @table @samp ## @item int16 or uint16 ## Values are rescaled to the range of the uint8 class [0 255]. ## ## @item logical ## True and false values are assigned a value of 0 and 255 respectively. ## ## @item double or single ## Values are truncated to the interval [0 1] and then rescaled to the range ## of values of the int16 class [0 255]. ## ## @item uint8 ## Returns the same image. ## ## @end table ## ## If the second argument is the string @qcode{"indexed"}, then values are ## cast to uint8, and a -1 offset is applied if input is ## a floating point class. Input checking is performed and an error will ## be throw is the range of values in uint8 is not enough for all the ## image indices. ## ## @seealso{im2bw, imcast, im2double, im2int16, im2single, im2uint16} ## @end deftypefn function imout = im2uint8 (img, varargin) if (nargin < 1 || nargin > 2) print_usage (); elseif (nargin == 2 && ! strcmpi (varargin{1}, "indexed")) error ("im2uint8: second input argument must be the string \"indexed\""); endif imout = imcast (img, "uint8", varargin{:}); endfunction %!assert (im2uint8 (uint8 ([1 2 3])), uint8 ([1 2 3])); %!assert (im2uint8 (uint16 ([0 65535])), uint8 ([0 255])); %!assert (im2uint8 ([0 0.5 1]), uint8 ([0 128 255])); %!assert (im2uint8 ([1 2]), uint8 ([255 255])); %!assert (im2uint8 ([-1 0 0.5 1 2]), uint8 ([0 0 128 255 255])); %!assert (im2uint8 (int16 ([-32768 0 32768])), uint8 ([0 128 255])); %!assert (im2uint8 ([false true]), uint8 ([0 255])); %!assert (im2uint8 ([true false]), uint8 ([255 0])); %!assert (im2uint8 ([1 256], "indexed"), uint8 ([0 255])); %!assert (im2uint8 ([3 25], "indexed"), uint8 ([2 24])); %!assert (im2uint8 (uint16 ([3 25]), "indexed"), uint8 ([3 25])); %!error im2uint8 ([0 1 2], "indexed"); %!error im2uint8 (int16 ([17 8]), "indexed"); %!error im2uint8 (int16 ([-7 8]), "indexed"); %!error im2uint8 ([false true], "indexed"); %!error im2uint8 (uint16 (256), "indexed"); %!error im2uint8 (257, "indexed"); image-2.4.1/inst/PaxHeaders.6632/ordfilt2.m0000644000000000000000000000013212561122761015140 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/ordfilt2.m0000644000175000017500000000304512561122761017765 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Teemu Ikonen ## ## 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 3 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} {} ordfilt2 (@var{A}, @var{nth}, @var{domain}) ## @deftypefnx {Function File} {} ordfilt2 (@var{A}, @var{nth}, @var{domain}, @var{S}) ## @deftypefnx {Function File} {} ordfilt2 (@dots{}, @var{padding}) ## Two dimensional ordered filtering. ## ## This function exists only for @sc{matlab} compatibility as is just a wrapper ## to the @code{ordfiltn} which performs the same function on N dimensions. See ## @code{ordfiltn} help text for usage explanation. ## ## @seealso{medfilt2, padarray, ordfiltn} ## @end deftypefn function A = ordfilt2 (A, nth, domain, varargin) if (nargin < 3) print_usage (); elseif (ndims (A) > 2 || ndims (domain) > 2 ) error ("ordfilt2: A and DOMAIN are limited to 2 dimensinos. Use `ordfiltn' for more") endif A = ordfiltn (A, nth, domain, varargin{:}); endfunction image-2.4.1/inst/PaxHeaders.6632/imnoise.m0000644000000000000000000000013212561122761015056 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imnoise.m0000644000175000017500000001233112561122761017701 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2004 Stefan van der Walt ## Copyright (C) 2012 Carlo de Falco ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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} {} imnoise (@var{A}, @var{type}) ## @deftypefnx {Function File} {} imnoise (@dots{}, @var{options}) ## Add noise to image. ## ## @end deftypefn ## @deftypefn {Function File} {} imnoise (@var{A}, "gaussian", @var{mean}, @var{variance}) ## Additive gaussian noise with @var{mean} and @var{variance} defaulting to 0 ## and 0.01. ## ## @end deftypefn ## @deftypefn {Function File} {} imnoise (@var{A}, "poisson") ## Creates poisson noise in the image using the intensity value of each pixel as ## mean. ## ## @end deftypefn ## @deftypefn {Function File} {} imnoise (@var{A}, "salt & pepper", @var{density}) ## Create "salt and pepper"/"lost pixels" in @var{density}*100 percent of the ## image. @var{density} defaults to 0.05. ## ## @end deftypefn ## @deftypefn {Function File} {} imnoise (@var{A}, "speckle", @var{variance}) ## Multiplicative gaussian noise with @var{B} = @var{A} + @var{A} * noise with ## mean 0 and @var{variance} defaulting to 0.04. ## ## @seealso{rand, randn, randp} ## @end deftypefn function A = imnoise (A, stype, a, b) ## we do not set defaults right at the start because they are different ## depending on the method used to generate noise if (nargin < 2 || nargin > 4) print_usage; elseif (! isimage (A)) error ("imnoise: first argument must be an image."); elseif (! ischar (stype)) error ("imnoise: second argument must be a string with name of noise type."); endif in_class = class (A); fix_class = false; # for cases when we need to use im2double switch (lower (stype)) case "poisson" switch (in_class) case ("double") A = randp (A * 1e12) / 1e12; case ("single") A = single (randp (A * 1e6) / 1e6); case {"uint8", "uint16"} A = cast (randp (A), in_class); otherwise A = imnoise (im2double (A), "poisson"); fix_class = true; endswitch case "gaussian" A = im2double (A); fix_class = true; if (nargin < 3), a = 0.00; endif if (nargin < 4), b = 0.01; endif A = A + (a + randn (size (A)) * sqrt (b)); ## Variance of Gaussian data with mean 0 is E[X^2] case {"salt & pepper", "salt and pepper"} if (nargin < 3), a = 0.05; endif noise = rand (size (A)); if (isfloat (A)) black = 0; white = 1; else black = intmin (in_class); white = intmax (in_class); endif A(noise <= a/2) = black; A(noise >= 1-a/2) = white; case "speckle" A = im2double (A); fix_class = true; if (nargin < 3), a = 0.04; endif A = A .* (1 + randn (size (A)) * sqrt (a)); otherwise error ("imnoise: unknown or unimplemented type of noise `%s'", stype); endswitch if (fix_class) A = imcast (A, in_class); elseif (isfloat (A)) ## this includes not even cases where the noise made it go outside of the ## [0 1] range, but also images that were already originally outside that ## range. This is by design and matlab compatibility. And we do this after ## fixing class because the imcast functions already take care of such ## adjustment A(A < 0) = cast (0, class (A)); A(A > 1) = cast (1, class (A)); endif endfunction %!assert(var(imnoise(ones(10)/2,'gaussian')(:)),0.01,0.005) # probabilistic %!assert(length(find(imnoise(ones(10)/2,'salt & pepper')~=0.5)),5,10) # probabilistic %!assert(var(imnoise(ones(10)/2,'speckle')(:)),0.01,0.005) # probabilistic %!test %! A = imnoise (.5 * ones (100), 'poisson'); %! assert (class (A), 'double') %!test %! A = imnoise (.5 * ones (100, 'single'), 'poisson'); %! assert (class (A), 'single') %!test %! A = imnoise (128 * ones (100, 'uint8'), 'poisson'); %! assert (class (A), 'uint8') %!test %! A = imnoise (256 * ones (100, 'uint16'), 'poisson'); %! assert (class (A), 'uint16') %!demo %! A = imnoise (2^7 * ones (100, 'uint8'), 'poisson'); %! subplot (2, 2, 1) %! imshow (A) %! title ('uint8 image with poisson noise') %! A = imnoise (2^15 * ones (100, 'uint16'), 'poisson'); %! subplot (2, 2, 2) %! imshow (A) %! title ('uint16 image with poisson noise') %! A = imnoise (.5 * ones (100), 'poisson'); %! subplot (2, 2, 3) %! imshow (A) %! title ('double image with poisson noise') %! A = imnoise (.5 * ones (100, 'single'), 'poisson'); %! subplot (2, 2, 4) %! imshow (A) %! title ('single image with poisson noise') image-2.4.1/inst/PaxHeaders.6632/im2single.m0000644000000000000000000000013212561122761015304 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2single.m0000644000175000017500000000552312561122761020134 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012-2014 Carnë Draug ## ## 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 3 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} {} im2single (@var{img}) ## @deftypefnx {Function File} {} im2single (@var{img}, "indexed") ## Convert image to single precision. ## ## The conversion of @var{img} to single precision, is dependent ## on the type of input image. The following input classes are supported: ## ## @table @samp ## @item uint8, uint16, and int16 ## The whole range of values from the class (see @code{getrangefromclass}) ## are scaled for the interval [0 1], e.g., if input image was uint8, ## intensity values of 0, 127, and 255, are converted to intensity of ## 0, 0.498, and 1. ## ## @item logical ## True and false values are assigned a value of 0 and 1 respectively. ## ## @item double ## Values are cast to double precision. ## ## @item single ## Returns the same image. ## ## @end table ## ## If the second argument is the string @qcode{"indexed"}, then values are ## cast to single precision, and a +1 offset is applied if input is ## an integer class. ## ## @seealso{im2bw, imcast, im2uint8, im2double, im2int16, im2uint16} ## @end deftypefn function imout = im2single (img, varargin) if (nargin < 1 || nargin > 2) print_usage (); elseif (nargin == 2 && ! strcmpi (varargin{1}, "indexed")) error ("im2single: second input argument must be the string \"indexed\""); endif imout = imcast (img, "single", varargin{:}); endfunction %!assert (im2single (single ([1 2 3])), single ([1 2 3])); %!assert (im2single ([1 2 3]), single ([1 2 3])); %!assert (im2single (uint8 ([0 127 128 255])), single ([0 127/255 128/255 1])); %!assert (im2single (uint16 ([0 127 128 65535])), single ([0 127/65535 128/65535 1])); %!assert (im2single (int16 ([-32768 -32767 -32766 32767])), single ([0 1/65535 2/65535 1])); %!assert (im2single (uint8 ([0 1 255]), "indexed"), single ([1 2 256])); %!assert (im2single (uint16 ([0 1 2557]), "indexed"), single ([1 2 2558])); %!assert (im2single ([3 25], "indexed"), single ([3 25])); %!error im2single ([0 1 2], "indexed"); %!error im2single (int16 ([17 8]), "indexed"); %!error im2single (int16 ([-7 8]), "indexed"); %!error im2single ([false true], "indexed"); image-2.4.1/inst/PaxHeaders.6632/checkerboard.m0000644000000000000000000000013212561122761016027 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/checkerboard.m0000644000175000017500000000415012561122761020652 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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{board} =} checkerboard () ## @deftypefnx {Function File} {@var{board} =} checkerboard (@var{side}) ## @deftypefnx {Function File} {@var{board} =} checkerboard (@var{side}, @var{size}) ## @deftypefnx {Function File} {@var{board} =} checkerboard (@var{side}, @var{M}, @var{N}) ## Create checkerboard. ## ## Each tile of the checkerboard is made of four squares @var{side} pixels wide. ## The created checkerboard itself will be @var{size}, or @var{M}x@var{N} tiles ## wide. Defaults to 4x4 tiles 10 pixels wide. ## ## @seealso{repmat} ## @end deftypefn function [board] = checkerboard (side = 10, nRows = 4, nCols = nRows) if (nargin > 3) print_usage (); endif check_checkerboard (side, "square side"); check_checkerboard (nRows, "number of rows"); check_checkerboard (nCols, "number of columns"); [xx, yy] = meshgrid (linspace (-1, 1, 2*side)); tile = (xx .* yy) < 0; board = double (repmat (tile, nRows, nCols)); board(:, (end/2+1):end) *= .7; # matlab compatible endfunction function check_checkerboard (in, name) ## isindex makes easy to check if it's a positive integer but also returns ## true for a logical matrix. Hence the use for islogical if (! isscalar (in) || ! isindex (in) || islogical (in)) error ("checkerboard: %s must be a positive integer.", name) endif endfunction image-2.4.1/inst/PaxHeaders.6632/imsmooth.m0000644000000000000000000000013212561122761015252 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imsmooth.m0000644000175000017500000004502612561122761020104 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Søren Hauberg ## ## 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 3 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{J} = imsmooth(@var{I}, @var{name}, @var{options}) ## Smooth the given image using several different algorithms. ## ## The first input argument @var{I} is the image to be smoothed. If it is an RGB ## image, each color plane is treated separately. ## The variable @var{name} must be a string that determines which algorithm will ## be used in the smoothing. It can be any of the following strings ## ## @table @asis ## @item "Gaussian" ## Isotropic Gaussian smoothing. This is the default. ## @item "Average" ## Smoothing using a rectangular averaging linear filter. ## @item "Disk" ## Smoothing using a circular averaging linear filter. ## @item "Median" ## Median filtering. ## @item "Bilateral" ## Gaussian bilateral filtering. ## @item "Perona & Malik" ## @itemx "Perona and Malik" ## @itemx "P&M" ## Smoothing using nonlinear isotropic diffusion as described by Perona and Malik. ## @item "Custom Gaussian" ## Gaussian smoothing with a spatially varying covariance matrix. ## @end table ## ## In all algorithms the computation is done in double precision floating point ## numbers, but the result has the same type as the input. Also, the size of the ## smoothed image is the same as the input image. ## ## @strong{Isotropic Gaussian smoothing} ## ## The image is convolved with a Gaussian filter with spread @var{sigma}. ## By default @var{sigma} is @math{0.5}, but this can be changed. If the third ## input argument is a scalar it is used as the filter spread. ## ## The image is extrapolated symmetrically before the convolution operation. ## ## @strong{Rectangular averaging linear filter} ## ## The image is convolved with @var{N} by @var{M} rectangular averaging filter. ## By default a 3 by 3 filter is used, but this can e changed. If the third ## input argument is a scalar @var{N} a @var{N} by @var{N} filter is used. If the third ## input argument is a two-vector @code{[@var{N}, @var{M}]} a @var{N} by @var{M} ## filter is used. ## ## The image is extrapolated symmetrically before the convolution operation. ## ## @strong{Circular averaging linear filter} ## ## The image is convolved with circular averaging filter. By default the filter ## has a radius of 5, but this can e changed. If the third input argument is a ## scalar @var{r} the radius will be @var{r}. ## ## The image is extrapolated symmetrically before the convolution operation. ## ## @strong{Median filtering} ## ## Each pixel is replaced with the median of the pixels in the local area. By ## default, this area is 3 by 3, but this can be changed. If the third input ## argument is a scalar @var{N} the area will be @var{N} by @var{N}, and if it's ## a two-vector [@var{N}, @var{M}] the area will be @var{N} by @var{M}. ## ## The image is extrapolated symmetrically before the filtering is performed. ## ## @strong{Gaussian bilateral filtering} ## ## The image is smoothed using Gaussian bilateral filtering as described by ## Tomasi and Manduchi [2]. The filtering result is computed as ## @example ## @var{J}(x0, y0) = k * SUM SUM @var{I}(x,y) * w(x, y, x0, y0, @var{I}(x0,y0), @var{I}(x,y)) ## x y ## @end example ## where @code{k} a normalisation variable, and ## @example ## w(x, y, x0, y0, @var{I}(x0,y0), @var{I}(x,y)) ## = exp(-0.5*d([x0,y0],[x,y])^2/@var{sigma_d}^2) ## * exp(-0.5*d(@var{I}(x0,y0),@var{I}(x,y))^2/@var{sigma_r}^2), ## @end example ## with @code{d} being the Euclidian distance function. The two parameters ## @var{sigma_d} and @var{sigma_r} control the amount of smoothing. @var{sigma_d} ## is the size of the spatial smoothing filter, while @var{sigma_r} is the size ## of the range filter. When @var{sigma_r} is large the filter behaves almost ## like the isotropic Gaussian filter with spread @var{sigma_d}, and when it is ## small edges are preserved better. By default @var{sigma_d} is 2, and @var{sigma_r} ## is @math{10/255} for floating points images (with integer images this is ## multiplied with the maximal possible value representable by the integer class). ## ## The image is extrapolated symmetrically before the filtering is performed. ## ## @strong{Perona and Malik} ## ## The image is smoothed using nonlinear isotropic diffusion as described by Perona and ## Malik [1]. The algorithm iteratively updates the image using ## ## @example ## I += lambda * (g(dN).*dN + g(dS).*dS + g(dE).*dE + g(dW).*dW) ## @end example ## ## @noindent ## where @code{dN} is the spatial derivative of the image in the North direction, ## and so forth. The function @var{g} determines the behaviour of the diffusion. ## If @math{g(x) = 1} this is standard isotropic diffusion. ## ## The above update equation is repeated @var{iter} times, which by default is 10 ## times. If the third input argument is a positive scalar, that number of updates ## will be performed. ## ## The update parameter @var{lambda} affects how much smoothing happens in each ## iteration. The algorithm can only be proved stable is @var{lambda} is between ## 0 and 0.25, and by default it is 0.25. If the fourth input argument is given ## this parameter can be changed. ## ## The function @var{g} in the update equation determines the type of the result. ## By default @code{@var{g}(@var{d}) = exp(-(@var{d}./@var{K}).^2)} where @var{K} = 25. ## This choice gives privileges to high-contrast edges over low-contrast ones. ## An alternative is to set @code{@var{g}(@var{d}) = 1./(1 + (@var{d}./@var{K}).^2)}, ## which gives privileges to wide regions over smaller ones. The choice of @var{g} ## can be controlled through the fifth input argument. If it is the string ## @code{"method1"}, the first mentioned function is used, and if it is @var{"method2"} ## the second one is used. The argument can also be a function handle, in which case ## the given function is used. It should be noted that for stability reasons, ## @var{g} should return values between 0 and 1. ## ## The following example shows how to set ## @code{@var{g}(@var{d}) = exp(-(@var{d}./@var{K}).^2)} where @var{K} = 50. ## The update will be repeated 25 times, with @var{lambda} = 0.25. ## ## @example ## @var{g} = @@(@var{d}) exp(-(@var{d}./50).^2); ## @var{J} = imsmooth(@var{I}, "p&m", 25, 0.25, @var{g}); ## @end example ## ## @strong{Custom Gaussian Smoothing} ## ## The image is smoothed using a Gaussian filter with a spatially varying covariance ## matrix. The third and fourth input arguments contain the Eigenvalues of the ## covariance matrix, while the fifth contains the rotation of the Gaussian. ## These arguments can be matrices of the same size as the input image, or scalars. ## In the last case the scalar is used in all pixels. If the rotation is not given ## it defaults to zero. ## ## The following example shows how to increase the size of an Gaussian ## filter, such that it is small near the upper right corner of the image, and ## large near the lower left corner. ## ## @example ## [@var{lambda1}, @var{lambda2}] = meshgrid (linspace (0, 25, columns (@var{I})), linspace (0, 25, rows (@var{I}))); ## @var{J} = imsmooth (@var{I}, "Custom Gaussian", @var{lambda1}, @var{lambda2}); ## @end example ## ## The implementation uses an elliptic filter, where only neighbouring pixels ## with a Mahalanobis' distance to the current pixel that is less than 3 are ## used to compute the response. The response is computed using double precision ## floating points, but the result is of the same class as the input image. ## ## @strong{References} ## ## [1] P. Perona and J. Malik, ## "Scale-space and edge detection using anisotropic diffusion", ## IEEE Transactions on Pattern Analysis and Machine Intelligence, ## 12(7):629-639, 1990. ## ## [2] C. Tomasi and R. Manduchi, ## "Bilateral Filtering for Gray and Color Images", ## Proceedings of the 1998 IEEE International Conference on Computer Vision, Bombay, India. ## ## @seealso{imfilter, fspecial} ## @end deftypefn ## TODO: Implement Joachim Weickert's anisotropic diffusion (it's soo cool) function J = imsmooth(I, name = "Gaussian", varargin) ## Check inputs if (nargin == 0) print_usage(); endif if (! isimage (I)) error("imsmooth: I must be an image"); endif [imrows, imcols, imchannels, tmp] = size(I); if ((imchannels != 1 && imchannels != 3) || tmp != 1) error("imsmooth: first input argument must be an image"); endif if (nargin == 2 && isscalar (name)) varargin {1} = name; name = "Gaussian"; endif if (!ischar(name)) error("imsmooth: second input must be a string"); endif len = length(varargin); ## Save information for later C = class(I); ## Take action depending on 'name' switch (lower(name)) ############################## ### Gaussian smoothing ### ############################## case "gaussian" ## Check input s = 0.5; if (len > 0) if (isscalar(varargin{1}) && varargin{1} > 0) s = varargin{1}; else error("imsmooth: third input argument must be a positive scalar when performing Gaussian smoothing"); endif endif ## Compute filter h = ceil(3*s); f = exp( (-(-h:h).^2)./(2*s^2) ); f /= sum(f); ## Pad image I = double (padarray (I, [h h], "symmetric")); ## Perform the filtering for i = imchannels:-1:1 J(:,:,i) = conv2(f, f, I(:,:,i), "valid"); endfor ############################ ### Square averaging ### ############################ case "average" ## Check input s = [3, 3]; if (len > 0) if (isscalar(varargin{1}) && varargin{1} > 0) s = [varargin{1}, varargin{1}]; elseif (isvector(varargin{1}) && length(varargin{1}) == 2 && all(varargin{1} > 0)) s = varargin{1}; else error("imsmooth: third input argument must be a positive scalar or two-vector when performing averaging"); endif endif ## Compute filter f2 = ones(1,s(1))/s(1); f1 = ones(1,s(2))/s(2); ## Pad image I = padarray (I, floor ( [s(1) s(2)] /2), "symmetric", "pre"); I = padarray (I, floor (([s(1) s(2)]-1)/2), "symmetric", "post"); I = double (I); ## Perform the filtering for i = imchannels:-1:1 J(:,:,i) = conv2 (f1, f2, I(:,:,i), "valid"); endfor ############################## ### Circular averaging ### ############################## case "disk" ## Check input r = 5; if (len > 0) if (isscalar(varargin{1}) && varargin{1} > 0) r = varargin{1}; else error("imsmooth: third input argument must be a positive scalar when performing averaging"); endif endif ## Compute filter f = fspecial("disk", r); ## Pad image i = double (padarray (I, [r r], "symmetric")); ## Perform the filtering for i = imchannels:-1:1 J(:,:,i) = conv2(I(:,:,i), f, "valid"); endfor ############################ ### Median Filtering ### ############################ case "median" ## Check input s = [3, 3]; if (len > 0) opt = varargin{1}; if (isscalar(opt) && opt > 0) s = [opt, opt]; elseif (isvector(opt) && numel(opt) == 2 && all(opt>0)) s = opt; else error("imsmooth: third input argument must be a positive scalar or two-vector"); endif s = round(s); # just in case the use supplies non-integers. endif ## Perform the filtering for i = imchannels:-1:1 J(:,:,i) = medfilt2(I(:,:,i), s, "symmetric"); endfor ############################### ### Bilateral Filtering ### ############################### case "bilateral" ## Check input if (len > 0 && !isempty(varargin{1})) if (isscalar(varargin{1}) && varargin{1} > 0) sigma_d = varargin{1}; else error("imsmooth: spread of closeness function must be a positive scalar"); endif else sigma_d = 2; endif if (len > 1 && !isempty(varargin{2})) if (isscalar(varargin{2}) && varargin{2} > 0) sigma_r = varargin{2}; else error("imsmooth: spread of similarity function must be a positive scalar"); endif else sigma_r = 10/255; if (isinteger(I)), sigma_r *= intmax(C); endif endif ## Pad image s = max([round(3*sigma_d),1]); I = padarray (I, [s s], "symmetric"); ## Perform the filtering J = __bilateral__(I, sigma_d, sigma_r); ############################ ### Perona and Malik ### ############################ case {"perona & malik", "perona and malik", "p&m"} ## Check input K = 25; method1 = @(d) exp(-(d./K).^2); method2 = @(d) 1./(1 + (d./K).^2); method = method1; lambda = 0.25; iter = 10; if (len > 0 && !isempty(varargin{1})) if (isscalar(varargin{1}) && varargin{1} > 0) iter = varargin{1}; else error("imsmooth: number of iterations must be a positive scalar"); endif endif if (len > 1 && !isempty(varargin{2})) if (isscalar(varargin{2}) && varargin{2} > 0) lambda = varargin{2}; else error("imsmooth: fourth input argument must be a scalar when using 'Perona & Malik'"); endif endif if (len > 2 && !isempty(varargin{3})) fail = false; if (ischar(varargin{3})) if (strcmpi(varargin{3}, "method1")) method = method1; elseif (strcmpi(varargin{3}, "method2")) method = method2; else fail = true; endif elseif (strcmp(typeinfo(varargin{3}), "function handle")) method = varargin{3}; else fail = true; endif if (fail) error("imsmooth: fifth input argument must be a function handle or the string 'method1' or 'method2' when using 'Perona & Malik'"); endif endif ## Perform the filtering I = double(I); for i = imchannels:-1:1 J(:,:,i) = pm(I(:,:,i), iter, lambda, method); endfor ##################################### ### Custom Gaussian Smoothing ### ##################################### case "custom gaussian" ## Check input if (length (varargin) < 2) error ("imsmooth: not enough input arguments"); elseif (length (varargin) == 2) varargin {3} = 0; # default theta value endif arg_names = {"third", "fourth", "fifth"}; for k = 1:3 if (isscalar (varargin {k})) varargin {k} = repmat (varargin {k}, imrows, imcols); elseif (isnumeric (varargin {k}) && ismatrix (varargin {k})) if (rows (varargin {k}) != imrows || columns (varargin {k}) != imcols) error (["imsmooth: %s input argument must have same number of rows " "and columns as the input image"], arg_names {k}); endif else error ("imsmooth: %s input argument must be a scalar or a matrix", arg_names {k}); endif if (!strcmp (class (varargin {k}), "double")) error ("imsmooth: %s input argument must be of class 'double'", arg_names {k}); endif endfor ## Perform the smoothing for i = imchannels:-1:1 J(:,:,i) = __custom_gaussian_smoothing__ (I(:,:,i), varargin {:}); endfor ###################################### ### Mean Shift Based Smoothing ### ###################################### # NOT YET IMPLEMENTED #case "mean shift" # J = mean_shift(I, varargin{:}); ############################# ### Unknown filtering ### ############################# otherwise error("imsmooth: unsupported smoothing type '%s'", name); endswitch ## Cast the result to the same class as the input J = cast(J, C); endfunction ## Perona and Malik for gray-scale images function J = pm(I, iter, lambda, g) ## Initialisation [imrows, imcols] = size(I); J = I; for i = 1:iter ## Pad image padded = padarray (J, [1 1], "circular"); ## Spatial derivatives dN = padded(1:imrows, 2:imcols+1) - J; dS = padded(3:imrows+2, 2:imcols+1) - J; dE = padded(2:imrows+1, 3:imcols+2) - J; dW = padded(2:imrows+1, 1:imcols) - J; gN = g(dN); gS = g(dS); gE = g(dE); gW = g(dW); ## Update J += lambda*(gN.*dN + gS.*dS + gE.*dE + gW.*dW); endfor endfunction ## Mean Shift smoothing for gray-scale images ## XXX: This function doesn't work!! #{ function J = mean_shift(I, s1, s2) sz = [size(I,2), size(I,1)]; ## Mean Shift [x, y] = meshgrid(1:sz(1), 1:sz(2)); f = ones(s1); tmp = conv2(ones(sz(2), sz(1)), f, "same"); # We use normalised convolution to handle the border m00 = conv2(I, f, "same")./tmp; m10 = conv2(I.*x, f, "same")./tmp; m01 = conv2(I.*y, f, "same")./tmp; ms_x = round( m10./m00 ); # konverter ms_x og ms_y til linære indices og arbejd med dem! ms_y = round( m01./m00 ); ms = sub2ind(sz, ms_y, ms_x); %for i = 1:10 i = 0; while (true) disp(++i) ms(ms) = ms; #new_ms = ms(ms); if (i >200), break; endif #idx = ( abs(I(ms)-I(new_ms)) < s2 ); #ms(idx) = new_ms(idx); %for j = 1:length(ms) % if (abs(I(ms(j))-I(ms(ms(j)))) < s2) % ms(j) = ms(ms(j)); % endif %endfor endwhile %endfor ## Compute result J = I(ms); endfunction #} %!test %! ## checking Bilateral Filter %! %! ## constant image remain the same after Bilateral Filter %! A = uint8(255*ones(128,128)); %! B = uint8(imsmooth(A, 'Bilateral', 2, 10)); %! assert (A,B); %! %! ## Bilateral Filter does not smear outlayers %! A = zeros(256,256); %! A(128,128) = 256; %! ## bilateral filter does not smear outlayers %! B = imsmooth(A, 'Bilateral', 2, 10); %! assert (A,B,1.e-140); %! %! ## When sigma_r is large the filter behaves almost %! ## like the isotropic Gaussian filter %! %! A0 = fspecial ('gaussian',100,100); %! A = uint8(A0/max(max(A0))*255); %! B1 = imsmooth(A, 'Bilateral', 2, 100); %! B2 = imsmooth(A, 'Gaussian', 2); %! assert (B1,B2); image-2.4.1/inst/PaxHeaders.6632/colfilt.m0000644000000000000000000000013212561122761015047 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/colfilt.m0000644000175000017500000001544412561122761017702 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} colfilt (@var{A}, @var{block_size}, @var{block_type}, @var{func}) ## @deftypefnx {Function File} {} colfilt (@var{A}, @var{block_size}, @var{subsize}, @var{block_type}, @var{func}, @dots{}) ## @deftypefnx {Function File} {} colfilt (@var{A}, "indexed", @dots{}) ## @deftypefnx {Function File} {} colfilt (@dots{}, @var{func}, @var{extra_args}, @dots{}) ## Apply function to matrix blocks ## ## Executes the function @var{func} on blocks of size @var{block_size}, ## taken from the matrix @var{A}. Both the matrix @var{A}, and the block ## can have any number of dimensions. ## ## The different blocks are organized into a matrix, each block as a ## single column, and passed as the first to the function handle ## @var{func}. Any input arguments to @code{colfilt} after @var{func} ## are passed to @var{func} after the blocks matrix. ## ## Blocks can be of two different types as defined by the string @var{block_type}: ## ## @table @asis ## @item @qcode{"distinct"} ## Each block is completely distinct from the other, with no overlapping ## elements. @var{func} must return a matrix of exactly the same size as ## its input. ## ## @item @qcode{"sliding"} ## Each possible block of size @var{block_size} inside @var{A} is used. ## @var{func} should act along the column dimension (be a column ## compression function) and return a vector of length equal to the ## number of columns of its input. ## ## @end table ## ## The optional argument @var{subsize} divides @var{A} into smaller pieces ## before generating the matrices with one block per column in order to ## save memory. It is currently only accepted for @sc{Matlab} compatibility. ## ## If @var{A} is an indexed image, the second argument should be the ## string @qcode{"indexed"} so that any required padding is done correctly. ## The padding value will be 0 except for indexed images of class uint8 ## and uint16. ## ## This function is mostly useful to apply moving or sliding window filter ## when @var{block_type} is "sliding". However, for many cases, specialized ## functions perform much faster. For the following common cases, consider ## the suggested alternatives; ## ## @table @asis ## @item moving average ## A moving average filter is equivalent to convolve with a matrix ## of @code{1/@var{N}} sized @var{block_size}, where @var{N} is the total ## number of elements in a block. Use ## @code{convn (@var{A}, (1/@var{N}) * ones (@var{block_size}) *, "same")} ## ## @item maximum or minimum ## This is the equivalent to a dilation and erosion. Use @code{imdilate} or ## @code{imerode}. ## ## @item any or all ## Same as dilation and erosion but with logical input. Use @code{imdilate} ## or @code{imerode} with @code{logical (@var{A})}. ## ## @item median ## Use @code{medfilt2} if @var{A} is only 2 dimensional, and @code{ordfiltn} ## with the @code{floor (prod (@var{N}/ 2)} th element, where @var{N} is the ## total number of elements in a block (add 1 if it is an even number). ## ## @item sort or nth_element ## Use @code{ordfiltn}. ## ## @item standard deviation ## Use @code{stdfilt}. ## ## @item sum ## Use a matrix of 1 to perform convolution, ## @code{convn (@var{A}, ones (@var{block_size}), "same")} ## ## @end table ## ## @seealso{bestblk, blockproc, col2im, im2col, nlfilter} ## @end deftypefn function B = colfilt (A, varargin) ## Input check if (nargin < 4) print_usage (); endif [p, block_size, padval] = im2col_check ("colfilt", nargin, A, varargin{:}); subsize = size (A); if (numel (varargin) < p) print_usage (); elseif (isnumeric (varargin{p}) && isvector (varargin{p})) subsize = varargin{p++}; subsize = postpad (subsize, ndims (A), 1); subsize = min (subsize, size (A)); subsize = max (subsize, block_size); endif ## We need at least 2 more arguments (block type and function) if (numel (varargin) < p +1) print_usage (); endif ## Next one needs to be block type block_type = varargin{p++}; if (! ischar (block_type)) error ("colfilt: BLOCK_TYPE must be a string"); endif ## followed by the function func = varargin{p++}; if (! isa (func, "function_handle")) error ("colfilt: FUNC must be a function handle"); endif ## anything after this are extra arguments to func extra_args = varargin(p:end); switch (tolower (block_type)) case "sliding" ## Function must return a single vector, one element per column, ## i.e., should act along the elements of each column. ## TODO for some large blocks, we may easily try to create matrix ## too large for Octave (see im2col documentation about the ## size). May be a good idea to split it into smaller images ## even if subsize is that large, so that we never go above ## sizemax (). ## However, this can be tricky. After splitting the image in ## smaller blocks, they can't be distinct, some parts need ## to overlap otherwise when we put them back together, we'll ## introduce many artifacts. padded = pad_for_sliding_filter (A, block_size, padval); cols = im2col (padded, block_size, "sliding"); B = col2im (func (cols, extra_args{:}), block_size, size (padded), "sliding"); case "distinct" ## Function must return a matrix with the same number of elements ## as its input, specially the same number of rows. ## One of the options of this function is to do the block ## processing already from big blocks from the original matrix ## in order to save memory. While this may make sense with ## sliding blocks, not so much here since cols will have the same ## size as A, and so will B. cols = im2col (A, block_size, "distinct"); B = col2im (func (cols, extra_args{:}), block_size, size (A), "distinct"); otherwise error ("colfilt: invalid BLOCK_TYPE `%s'.", block_type); endswitch endfunction %!demo %! ## Perform moving average filter with a 4x4 window %! A = magic (12) %! colfilt (A, [4 4], "sliding", @mean) %!test %! A = reshape (1:36, [6 6]); %! assert (colfilt (A, [2 2], [3 3], "sliding", @sum), %! conv2 (A, ones (2), "same")); image-2.4.1/inst/PaxHeaders.6632/imcrop.m0000644000000000000000000000013212561122761014704 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imcrop.m0000644000175000017500000002030012561122761017522 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imcrop () ## @deftypefnx {Function File} {} imcrop (@var{img}) ## @deftypefnx {Function File} {} imcrop (@var{ind}, @var{cmap}) ## @deftypefnx {Function File} {} imcrop (@var{h}) ## @deftypefnx {Function File} {} imcrop (@dots{}, @var{rect}) ## @deftypefnx {Function File} {[@var{cropped}] =} imcrop (@dots{}) ## @deftypefnx {Function File} {[@var{cropped}, @var{rect}] =} imcrop (@dots{}) ## @deftypefnx {Function File} {[@var{x}, @var{y}, @var{cropped}, @var{rect}] =} imcrop (@dots{}) ## Crop image. ## ## Displays the image @var{img} in a figure window and waits for the user to ## select two points defining a bounding box. First click on the top left ## and then on the bottom right corner of the region. For an indexed image, a ## corresponding colormap can be specified in @var{cmap}. For multi-dimensional ## images (each 2D image is concatenated in the 4th dimension), only the ## first image is displayed. ## ## if no image data is given, uses the current figure or figure from graphics ## handle @var{h}. ## ## Non-interactive usage is supported if the last input argument is 4 element ## vector @var{rect} defining the region of interest. The first two elements ## specify the initial @var{x_ini} and @var{y_ini} coordinates, and the last ## two the @var{width} and @var{height}, i.e., ## @code{@var{rect} = [@var{x_ini} @var{y_ini} @var{width} @var{height}]}. ## Note how this the opposite of the majority of Octave indexing rules where ## rows come before columns. ## ## Returns the @var{cropped} image and a vector @var{rect} with the ## coordinates and size for @var{cropped}. If more than 3 output arguments ## are requested, also returns the @var{x} and @var{y} data that define ## the coordinate system. ## ## @emph{Note}: the values in @var{rect} are not necessarily integer values ## and can't always be used directly as index values for other images. To ## crop the same region from a multiple images of the same size, either using ## a multi-dimensional image: ## ## @example ## @group ## nd_img = cat (4, img1, img2, img3, img4); ## cropped = imcrop (nd_img); ## cropped_1 = cropped(:,:,:,1); ## cropped_2 = cropped(:,:,:,2); ## cropped_3 = cropped(:,:,:,3); ## cropped_4 = cropped(:,:,:,4); ## @end group ## @end example ## ## or multiple calls to @code{imcrop}: ## ## @example ## @group ## [cropped_1, rect] = imcrop (img1); ## cropped_2 = imcrop (img2, rect); ## cropped_3 = imcrop (img3, rect); ## cropped_4 = imcrop (img4, rect); ## @end group ## @end example ## ## @seealso{impixel, imshow} ## @end deftypefn ## TODO not yet implemented ## @deftypefnx {Function File} {} imcrop (@var{xData}, @var{yData}, @dots{}) function varargout = imcrop (varargin) ## Screw Matlab and their over complicated API's! How can we properly ## parse all the possible alternative calls? See ## http://www.youtube.com/watch?v=1oZWacjmYm8 to understand how such ## API's develop. ## There is no check for this things, anything is valid. We (Octave) ## are at least checking the number of elements otherwise the input ## parsing would be horrible. valid_rect = @(x) numel (x) == 4; valid_system = @(x) numel (x) == 2; rect = []; interactive = true; # is interactive usage alt_system = false; # was an alternative coordinate system requested? from_fig = false; # do we have the image data or need to fetch from figure? if (nargin > 5) print_usage (); endif rect = []; if (numel (varargin) > 1 && valid_rect (varargin{end})) interactive = false; rect = varargin{end}; varargin(end) = []; endif xdata = []; ydata = []; if (numel (varargin) > 2 && valid_system (varargin{1}) && valid_system (varargin{2})) ## requested messy stuff ## we should probably reuse part of what impixel does alt_system = true; xdata = varargin{1}; ydata = varargin{2}; varargin([1 2]) = []; error ("imcrop: messing around with coordinate system is not implemented"); endif ## After we remove all that extra stuff, we are left with the image fnargin = numel (varargin); if (fnargin > 2) print_usage (); elseif (fnargin == 0) ## use current figure from_fig = true; h = gcf (); ## We check isscalar() because ishandle() accepts arrays of handles, and we ## check "!= 0" because 0 is and handle for the "root figure" which is ## invalid for imcrop (see bug #42714). elseif (fnargin == 1 && isscalar (varargin{1}) && varargin{1} != 0 && ishandle (varargin{1})) ## use specified figure from_fig = true; h = varargin{1}; elseif (interactive) ## leave input check to imshow h = nd_imshow (varargin{:}); elseif (isimage (varargin{1})) ## we have the image data and it's not interactive, so there is ## nothing to do. We only check the minimum in the image. else print_usage (); endif if (from_fig) cdata = get (h, "cdata"); xdata = get (h, "xdata"); ydata = get (h, "ydata"); else cdata = varargin{1}; if (! alt_system) xdata = [1 columns(cdata)]; ydata = [1 rows(cdata)]; endif endif ## Finally, crop the image if (interactive) [x, y] = ginput (2); rect = [x(1) y(1) x(2)-x(1) y(2)-y(1)]; endif i_ini = round ([rect(1) rect(2)]); i_end = round ([rect(1)+rect(3) rect(2)+rect(4)]); img = cdata(i_ini(2):i_end(2), i_ini(1):i_end(1),:,:); # don't forget RGB and ND images ## Even the API for the output is complicated if (nargout == 0 && interactive) figure (); ## In case we have a colormap or something like that, use ## it again when displaying the cropped image. nd_imshow (img, varargin{2:end}); elseif (nargout < 3) varargout{1} = img; varargout{2} = rect; else varargout{1} = xdata; varargout{2} = ydata; varargout{3} = img; varargout{4} = rect; endif endfunction ## shadows core function to support ND image. If we have one, use ## the first frame only function h = nd_imshow (varargin) size (varargin{1}); h = imshow (varargin{1}(:,:,:,1), varargin{2:end}); endfunction ## test typical non-interactive usage, grayscale image %!test %! a = randi (255, [100 100]); %! rect = [20 30 3 5]; %! assert (nthargout ([1 2], @imcrop, a, rect), {a(30:35, 20:23) rect}); %! assert (nthargout (2, @imcrop, a, rect), rect); %! assert (nthargout ([3 4], 4, @imcrop, a, rect), {a(30:35, 20:23) rect}); ## test typical non-interactive usage, RGB image %!test %! rgb = randi (255, [100 100 3]); %! rect = [20 30 3 5]; %! assert (nthargout ([1 2], @imcrop, rgb, rect), {rgb(30:35, 20:23,:) rect}); %! assert (nthargout (2, @imcrop, rgb, rect), rect); %! assert (nthargout ([3 4], 4, @imcrop, rgb, rect), {rgb(30:35, 20:23,:) rect}); ## test typical non-interactive usage, indexed image %!test %! a = randi (255, [100 100]); %! rect = [20 30 3 5]; %! cmap = jet (255); %! assert (nthargout ([1 2], @imcrop, a, cmap, rect), {a(30:35, 20:23) rect}); %! assert (nthargout (2, @imcrop, a, cmap, rect), rect); %! assert (nthargout ([3 4], 4, @imcrop, a, cmap, rect), {a(30:35, 20:23) rect}); ## test typical non-interactive usage, logical image %!test %! a = rand (100) > 0.5; %! rect = [20 30 3 5]; %! assert (nthargout ([1 2], @imcrop, a, rect), {a(30:35, 20:23) rect}); %! assert (nthargout (2, @imcrop, a, rect), rect); %! assert (nthargout ([3 4], 4, @imcrop, a, rect), {a(30:35, 20:23) rect}); ## 0 is the root figure (always true figure handle), so make sure we use ## scalar 0 as image data, not as figure handle. %!assert (imcrop (0, [0.5 0.5 0.9 0.9]), 0); %!assert (imcrop (zeros (5), [1 1 1 1]), zeros (2)); image-2.4.1/inst/PaxHeaders.6632/imfilter.m0000644000000000000000000000013212561122761015226 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imfilter.m0000644000175000017500000001015512561122761020053 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2007 Søren Hauberg ## ## 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 3 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{J} = imfilter(@var{I}, @var{f}) ## @deftypefnx{Function File} @var{J} = imfilter(@var{I}, @var{f}, @var{options}, @dots{}) ## Computes the linear filtering of the image @var{I} and the filter @var{f}. ## The computation is performed using double precision floating point numbers, ## but the class of the input image is preserved as the following example shows. ## @example ## I = 255*ones(100, 100, "uint8"); ## f = fspecial("average", 3); ## J = imfilter(I, f); ## class(J) ## @result{} ans = uint8 ## @end example ## ## The function also accepts a number of optional arguments that control the ## details of the filtering. The following options is currently accepted ## @table @samp ## @item S ## If a scalar input argument is given, the image is padded with this scalar ## as part of the filtering. The default value is 0. ## @item "symmetric" ## The image is padded symmetrically. ## @item "replicate" ## The image is padded using the border of the image. ## @item "circular" ## The image is padded by circular repeating of the image elements. ## @item "same" ## The size of the output image is the same as the input image. This is the default ## behaviour. ## @item "full" ## Returns the full filtering result. ## @item "corr" ## The filtering is performed using correlation. This is the default behaviour. ## @item "conv" ## The filtering is performed using convolution. ## @end table ## @seealso{conv2, filter2, fspecial, padarray} ## @end deftypefn function retval = imfilter(im, f, varargin) ## Check number of input arguments if (nargin < 2) print_usage(); endif ## Check image if (! isimage (im)) error("imfilter: IM must be an image"); endif [imrows, imcols, imchannels, tmp] = size(im); if (tmp != 1 || (imchannels != 1 && imchannels != 3)) error("imfilter: first input argument must be an image"); endif C = class(im); ## Check filter (XXX: matlab support 3D filter, but I have no idea what they do with them) if (! isnumeric (f)) error("imfilter: F must be a numeric array"); endif [frows, fcols, tmp] = size(f); if (tmp != 1) error("imfilter: second argument must be a 2-dimensional matrix"); endif ## Parse options res_size = "same"; res_size_options = {"same", "full"}; pad = 0; pad_options = {"symmetric", "replicate", "circular"}; ftype = "corr"; ftype_options = {"corr", "conv"}; for i = 1:length(varargin) v = varargin{i}; if (any(strcmpi(v, pad_options)) || isscalar(v)) pad = v; elseif (any(strcmpi(v, res_size_options))) res_size = v; elseif (any(strcmpi(v, ftype_options))) ftype = v; else warning("imfilter: cannot handle input argument number %d", i+2); endif endfor ## Pad the image im = padarray(im, floor([frows/2, fcols/2]), pad); if (mod(frows,2) == 0) im = im(1:end-1, :, :); endif if (mod(fcols,2) == 0) im = im(:, 1:end-1, :); endif ## Do the filtering if (strcmpi(res_size, "same")) res_size = "valid"; else # res_size == "full" res_size = "same"; endif if (strcmpi(ftype, "corr")) for i = imchannels:-1:1 retval(:,:,i) = filter2(f, im(:,:,i), res_size); endfor else for i = imchannels:-1:1 retval(:,:,i) = conv2(im(:,:,i), f, res_size); endfor endif ## Change the class of the output to the class of the input ## (the filtering functions returns doubles) retval = cast(retval, C); endfunction image-2.4.1/inst/PaxHeaders.6632/hough_circle.m0000644000000000000000000000013212561122761016046 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/hough_circle.m0000644000175000017500000000632212561122761020674 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{accum}= hough_circle (@var{bw}, @var{r}) ## Perform the Hough transform for circles with radius @var{r} on the ## black-and-white image @var{bw}. ## ## As an example, the following shows how to compute the Hough transform for circles ## with radius 3 or 7 in the image @var{im} ## @example ## bw = edge(im); ## accum = hough_circle(bw, [3, 7]); ## @end example ## If @var{im} is an NxM image @var{accum} will be an NxMx2 array, where ## @var{accum}(:,:,1) will contain the Hough transform for circles with ## radius 3, and @var{accum}(:,:,2) for radius 7. To find good circles you ## now need to find local maximas in @var{accum}, which can be a hard problem. ## If you find a local maxima in @var{accum}(row, col, 1) it means that a ## good circle exists with center (row,col) and radius 3. ## ## @seealso{houghtf} ## @end deftypefn function accum = hough_circle(bw, r) ## Check input arguments if (nargin != 2) error("hough_circle: wrong number of input arguments"); endif if (! ismatrix (bw)) error("hough_circle: BW must be a 2-dimensional matrix"); endif if (!isvector(r) || !isreal(r) || any(r<0)) error("hough_circle: radius arguments must be a positive vector or scalar"); endif ## Create the accumulator array. accum = zeros(size(bw,1), size(bw,2), length(r)); ## Find the pixels we need to look at [R, C] = find(bw); ## Iterate over different radius for j = 1:length(r) rad = r(j); ## Compute a filter containing the circle we're looking for. circ = circle(rad); ## Iterate over all interesting image points for i =1:length(R) row = R(i); col = C(i); ## Compute indices for the accumulator array a_rows = max(row-rad,1) : min(row+rad, size(accum,1)); a_cols = max(col-rad,1) : min(col+rad, size(accum,2)); ## Compute indices for the circle array (the filter) c_rows = max(rad-row+2,1) : min(rad-row+1+size(accum,1), size(circ,1)); c_cols = max(rad-col+2,1) : min(rad-col+1+size(accum,2), size(circ,2)); ## Update the accumulator array accum( a_rows, a_cols, j ) += circ ( c_rows, c_cols ); endfor endfor endfunction ## Small auxilary function that creates an (2r+1)x(2r+1) image containing ## a circle with radius r and center (r+1, r+1). function circ = circle(r) circ = zeros(round(2*r+1)); col = 1:size(circ,2); for row=1:size(circ,1) tmp = (row-(r+1)).^2 + (col-(r+1)).^2; circ(row,col) = (tmp <= r^2); endfor circ = bwmorph(circ, 'remove'); endfunction image-2.4.1/inst/PaxHeaders.6632/immaximas.m0000644000000000000000000000013212561122761015400 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/immaximas.m0000644000175000017500000001117312561122761020226 0ustar00carandraugcarandraug00000000000000## Copyright (c) 2003-2005 Peter Kovesi ## School of Computer Science & Software Engineering ## The University of Western Australia ## http://www.csse.uwa.edu.au/ ## ## Permission is hereby granted, free of charge, to any person obtaining a copy ## of this software and associated documentation files (the "Software"), to deal ## in the Software without restriction, including without limitation the rights ## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ## copies of the Software, and to permit persons to whom the Software is ## furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included in ## all copies or substantial portions of the Software. ## ## The software is provided "as is", without warranty of any kind, express or ## implied, including but not limited to the warranties of merchantability, ## fitness for a particular purpose and noninfringement. In no event shall the ## authors or copyright holders be liable for any claim, damages or other ## liability, whether in an action of contract, tort or otherwise, arising from, ## out of or in connection with the software or the use or other dealings in the ## software. ## ## I've made minor changes compared to the original 'nonmaxsuppts' function developed ## by Peter Kovesi. The original is available at ## http://www.csse.uwa.edu.au/~pk/research/matlabfns/Spatial/nonmaxsuppts.m ## -- Søren Hauberg, 2008 ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{r}, @var{c}] =} immaximas (@var{im}, @var{radius}) ## @deftypefnx{Function File} {[@var{r}, @var{c}] =} immaximas (@var{im}, @var{radius}, @var{thresh}) ## @deftypefnx{Function File} {[@var{r}, @var{c}, @dots{}] =} immaximas (@dots{}) ## @deftypefnx{Function File} {[@dots{}, @var{val}] =} immaximas (@dots{}) ## Find local spatial maximas. ## ## Local spatial maximas should not be mistaken with regional maxima. ## See @code{imregionalmax} for the later. ## ## A local spatial maxima is ## defined as an image point with a value that is larger than all neighbouring ## values in a square region of width 2*@var{radius}+1. By default @var{radius} ## is 1, such that a 3 by 3 neighbourhood is searched. If the @var{thresh} input ## argument is supplied, only local maximas with a value greater than @var{thresh} ## are retained. ## ## The output vectors @var{r} and @var{c} contain the row-column coordinates ## of the local maximas. The actual values are computed to sub-pixel precision ## by fitting a parabola to the data around the pixel. If @var{im} is ## @math{N}-dimensional, then @math{N} vectors will be returned. ## ## If @var{im} is @math{N}-dimensional, and @math{N}+1 outputs are requested, ## then the last output will contain the image values at the maximas. Currently ## this value is not interpolated. ## ## @seealso{imregionalmax, ordfilt2, ordfiltn} ## @end deftypefn function varargout = immaximas(im, radius, thresh) ## Check input if (nargin == 0) error("immaximas: not enough input arguments"); endif if (nargin <= 1 || isempty(radius)) radius = 1; endif if (nargin <= 2) thresh = []; endif if (! isnumeric (im)) error("immaximas: IM must be a numeric array"); endif if (!isscalar(radius)) error("immaximas: second input argument must be a scalar or an empty matrix"); endif if (!isscalar(thresh) && !isempty(thresh)) error("immaximas: third input argument must be a scalar or an empty matrix"); endif ## Find local maximas nd = ndims(im); s = size(im); sze = 2*radius+1; mx = ordfiltn(im, sze^nd, ones(repmat(sze,1, nd), "logical"), "reflect"); mx2 = ordfiltn(im, sze^nd-1, ones(repmat(sze,1, nd), "logical"), "reflect"); # Find maxima, threshold immx = (im == mx) & (im != mx2); if (!isempty(thresh)) immx &= (im>thresh); endif ## Find local maximas and fit parabolas locally ind = find(immx); [sub{1:nd}] = ind2sub(s, ind); if (!isempty(ind)) w = 1; # Width that we look out on each side of the feature point to fit a local parabola ws = w*cumprod([1; s(:)]); ## We fit a parabola to the points in each dimension for d = 1:nd ## Indices of points above, below, left and right of feature point indminus1 = max(ind-ws(d), 1); indplus1 = min(ind+ws(d), numel(immx)); ## Solve quadratic c = im(ind); a = (im(indminus1) + im(indplus1))/2 - c; b = a + c - im(indminus1); shift = -w*b./(2*a); # Maxima of quadratic ## Move point sub{d} += shift; endfor endif ## Output varargout(1:nd) = sub(1:nd); if (nargout > nd) varargout{nd+1} = im(ind); endif endfunction image-2.4.1/inst/PaxHeaders.6632/phantom.m0000644000000000000000000000013212561122761015061 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/phantom.m0000644000175000017500000002075012561122761017710 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Alex Opie ## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{P}} = phantom () ## @deftypefnx {Function File} {@var{P}} = phantom (@var{model}) ## @deftypefnx {Function File} {@var{P}} = phantom (@var{E}) ## @deftypefnx {Function File} {@var{P}} = phantom (@dots{}, @var{n}) ## @deftypefnx {Function File} {[@var{P}, @var{E}]} = phantom (@dots{}) ## Create computational phantom head. ## ## A phantom is a known object (either real or purely mathematical) that is ## used for testing image reconstruction algorithms. The Shepp-Logan phantom ## is a popular mathematical model of a cranial slice, made up of a set of ## overlaying ellipses. This allows rigorous testing of computed tomography ## (CT) algorithms as it can be analytically transformed with the radon ## transform (see the functions @code{radon} and @code{iradon}). ## ## The phantom @var{P}, is created by overlaying ellipses as defined by the ## matrix @var{E} or one of the standard @var{model}s, in a square of size ## @var{n} by @var{n} (defaults to 256). ## ## The available standard @var{model}s (use the output argument @var{E} to ## inspect the details of the different ellipses) are: ## ## @table @asis ## @item @qcode{"Sheep-Logan"} ## This is the original Sheep-Logan model with 10 ellipses as described in ## Table 1 of @cite{Shepp, Lawrence A., and Benjamin F. Logan. "The Fourier ## reconstruction of a head section." Nuclear Science, IEEE Transactions on ## 21, no. 3 (1974): 21-43.} ## ## @item @qcode{"Modified Shepp-Logan"} (default) ## A modification of the original Shepp-Logan model to give a better contrast, ## as described in Table B.3 of @cite{Toft, Peter Aundal. "The radon ## transform-theory and implementation." PhD diss., Department of Mathematical ## Modelling, Technical University of Denmark, 1996.} ## ## @end table ## ## A 6 column matrix @var{E} can be used to generate a custom image by ## superimposing arbitrary ellipses. Each row defines a single ellipse, with ## each column for the values of @{I, a, b, x0, y0, phi@}: ## ## @table @abbr ## @item I ## is the additive intensity of the ellipse ## ## @item a ## is the length of the major axis ## ## @item b ## is the length of the minor axis ## ## @item x0 ## is the horizontal offset of the centre of the ellipse ## ## @item y0 ## is the vertical offset of the centre of the ellipse ## ## @item phi ## is the counterclockwise rotation of the ellipse in degrees, ## measured as the angle between the x axis and the ellipse major axis. ## ## @end table ## ## The image bounding box in the algorithm is @{[-1, -1], [1, 1]@}, so the ## values of a, b, x0, y0 should all be specified with this in mind. ## ## Example: ## ## @example ## @group ## P = phantom (512); ## imshow (P); ## @end group ## @end example ## ## @seealso{iradon, radon} ## @end deftypefn function [head, ellipses] = phantom (varargin) if (nargin > 2) print_usage () endif ## Would be really cool if we implemented a 3D phantom as already described ## in Cheng Guan Koay, Joelle E. Sarlls, and Evren Ozarslan (2007). ## "Three-Dimensional Analytical Magnetic Resonance Imaging Phantom in the ## Fourier Domain". Magnetic Resonance in Medicine 58:430 - 436. ## The Table 1 on their paper to generate the 3D model, would take 8 columns, ## an extra value for z axis coordinates, and extra axis length. ## They mention other phantom heads as more canonical 3D head phantoms (read ## the introduction) ## Defaults ellipses = mod_shepp_logan (); n = 256; if (nargin) ## Check validity of N chk_n = @(x) isnumeric (x) && isscalar (x) && ceil (x) == x; in = varargin{1}; if (ischar (in)) switch (tolower (in)) case "shepp-logan", ellipses = shepp_logan (); case "modified shepp-logan", ellipses = mod_shepp_logan (); otherwise error ("phantom: unknown MODEL `%s'", in); endswitch elseif (isnumeric (in) && ndims (in) == 2 && columns (in) == 6) ellipses = in; elseif (chk_n (in)) n = in; ## If N is the first argument, we can't have more if (nargin > 1) print_usage (); endif else error ("phantom: first argument must either be MODEL, E, or N"); endif ## If there is a second input argument, must be N if (nargin > 1) if (chk_n (varargin{2})) n = varargin{2}; else error ("phantom: N must be numeric scalar"); endif endif endif ## Initialize blank image head = zeros (n); # Create the pixel grid xvals = (-1 : 2 / (n - 1) : 1); xgrid = repmat (xvals, n, 1); for i = 1:rows (ellipses) I = ellipses (i, 1); a2 = ellipses (i, 2)^2; b2 = ellipses (i, 3)^2; x0 = ellipses (i, 4); y0 = ellipses (i, 5); phi = ellipses (i, 6) * pi / 180; # Rotation angle in radians ## Create the offset x and y values for the grid x = xgrid - x0; y = rot90 (xgrid) - y0; cos_p = cos (phi); sin_p = sin (phi); ## Find the pixels within the ellipse locs = find (((x .* cos_p + y .* sin_p).^2) ./ a2 ... + ((y .* cos_p - x .* sin_p).^2) ./ b2 <= 1); ## Add the ellipse intensity to those pixels head(locs) += I; endfor endfunction function ellipses = shepp_logan () ## Standard head phantom, taken from Shepp & Logan ## ## Note that the first element of this matrix, the gray value for the first ## ellipse (human skull), has a value of 1.0 even though the paper gives it a ## a value of 2.0 (see Table 1 on page 32 and Figure 1 on page 34). This ## change is so that the **head** intensity values appear in the range [0 1] ## rather than the range [1 2]. ## ## **The problem with this** ## ## The background still need an intensity value which is going to be 0. This ## means that we can't distinguish between the background and the ventricles ## (ellipse "c" and "d" whose intensities are a + b + c and a + b + d, see ## Figure 1) since they will have an intensity value of 0 (actually, because ## of machine precision the ventricules will be almost 0). But if we didn't ## made this change, the ** image** range would be [0 2] with all of the head ## details compressed in half of the display range. Also, Matlab seems to be ## doing the same. persistent ellipses = [ 1 0.69 0.92 0 0 0 -0.98 0.6624 0.874 0 -0.0184 0 -0.02 0.11 0.31 0.22 0 -18 -0.02 0.16 0.41 -0.22 0 18 0.01 0.21 0.25 0 0.35 0 0.01 0.046 0.046 0 0.1 0 0.01 0.046 0.046 0 -0.1 0 0.01 0.046 0.023 -0.08 -0.605 0 0.01 0.023 0.023 0 -0.606 0 0.01 0.023 0.046 0.06 -0.605 0]; endfunction function ellipses = mod_shepp_logan () ## Modified version of Shepp & Logan's head phantom, adjusted to improve ## contrast. Taken from Peter Toft PhD thesis, Table B.3 persistent ellipses = [ 1.0 0.69 0.92 0.0 0.0 0 -0.8 0.6624 0.874 0.0 -0.0184 0 -0.2 0.11 0.31 0.22 0.0 -18 -0.2 0.16 0.41 -0.22 0.0 18 0.1 0.21 0.25 0.0 0.35 0 0.1 0.046 0.046 0.0 0.1 0 0.1 0.046 0.046 0.0 -0.1 0 0.1 0.046 0.023 -0.08 -0.605 0 0.1 0.023 0.023 0.0 -0.606 0 0.1 0.023 0.046 0.06 -0.605 0]; endfunction %!demo %! P = phantom (512); %! imshow (P); image-2.4.1/inst/PaxHeaders.6632/otf2psf.m0000644000000000000000000000013212561122761014776 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/otf2psf.m0000644000175000017500000000753512561122761017633 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2015 Carnë Draug ## ## 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 3 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} {} otf2psf (@var{otf}) ## @deftypefnx {Function File} {} otf2psf (@var{otf}, @var{outsize}) ## Compute PSF from OTF. ## ## Returns the Point Spread Function (OTF) of the Optical Transfer ## Function @var{otf}. ## ## The optional argument @var{outsize} defines the size of the returned ## @var{psf}. ## ## @seealso{circshift, ifft2, ifftn, psf2otf} ## @end deftypefn function psf = otf2psf (otf, outsize) if (nargin < 1 || nargin > 2) print_usage (); elseif (! isnumeric (otf)) error ("otf2psf: OTF must be numeric") endif insize = size (otf); psf = ifftn (otf); psf = circshift (psf, floor (insize / 2)); if (nargin > 1) if (! isnumeric (outsize) || ! isvector (outsize)) error ("otf2psf: OUTSIZE must be a numeric vector"); endif insize = size (otf); n = max (numel (outsize), numel (insize)); outsize = postpad (outsize(:), n, 1); insize = postpad (insize(:) , n, 1); pad = (insize - outsize) / 2; if (any (pad < 0)) error ("otf2psf: OUTSIZE must be smaller than or equal than OTF size"); endif prepad = floor (pad); postpad = ceil (pad); idx = arrayfun (@colon, prepad + 1, insize - postpad, "UniformOutput", false); psf = psf(idx{:}); endif endfunction ## We are assuming psf2otf is working correctly %!function otf = rand_otf (varargin) %! otf = complex (rand (varargin{:}), rand (varargin{:})); %!endfunction ## Basic usage, 1, 2, and 3 dimensional %!test %! otf = rand_otf (6, 1); %! assert (otf2psf (otf), circshift (ifft (otf), 3)); %!test %! otf = rand_otf (6, 6); %! assert (otf2psf (otf), circshift (ifft2 (otf), [3 3])); %!test %! otf = rand_otf (6, 6, 6); %! assert (otf2psf (otf), circshift (ifftn (otf), [3 3 3])); ## Test when length of some sides are odd %!test %! otf = rand_otf (7, 1); %! assert (otf2psf (otf), circshift (ifft (otf), 3)); %!test %! otf = rand_otf (7, 7); %! assert (otf2psf (otf), circshift (ifft2 (otf), [3 3])); %!test %! otf = rand_otf (6, 7, 8); %! assert (otf2psf (otf), circshift (ifftn (otf), [3 3 4])); ## Test the outsize/unpadding option %!test %! otf = rand_otf (7, 1); %! ppsf = circshift (ifft (otf), 3); %! assert (otf2psf (otf, 6), ppsf(1:6)); %! assert (otf2psf (otf, [6 1]), ppsf(1:6)); %!test %! otf = rand_otf (7, 7); %! ppsf = circshift (ifft2 (otf), [3 3]); %! assert (otf2psf (otf, [6 1]), ppsf(1:6,4)); %!test %! otf = rand_otf (6, 7); %! ppsf = circshift (ifft2 (otf), [3 3]); %! assert (otf2psf (otf, [6 6]), ppsf(:,1:6)); %!error otf2psf ("not a otf") %!error otf2psf (rand_otf (16), 18) %!error otf2psf (rand_otf (16), [14 18]) %!error otf2psf (rand_otf (16), [18 18]) %!error otf2psf (rand_otf (16, 1), 18) ## Some less random tests %!test %! psf = fspecial ("gaussian", 16); %! otf = psf2otf (psf); %! assert (otf2psf (otf), psf, eps); %!test %! psf = rand (16); %! otf = psf2otf (psf); %! assert (otf2psf (otf), psf, 2*eps); %!test %! psf = rand (8); %! otf = psf2otf (psf, [16 16]); %! assert (otf2psf (otf, [8 8]), psf, 2*eps); image-2.4.1/inst/PaxHeaders.6632/iradon.m0000644000000000000000000000013212561122761014667 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/iradon.m0000644000175000017500000001351512561122761017517 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Alex Opie ## ## 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 3 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{recon} =} iradon (@var{proj}, @var{theta}, @var{interp}, @var{filter}, @var{scaling}, @var{output_size}) ## ## Performs filtered back-projection on the projections in @var{proj} ## to reconstruct an approximation of the original image. ## ## @var{proj} should be a matrix whose columns are projections of an ## image (or slice). Each element of @var{theta} is used as the angle ## (in degrees) that the corresponding column of @var{proj} was ## projected at. If @var{theta} is omitted, it is assumed that ## projections were taken at evenly spaced angles between 0 and 180 degrees. ## @var{theta} can also be a scalar, in which case it is taken as the ## angle between projections if more than one projection is provided. ## ## @var{interp} determines the type of interpolation that is used ## in the back-projection. It must be one of the types accepted by ## @command{interp1}, and defaults to 'Linear' if it is omitted. ## ## @var{filter} and @var{scaling} determine the type of rho filter ## to apply. See the help for @command{rho_filter} for their use. ## ## @var{output_size} sets the edge length of the output image (it ## is always square). This argument does not scale the image. If it ## is omitted, the length is taken to be ## @group ## 2 * floor (size (proj, 1) / (2 * sqrt (2))). ## @end group ## ## If @var{proj} was obtained using @command{radon}, there is no ## guarantee that the reconstructed image will be exactly the same ## size as the original. ## ## @end deftypefn ## @deftypefn {Function File} {[@var{recon}, @var{filt}] =} iradon (@dots{}) ## ## This form also returns the filter frequency response in the vector ## @var{filt}. ## ## Performs filtered back-projection in order to reconstruct an ## image based on its projections. ## ## Filtered back-projection is the most common means of reconstructing ## images from CT scans. It is a two step process: First, each of ## the projections is filtered with a `rho filter', so named due ## to its frequency domain definition, which is simply |rho|, where ## rho is the radial axis in a polar coordinate system. Second, ## the filtered projections are each `smeared' across the image ## space. This is the back-projection part. ## ## Usage example: ## ## @example ## @group ## P = phantom (); ## projections = radon (P, 1:179); ## reconstruction = iradon (filtered_projections, 1:179, 'Spline', 'Hann'); ## figure, imshow (reconstruction, []) ## @end group ## @end example ## ## @end deftypefn function [recon, filt] = iradon (proj, theta, interp, filter, scaling, output_size) if (nargin == 0) error ("No projections provided to iradon"); endif if (nargin < 6) output_size = 2 * floor (size (proj, 1) / (2 * sqrt (2))); endif if (nargin < 5) || (length (scaling) == 0) scaling = 1; endif if (nargin < 4) || (length (filter) == 0) filter = "Ram-Lak"; endif if (nargin < 3) || (length (interp) == 0) interp = "linear"; endif if (nargin < 2) || (length (theta) == 0) theta = 180 * (0:1:size (proj, 2) - 1) / size (proj, 2); endif if (isscalar (theta)) && (size (proj, 2) != 1) theta = (0:size (proj, 2) - 1) * theta; endif if (length (theta) != size (proj, 2)) error ("iradon: Number of projections does not match number of angles") endif if (!isscalar (scaling)) error ("iradon: Frequency scaling value must be a scalar"); endif if (!length (find (strcmpi (interp, {'nearest', 'linear', 'spline', ... 'pchip', 'cubic'})))) error ("iradon: Invalid interpolation method specified"); endif ## Convert angles to radians theta *= pi / 180; ## First, filter the projections [filtered, filt] = rho_filter (proj, filter, scaling); ## Next, back-project recon = back_project (filtered, theta, interp, output_size); endfunction function recon = back_project (proj, theta, interpolation, dim) ## Make an empty image recon = zeros (dim, dim); ## Zero pad the projections if the requested image ## has a diagonal longer than the projections diagonal = ceil (dim * sqrt (2)) + 1; if (size (proj, 1) < diagonal) diff = 2 * ceil ((diagonal - size (proj, 1)) / 2); proj = padarray (proj, diff / 2); endif ## Create the x & y values for each pixel centre = floor ((dim + 1) / 2); x = (0:dim - 1) - centre + 1; x = repmat (x, dim, 1); y = (dim - 1: -1 : 0)' - centre; y = repmat (y, 1, dim); ## s axis for projections, needed by interp1 s = (0:size (proj, 1) - 1) - floor (size (proj, 1) / 2); ## Sum each projection's contribution for i = 1:length (theta) s_dash = (x * cos (theta (i)) + y * sin (theta (i))); interpolated = interp1 (s, proj (:, i), s_dash (:), ["*", interpolation]); recon += reshape (interpolated, dim, dim); endfor ## Scale the reconstructed values to their original size recon *= pi / (2 * length (theta)); endfunction %!demo %! P = phantom (); %! figure, imshow (P, []), title ("Original image") %! projections = radon (P, 0:179); %! reconstruction = iradon (projections, 0:179, 'Spline', 'Hann'); %! figure, imshow (reconstruction, []), title ("Reconstructed image") image-2.4.1/inst/PaxHeaders.6632/imdither.m0000644000000000000000000000013212561122761015220 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imdither.m0000644000175000017500000000557612561122761020060 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2009 Sergey Kirgizov ## ## 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 3 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{Y}, @var{newmap}] =} imdither (@var{img}) ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} imdither (@var{img}, @ ## @var{colors}) ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} imdither (@var{img}, @ ## @var{colors}, @var{dithtype}) ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} imdither (@var{img}, @ ## @var{map}) ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} imdither (@var{img}, @ ## @var{map}, @var{colors}) ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} imdither(@var{img}, @ ## @var{map}, @var{colors}, @var{dithtype}) ## Reduce the number a colors of rgb or indexed image. ## ## Note: this requires the ImageMagick "convert" utility. ## get this from www.imagemagick.org if required ## additional documentation of options is available from the ## convert man page. ## ## where ## @var{dithtype} is a value from list: ## ## @itemize @bullet ## @item "None" ## @item "FloydSteinberg" (default) ## @item "Riemersma" ## @end itemize ## ## @var{colors} is a maximum number of colors in result map ## ## TODO: Add facility to use already created colormap over "-remap" option ## ## BUGS: This function return a 0-based indexed images ## when colormap size is lower or equals to 256 like at cmunique code ## @seealso{cmunique} ## ## @end deftypefn function [Y, newmap] = imdither (im, p1, p2, p3) colors="256"; dithtype="FloydSteinberg"; if (nargin < 1) print_usage; endif fname = [tmpnam(),".ppm"]; if (nargin == 1 || isscalar(p1)) # rgb if (nargin >= 2) colors=sprintf("%d",p1); if (nargin >= 3) dithtype=p2; endif endif opts=["-colors ",colors;"-dither ",dithtype]; imwrite(fname,im(:,:,1),im(:,:,2),im(:,:,3),opts); [Y,newmap]=cmunique(imread(fname)); delete(fname); else if (nargin <= 1) print_usage; endif # indexed if (nargin >= 3) colors=sprintf("%d",p2); if (nargin >= 4) dithtype=p3; endif endif opts=["-colors ",colors;"-dither ",dithtype]; im (rows(p1)<=256) imwrite(fname,im,(p1+1),opts); [Y,newmap]=cmunique(imread(fname)); delete(fname); endif endfunction image-2.4.1/inst/PaxHeaders.6632/imgradient.m0000644000000000000000000000013212561122761015536 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imgradient.m0000644000175000017500000000673312561122761020372 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Brandon Miles ## ## 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 3 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{gradMag}, @var{gradDir}] =} imgradient (@var{img}) ## @deftypefnx {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{img}, @var{method}) ## @deftypefnx {Function File} {[@var{gradMag}, @var{gradDir}] =} imgradient (@var{gx}, @var{gy}) ## Compute the gradient magnitude and direction in degrees for an image. ## ## These are computed from the @var{gx} and @var{xy} gradients using ## @code{imgradientxy}. The first input @var{img} is a gray scale image to ## compute the edges on. The second input @var{method} controls the method ## used to calculate the gradients. Alternatively the first input @var{gx} ## can be the x gradient and the second input @var{gy} can be the y gradient. ## ## The first output @var{gradMag} returns the magnitude of the gradient. ## The second output @var{gradDir} returns the direction in degrees. ## ## The @var{method} input argument must be a string specifying one of the ## methods supported by @code{imgradientxy}. ## ## @seealso{edge, imgradientxy} ## @end deftypefn function [gradMag, gradDir] = imgradient (img, method = "sobel") if (nargin < 1 || nargin > 2) print_usage (); elseif (ndims (img) != 2) error("imgradient: IMG must be a 2 dimensional matrix"); endif if (ischar (method)) [gradX, gradY] = imgradientxy (img, method); else ## we already got gX and gY, just confirm it's good data if (! size_equal (img, method)) error("imgradient: GX and GY must be of equal size") endif gradX = img; gradY = method; endif gradMag = sqrt (gradX.^2 + gradY.^2); if (nargout > 1) ## Why imgradient invert vertical when computing the angle ## Use atan2(-gy,gx)*pi/180. See http://stackoverflow.com/questions/18549015 gradDir = atan2d (-gradY, gradX); endif endfunction %!test %! A = [0 1 0 %! 1 1 1 %! 0 1 0]; %! %! [gMag, gDir] = imgradient (A); %! assert (gMag,[sqrt(18) 4 sqrt(18); 4 0 4; sqrt(18),4,sqrt(18)]); %! assert (gDir,[-45 -90 -135; -0 -0 -180; 45 90 135]); %! %! ## the following just test if passing gx and gy separately gets %! ## us the same as the image and method though imgradient %! [gxSobel, gySobel] = imgradientxy (A, "Sobel"); %! [gxPrewitt, gyPrewitt] = imgradientxy (A, "Prewitt"); %! [gxCd, gyCd] = imgradientxy (A, "CentralDifference"); %! [gxId, gyId] = imgradientxy (A, "IntermediateDifference"); %! %! assert (imgradient (A), %! imgradient (gxSobel, gySobel)); %! assert (imgradient (A, "Sobel"), %! imgradient (gxSobel, gySobel)); %! assert (imgradient (A, "Prewitt"), %! imgradient(gxPrewitt, gyPrewitt)); %! assert (imgradient (A, "CentralDifference"), %! imgradient (gxCd, gyCd)); %! assert (imgradient (A, "IntermediateDifference"), %! imgradient (gxId, gyId)); image-2.4.1/inst/PaxHeaders.6632/imshear.m0000644000000000000000000000013212561122761015043 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imshear.m0000644000175000017500000001020712561122761017666 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2002 Jeff Orchard ## ## 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 3 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} {} imshear (@var{M}, @var{axis}, @var{alpha}, @var{bbox}) ## Applies a shear to the image @var{M}. ## ## The argument @var{M} is either a matrix or an RGB image. ## ## @var{axis} is the axis along which the shear is to be applied, and can ## be either 'x' or 'y'. ## For example, to shear sideways is to shear along the 'x' axis. Choosing ## 'y' causes an up/down shearing. ## ## @var{alpha} is the slope of the shear. For an 'x' shear, it is the ## horizontal shift (in pixels) applied to the pixel above the ## center. For a 'y' shear, it is the vertical shift (in pixels) ## applied to the pixel just to the right of the center pixel. ## ## NOTE: @var{alpha} does NOT need to be an integer. ## ## @var{bbox} can be one of 'loose', 'crop' or 'wrap'. ## 'loose' allows the image to grow to accommodate the new transformed image. ## 'crop' keeps the same size as the original, clipping any part of the image ## that is moved outside the bounding box. ## 'wrap' keeps the same size as the original, but does not clip the part ## of the image that is outside the bounding box. Instead, it wraps it back ## into the image. ## ## If called with only 3 arguments, @var{bbox} is set to 'loose' by default. ## @end deftypefn function g = imshear(m, axis, alpha, bbox, noshift) # The code below only does y-shearing. This is because of # the implementation of fft (operates on columns, but not rows). # So, transpose first for x-shearing. if ( strcmp(axis, "x")==1 ) m = m'; endif if ( nargin < 4 ) bbox = "loose"; noshift = 0; elseif ( nargin < 5 ) noshift = 0; endif [ydim_orig xdim_orig] = size(m); if ( strcmp(bbox, "wrap") == 0 ) ypad = ceil( (xdim_orig+1)/2 * abs(alpha) ); m = padarray (m, ypad); endif [ydim_new xdim_new] = size(m); xcentre = ( xdim_new + 1 ) / 2; ycentre = ( ydim_new + 1 ) / 2; # This applies FFT to columns of m (x-axis remains a spatial axis). # Because the way that fft and fftshift are implemented, the origin # will move by 1/2 pixel, depending on the polarity of the image # dimensions. # # If dim is even (=2n), then the origin of the fft below is located # at the centre of pixel (n+1). ie. if dim=16, then centre is at 9. # # If dim is odd (=2n+1), then the origin of the fft below is located # at the centre of pixel (n). ie. if dim=15, then centre is at 8. if ( noshift==1 ) M = fft(m); else #M = imtranslate(fft(imtranslate(m, -xcentre, ycentre, "wrap")), xcentre, -ycentre, "wrap"); M = fftshift(fft(fftshift(m))); endif [ydim xdim] = size(m); x = zeros(ydim, xdim); # Find coords of the origin of the image. if ( noshift==1 ) xc_coord = 1; yc_coord = 1; l = (1:ydim)' - yc_coord; r = (1:xdim) - xc_coord; if ( strcmp(bbox, "wrap")==1 ) l((ydim/2):ydim) = l((ydim/2):ydim) - ydim; r((xdim/2):xdim) = r((xdim/2):xdim) - xdim; endif else xc_coord = (xdim+1)/2; yc_coord = (ydim+1)/2; l = (1:ydim)' - yc_coord; r = (1:xdim) - xc_coord; endif x = l * r; Ms = M.* exp(2*pi*I*alpha/ydim * x); if ( noshift==1 ) g = abs(ifft(Ms)); else #g = abs(imtranslate( ifft( imtranslate(Ms, -xcentre, ycentre, "wrap") ), xcentre, -ycentre, "wrap")); g = abs( fftshift(ifft(ifftshift(Ms))) ); endif if ( strcmp(bbox, "crop")==1 ) g = g(ypad+1:ydim_orig+ypad, :); endif # Un-transpose if x-shearing was wanted if ( strcmp(axis, "x")==1 ) g = g'; endif endfunction image-2.4.1/inst/PaxHeaders.6632/getrangefromclass.m0000644000000000000000000000013212561122761017121 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/getrangefromclass.m0000644000175000017500000000530512561122761021747 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011-2013 Carnë Draug ## ## 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 3 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{range} =} getrangefromclass (@var{img}) ## Return display range of image. ## ## For a given image @var{img}, returns the 1x2 element matrix @var{range} ## with the display range (minimum and maximum display values) for an ## image of that class. ## ## Images of different classes have different display ranges, the ranges ## of values that Octave will interpret between black to white. For an ## integer image, the range is from @code{intmin} to @code{intmax} of ## that class; for images of class logical, single, or double, the range ## is [0 1]. ## ## Note that @var{range} will be of class double, independently of the class ## of @var{img}. ## ## @example ## @group ## getrangefromclass (ones (5)) # note that class is 'double' ## @result{} [0 1] ## getrangefromclass (logical (ones (5))) ## @result{} [0 1] ## getrangefromclass (int8 (ones (5))) ## @result{} [-128 127] ## @end group ## @end example ## ## @seealso{intmin, intmax, bitmax} ## @end deftypefn function r = getrangefromclass (img) if (nargin != 1) print_usage (); elseif (! isimage (img)) error ("getrangefromclass: IMG must be an image"); endif cl = class (img); if (isinteger (img)) r = [intmin(cl) intmax(cl)]; elseif (any (strcmp (cl, {"single", "double", "logical"}))) r = [0 1]; else error ("getrangefromclass: unrecognized image class `%s'", cl) endif r = double (r); endfunction %!shared img %! img = ones (5); %!assert (getrangefromclass (double (img)), [0 1]); # double returns [0 1] %!assert (getrangefromclass (single (img)), [0 1]); # single returns [0 1] %!assert (getrangefromclass (logical (img)), [0 1]); # logical returns [0 1] %!assert (getrangefromclass (int8 (img)), [-128 127]); # checks int %!assert (getrangefromclass (uint8 (img)), [0 255]); # checks unit %!fail ("getrangefromclass ('string')"); # fails with strings %!fail ("getrangefromclass ({3, 4})"); # fails with cells image-2.4.1/inst/PaxHeaders.6632/iptcheckmap.m0000644000000000000000000000013212561122761015703 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/iptcheckmap.m0000644000175000017500000000454612561122761020537 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} iptcheckmap (@var{in}, @var{func_name}, @var{var_name}, @var{pos}) ## Check if argument is valid colormap. ## ## If @var{in} is not a valid colormap, gives a properly formatted error message. ## @var{func_name} is the name of the function to be used on the error message, ## @var{var_name} the name of the argument being checked (for the error message), ## and @var{pos} the position of the argument in the input. ## ## A valid colormap is a 2-D matrix with 3 columns of doubles with values between ## 0 and 1 (inclusive), that refer to the intensity levels of red, green and blue. ## ## @seealso{colormap} ## @end deftypefn function iptcheckmap (in, func_name, var_name, pos) if (nargin != 4) print_usage; elseif (!ischar (func_name)) error ("Argument func_name must be a string"); elseif (!ischar (var_name)) error ("Argument var_name must be a string"); elseif (!isnumeric (pos) || !isscalar (pos) || !isreal (pos) || pos <= 0 || rem (pos, 1) != 0) error ("Argument pos must be a real positive integer"); endif ## error ends in \n so the back trace of the error is not show. This is on ## purpose since the whole idea of this function is already to give a properly ## formatted error message if (!iscolormap (in)) error ("Function %s expected input number %d, %s, to be a valid colormap.\n\ Valid colormaps must be nonempty, double, 2-D matrices with 3 columns.\n", func_name, pos, var_name); endif endfunction %!test ("iptcheckmap (jet(64), 'func', 'var', 2)"); # simple must work %!fail ("iptcheckmap (3, 'func', 'var', 2)"); # not a colormap image-2.4.1/inst/PaxHeaders.6632/qtdecomp.m0000644000000000000000000000013212561122761015227 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/qtdecomp.m0000644000175000017500000002315712561122761020062 0ustar00carandraugcarandraug00000000000000## 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 3 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{S} =} qtdecomp (@var{I}) ## @deftypefnx {Function File} {@var{S} =} qtdecomp (@var{I}, @var{threshold}) ## @deftypefnx {Function File} {@var{S} =} qtdecomp (@var{I}, @var{threshold}, @var{mindim}) ## @deftypefnx {Function File} {@var{S} =} qtdecomp (@var{I}, @var{threshold}, [@var{mindim} @var{maxdim}]) ## @deftypefnx {Function File} {@var{S} =} qtdecomp (@var{I}, @var{fun}) ## @deftypefnx {Function File} {@var{S} =} qtdecomp (@var{I}, @var{fun}, @var{P1}, @var{P2}, @dots{}) ## Performs quadtree decomposition. ## ## qtdecomp decomposes a square image @var{I} into four equal-sized ## blocks. Then it performs some kind of test on each block to decide if ## it should decompose them further. This process is repeated ## iteratively until there's no block left to be decomposed. ## ## Note that blocks are not decomposed if their dimensions are not even. ## ## The output is a sparse matrix whose non-zero elements determine the ## position of the block (the element is at top-left position in the ## block) and size of each block (the value of the element determines ## length of a side of the square-shaped block). ## ## S = qtdecomp(I) decomposes an intensity image @var{I} as described ## above. By default it doesn't split a block if all elements are equal. ## ## S = qtdecomp(I, threshold) decomposes an image as described, but only ## splits a block if the maximum value in the block minus the minimum ## value is greater than @var{threshold}, which is a value between 0 and ## 1. If @var{I} is of class uint8, @var{threshold} is multiplied by 255 ## before use. Also, if@var{I} is of class uint16, @var{threshold} is ## multiplied by 65535. ## ## S = qtdecomp(I, threshold, mindim) decomposes an image using the ## @var{threshold} as just described, but doesn't produce blocks smaller ## than mindim. ## ## S = qtdecomp(I, threshold, [mindim maxdim]) decomposes an image as ## described, but produces blocks that can't be bigger than maxdim. It ## decomposes to maxdim even if it isn't needed if only @var{threshold} ## was considered. ## ## S = qtdecomp(I, fun) decomposes an image @var{I} and uses function ## @var{fun} to decide if a block should be splitted or not. @var{fun} ## is called with a m-by-m-by-k array of m-by-m blocks to be ## considered, and should return a vector of size k, whose elements ## represent each block in the stacked array. @var{fun} sets the ## corresponding value to 1 if the block should be split, and 0 ## otherwise. ## ## S = qtdecomp(I, fun, @dots{}) behaves as qtdecomp(I, fun) but passes ## extra parameters to @var{fun}. ## ## @seealso{qtgetblk, qtsetblk} ## @end deftypefn function S = qtdecomp (I, p1, varargin) if (nargin < 1) print_usage; elseif (! issquare (I)) error("qtdecomp: I should be square."); endif ## current size (assumed to be square) curr_size=size(I,1); ## initial mindim to a sensible value mindim=1; ## sensible default maxdim value maxdim=curr_size; if (nargin<2) ## Initialize decision method variable ## We could have implemented threshold as a function and use an ## uniform interface (function handle) to decide whether to split or ## not blocks. We have decided not to do so because block ## rearrangement that is needed as a parameter to functions is ## expensive. decision_method=0; elseif (isreal(p1)) ## p1 is threshold threshold=p1; decision_method=1; if(strcmp(typeinfo(I), 'uint8 matrix')) threshold*=255; elseif(strcmp(typeinfo(I), 'uint16 matrix')) threshold*=65535; endif if (nargin>3) print_usage; elseif (nargin==3) dims=varargin{1}; if (isvector(dims)&&length(dims)==2) mindim=dims(1); maxdim=dims(2); elseif (isreal(dims)) mindim=dims; else error("qtdecomp: third parameter must be 'mindim' or '[mindim maxdim]'"); endif ## we won't check if mindim or maxdim are powers of 2. It's too ## restrictive and don't need it at all. endif elseif strcmp(typeinfo(p1),"function handle") ... || strcmp(typeinfo(p1),"inline function") ## function handles seem to return true to isscalar fun=p1; decision_method=2; else error("qtdecomp: second parameter must be a integer (threshold) or a function handle (fun)."); endif ## initialize results matrices res=[]; ## bool to flag end finished=false; ## array of offsets to blocks to evaluate offsets=[1,1]; if (maxdim0) divs=2^initial_splits; if (rem(curr_size,divs)!=0) error("qtdecomp: Can't decompose I enough times to fulfill maxdim requirement."); endif ## update curr_size curr_size/=divs; if(curr_size0) ## check other ending conditions: ## is size is odd? ## is splitted size < than mindim? if ((rem(curr_size,2)!=0)||((curr_size/2) ## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} imresize (@var{im}, @var{scale}) ## @deftypefnx {Function File} {} imresize (@var{im}, [@var{M} @var{N}]) ## @deftypefnx {Function File} {} imresize (@dots{}, @var{method}) ## Resize image with interpolation ## ## Scales the image @var{im} by a factor @var{scale} or into the size @var{M} ## rows by @var{N} columns. For example: ## ## @example ## @group ## imresize (im, 1); # return the same image as input ## imresize (im, 1.5); # return image 1.5 times larger ## imresize (im, 0.5); # return image with half the size ## imresize (im, 2); # return image with the double size ## imresize (im, [512 610]); # return image of size 512x610 ## @end group ## @end example ## ## If @var{M} or @var{N} is @code{NaN}, it will be determined automatically so ## as to preserve aspect ratio. ## ## The optional argument @var{method} defines the interpolation method to be ## used. All methods supported by @code{interp2} can be used. By default, the ## @code{cubic} method is used. ## ## For @sc{matlab} compatibility, the methods @code{bicubic} (same as ## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as ## @code{linear}) are also supported. ## ## @table @asis ## @item bicubic (default) ## Same as @code{cubic}. ## ## @item bilinear ## Same as @code{linear}. ## ## @item triangle ## Same as @code{linear}. ## @end table ## ## @seealso{imremap, imrotate, interp2} ## @end deftypefn function im = imresize (im, scale, method = "cubic") if (nargin < 2 || nargin > 3) print_usage (); elseif (! isimage (im) || (! isrgb (im) && ! isgray (im))) error ("imresize: IM must be a grayscale or RGB image.") elseif (! isnumeric (scale) || any (scale <= 0) || all (isnan (scale))) error ("imresize: SCALE or [M N] must be numeric positive values") elseif (! ischar (method)) error ("imresize: METHOD must be a string with interpolation method") endif method = interp_method (method); inRows = rows (im); inCols = columns (im); ## we may be able to use clever indexing instead of interpolation int_row_scale = false; int_col_scale = false; if (isscalar (scale)) outRows = ceil (rows (im) * scale); outCols = ceil (columns (im) * scale); ## check if we can use clever indexing scale_rows = scale_cols = scale; int_row_scale = int_col_scale = is_for_integer (scale); elseif (numel (scale) == 2) outRows = scale(1); outCols = scale(2); ## maintain aspect ratio if requested if (isnan (outRows)) outRows = inRows * (outCols / inCols); elseif (isnan (outCols)) outCols = inCols * (outRows / inRows); endif outRows = ceil (outRows); outCols = ceil (outCols); ## we will need this to use clever indexing. In this case, we will also need ## to check that we are changing the rows and columns of the image in the ## same direction scale_rows = (outRows/inRows); scale_cols = (outCols/inCols); int_row_scale = is_for_integer (scale_rows); int_col_scale = is_for_integer (scale_cols); else error ("imresize: SCALE argument must be a scalar or a 2 element vector"); end ## Perform the actual resizing if (inRows == outRows && inCols == outCols) ## no resizing to do elseif (strcmpi (method, "nearest") && all ([int_row_scale int_col_scale])) ## we are matlab incompatible here on purpose. We can the stuff here in 2 ## ways. With interp2 or by clever indexing. Indexing is much much faster ## than interp2 but they return different results (the way we are doing it ## at least). Matlab does the same as we are doing if the both columns and ## rows go the same direction but if they increase one and decrease the ## other, then they return the same as if we were using interp2. We are ## smarter and use indexing even in that case but then the results differ if (int_row_scale == 1) row_idx = (1:rows (im))(ones (1, scale_rows), :); elseif (int_row_scale == -1) row_idx = ceil (linspace (floor (1/(scale_rows * 2)) + 1, inRows, outRows)); endif if (int_col_scale == 1) col_idx = (1:columns (im))(ones (scale_cols, 1), :); elseif (int_col_scale == -1) col_idx = ceil (linspace (floor (1/(scale_cols * 2)) + 1, inCols, outCols)); endif im = im(row_idx, col_idx); else [XI, YI] = meshgrid (linspace (1, inCols, outCols), linspace (1, inRows, outRows)); im = imremap (im, XI, YI, method); endif endfunction function retval = is_for_integer (scale) retval = false; if (fix (scale) == scale) retval = 1; elseif (fix (1/scale) == (1/scale)) ## if scale/n is an integer then we are resizing to one half, one third, etc ## and we can also use clever indexing retval = -1; endif endfunction %!test %! in = [116 227 153 69 146 194 59 130 139 106 %! 2 47 137 249 90 75 16 24 158 44 %! 155 68 46 84 166 156 69 204 32 152 %! 71 221 137 230 210 153 192 115 30 118 %! 107 143 108 52 51 73 101 21 175 90 %! 54 158 143 77 26 168 113 229 165 225 %! 9 47 133 135 130 207 236 43 19 73]; %! assert (imresize (uint8 (in), 1, "nearest"), uint8 (in)) %! assert (imresize (uint8 (in), 1, "bicubic"), uint8 (in)) %! %! out = [116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 %! 116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 %! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 %! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 %! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 %! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 %! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 %! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 %! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 %! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 %! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 %! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 %! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73 %! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73]; %! assert (imresize (uint8 (in), 2, "nearest"), uint8 (out)) %! assert (imresize (uint8 (in), 2, "neAreST"), uint8 (out)) %! assert (imresize (uint8 (in), [14 NaN], "nearest"), uint8 (out)) %! assert (imresize (uint8 (in), [NaN 20], "nearest"), uint8 (out)) %! %! out = [116 116 227 227 153 153 69 69 146 146 194 194 59 59 130 130 139 139 106 106 %! 2 2 47 47 137 137 249 249 90 90 75 75 16 16 24 24 158 158 44 44 %! 155 155 68 68 46 46 84 84 166 166 156 156 69 69 204 204 32 32 152 152 %! 71 71 221 221 137 137 230 230 210 210 153 153 192 192 115 115 30 30 118 118 %! 107 107 143 143 108 108 52 52 51 51 73 73 101 101 21 21 175 175 90 90 %! 54 54 158 158 143 143 77 77 26 26 168 168 113 113 229 229 165 165 225 225 %! 9 9 47 47 133 133 135 135 130 130 207 207 236 236 43 43 19 19 73 73]; %! assert (imresize (uint8 (in), [7 20], "nearest"), uint8 (out)) %! %! assert (imresize (uint8 (in), 1.5, "bicubic"), imresize (uint8 (in), 1.5, "cubic")) %! assert (imresize (uint8 (in), [NaN, size(in,2)*1.5], "bicubic"), imresize (uint8 (in), 1.5, "cubic")) %! assert (imresize (uint8 (in), [size(in,1)*1.5, NaN], "bicubic"), imresize (uint8 (in), 1.5, "cubic")) %! assert (imresize (uint8 (in), 1.5, "linear"), imresize (uint8 (in), 1.5, "LIneAR")) %! assert (imresize (uint8 (in), 1.5, "linear"), imresize (uint8 (in), 1.5, "triangle")) %! %! out = [ 47 249 75 24 44 %! 221 230 153 115 118 %! 158 77 168 229 225 %! 47 135 207 43 73]; %! assert (imresize (uint8 (in), 0.5, "nearest"), uint8 (out)) ## The following are the matlab results. We have slighlty different results but ## not by much. If there's would be any fixes, they would have to be on interp2 ## or maybe in imremap. %!shared in, out %! in = [116 227 153 69 146 194 59 130 139 106 %! 2 47 137 249 90 75 16 24 158 44 %! 155 68 46 84 166 156 69 204 32 152 %! 71 221 137 230 210 153 192 115 30 118 %! 107 143 108 52 51 73 101 21 175 90 %! 54 158 143 77 26 168 113 229 165 225 %! 9 47 133 135 130 207 236 43 19 73]; %! %! out = [116 185 235 171 96 64 134 189 186 74 90 141 140 124 108 %! 44 92 143 149 164 163 119 123 118 44 38 80 151 118 63 %! 14 21 47 107 195 228 115 81 70 24 19 56 137 105 49 %! 145 98 49 49 71 107 148 159 132 58 124 176 61 85 145 %! 118 139 144 92 116 168 201 188 159 140 167 158 27 69 152 %! 62 151 218 145 174 219 201 164 146 187 148 84 48 76 115 %! 102 132 151 119 90 72 72 72 83 114 60 31 144 130 81 %! 82 121 154 133 87 41 19 67 116 95 108 140 183 180 164 %! 40 96 152 149 117 74 34 108 179 131 175 215 153 177 219 %! 11 33 73 127 137 125 113 158 212 229 148 55 35 63 96 %! 4 17 53 121 141 138 133 171 220 253 141 16 7 36 67]; %!xtest assert (imresize (uint8 (in), 1.5, "bicubic"), uint8 (out)) %! %! out = [116 172 215 165 111 82 133 170 171 81 95 132 138 123 106 %! 59 98 138 144 152 152 125 127 119 54 58 89 137 112 75 %! 27 39 62 110 172 202 123 96 78 36 40 68 123 100 62 %! 129 97 64 62 87 119 146 148 128 74 117 154 73 94 134 %! 113 129 136 101 125 162 183 172 151 135 146 139 53 83 135 %! 77 143 195 145 166 197 186 162 146 171 138 92 62 84 113 %! 101 129 149 120 98 81 78 82 91 111 77 56 132 123 95 %! 81 116 147 130 96 61 43 80 119 109 116 132 162 164 158 %! 46 93 139 141 114 80 50 109 168 141 166 189 151 171 200 %! 16 41 77 123 130 123 115 157 204 214 145 69 48 71 98 %! 9 28 61 119 134 134 131 169 212 231 140 39 23 46 73]; %!xtest assert (imresize (uint8 (in), 1.5, "bilinear"), uint8 (out)) %! %! out = [108 136 125 89 107 %! 111 132 143 114 99 %! 106 110 106 127 136 %! 47 121 163 138 68]; %!xtest assert (imresize (uint8 (in), 0.5, "bilinear"), uint8 (out)) %! %! out = [103 141 124 78 110 %! 111 134 153 114 91 %! 115 108 93 128 146 %! 38 124 175 143 54]; %!xtest assert (imresize (uint8 (in), 0.5, "bicubic"), uint8 (out)) image-2.4.1/inst/PaxHeaders.6632/bweuler.m0000644000000000000000000000013212561122761015060 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bweuler.m0000644000175000017500000000643012561122761017706 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2004 Josep Mones i Teixidor ## Copyright (C) 2011 Adrián del Pino ## ## 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 3 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{eul} = } bweuler (@var{BW}, @var{n}) ## Calculate the Euler number of a binary image. ## ## This function calculates the Euler number @var{eul} of a binary ## image @var{BW}. This number is a scalar whose value represents the total ## number of objects in @var{BW} minus the number of holes. ## ## @var{n} is an optional argument that specifies the neighbourhood ## connectivity. Must either be 4 or 8. If omitted, defaults to 8. ## ## This function uses Bit Quads as described in "Digital Image ## Processing" to calculate euler number. ## ## References: ## W. K. Pratt, "Digital Image Processing", 3rd Edition, pp 593-595 ## ## @seealso{bwmorph, bwperim, qtgetblk} ## @end deftypefn function eul = bweuler (BW, n = 8) if (nargin < 1 || nargin > 2) print_usage; elseif (!isbw (BW, "non-logical")) error("first argument must be a Black and White image"); endif ## lut_4=(q1lut-q3lut+2*qdlut)/4; # everything in one lut will be quicker ## lut_8=(q1lut-q3lut-2*qdlut)/4; # but only the final result is divided by four ## we precalculate this... # to save more time if (!isnumeric (n) || !isscalar (n) || (n != 8 && n != 4)) error("second argument must either be 4 or 8"); elseif (n == 8) lut = [0; 1; 1; 0; 1; 0; -2; -1; 1; -2; 0; -1; 0; -1; -1; 0]; elseif (n == 4) lut = [0; 1; 1; 0; 1; 0; 2; -1; 1; 2; 0; -1; 0; -1; -1; 0]; endif ## Adding zeros to the top and left bordes to avoid errors when figures touch these borders. ## Notice that 1 0 is equivalent to 1 0 0 because there are implicit zeros in the bottom and right ## 0 1 0 1 0 ## 0 0 0 ## borders. Therefore, there are three one-pixel and one diagonal pixels. So, we get 3 * 1 - 2 = 1 ## (error) instead of 6 * 1 - 2 = 4 (correct). BWaux = zeros (rows (BW) + 1, columns (BW) + 1); for r = 1 : rows(BW) for c = 1 : columns (BW) BWaux (r + 1, c + 1) = BW (r, c); endfor endfor eul = sum (applylut (BWaux, lut) (:)) / 4; endfunction %!demo %! A=zeros(9,10); %! A([2,5,8],2:9)=1; %! A(2:8,[2,9])=1 %! bweuler(A) %! # Euler number (objects minus holes) is 1-2=-1 in an 8-like object %!test %! A=zeros(10,10); %! A(2:9,3:8)=1; %! A(4,4)=0; %! A(8,8)=0; # not a hole %! A(6,6)=0; %! assert(bweuler(A),-1); %!# This will test if n=4 and n=8 behave differently %!test %! A=zeros(10,10); %! A(2:4,2:4)=1; %! A(5:8,5:8)=1; %! assert(bweuler(A,4),2); %! assert(bweuler(A,8),1); %! assert(bweuler(A),1); image-2.4.1/inst/PaxHeaders.6632/entropy.m0000644000000000000000000000013212561122761015113 xustar0030 mtime=1438950897.726252238 30 atime=1438950897.726252238 30 ctime=1438950899.342252237 image-2.4.1/inst/entropy.m0000644000175000017500000000404012561122761017734 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{E} =} entropy (@var{im}) ## @deftypefnx{Function File} {@var{E} =} entropy (@var{im}, @var{nbins}) ## Computes the entropy of an image. ## ## The entropy of the elements of the image @var{im} is computed as ## ## @example ## @var{E} = -sum (@var{P} .* log2 (@var{P}) ## @end example ## ## where @var{P} is the distribution of the elements of @var{im}. The distribution ## is approximated using a histogram with @var{nbins} cells. If @var{im} is ## @code{logical} then two cells are used by default. For other classes 256 cells ## are used by default. ## ## When the entropy is computed, zero-valued cells of the histogram are ignored. ## ## @seealso{entropyfilt} ## @end deftypefn function retval = entropy (I, nbins = 0) ## Check input if (nargin == 0) error ("entropy: not enough input arguments"); endif if (! isnumeric (I)) error ("entropy: I must be numeric"); endif if (!isscalar (nbins)) error ("entropy: second input argument must be a scalar"); endif ## Get number of histogram bins if (nbins <= 0) if (islogical (I)) nbins = 2; else nbins = 256; endif endif ## Compute histogram P = hist (I (:), nbins, true); ## Compute entropy (ignoring zero-entries of the histogram) P += (P == 0); retval = -sum (P .* log2 (P)); endfunction image-2.4.1/inst/PaxHeaders.6632/fspecial.m0000644000000000000000000000013212561122761015201 xustar0030 mtime=1438950897.734252238 30 atime=1438950897.734252238 30 ctime=1438950899.342252237 image-2.4.1/inst/fspecial.m0000644000175000017500000003024312561122761020026 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2005 Søren Hauberg ## ## 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 3 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} {} fspecial(@var{type}, @var{arg1}, @var{arg2}) ## Create spatial filters for image processing. ## ## @var{type} determines the shape of the filter and can be ## @table @asis ## @item @qcode{"average"} ## Rectangular averaging filter. The optional argument @var{arg1} controls the ## size of the filter. If @var{arg1} is an integer @var{N}, a @var{N} by @var{N} ## filter is created. If it is a two-vector with elements @var{N} and @var{M}, the ## resulting filter will be @var{N} by @var{M}. By default a 3 by 3 filter is ## created. ## ## @item @qcode{"disk"} ## Circular averaging filter. The optional argument @var{arg1} controls the ## radius of the filter. If @var{arg1} is an integer @var{R}, a 2 @var{R} + 1 ## filter is created. By default a radius of 5 is used. If the returned matrix ## corresponds to a cartesian grid, each element of the matrix is weighted by ## how much of the corresponding grid square is covered by a disk of radius ## @var{R} and centered at the middle of the element @var{R}+1,@var{R}+1. ## ## @item @qcode{"gaussian"} ## Gaussian filter. The optional argument @var{arg1} controls the size of the ## filter. If @var{arg1} is an integer @var{N}, a @var{N} by @var{N} ## filter is created. If it is a two-vector with elements @var{N} and @var{M}, the ## resulting filter will be @var{N} by @var{M}. By default a 3 by 3 filter is ## created. The optional argument @var{arg2} sets spread of the filter. By default ## a spread of @math{0.5} is used. ## ## @item @qcode{"log"} ## Laplacian of Gaussian. The optional argument @var{arg1} controls the size of the ## filter. If @var{arg1} is an integer @var{N}, a @var{N} by @var{N} ## filter is created. If it is a two-vector with elements @var{N} and @var{M}, the ## resulting filter will be @var{N} by @var{M}. By default a 5 by 5 filter is ## created. The optional argument @var{arg2} sets spread of the filter. By default ## a spread of @math{0.5} is used. ## ## @item @qcode{"laplacian"} ## 3x3 approximation of the laplacian. The filter is approximated as ## ## @example ## (4/(@var{alpha}+1)) * [ @var{alpha}/4 (1-@var{alpha})/4 @var{alpha}/4 ## (1-@var{alpha})/4 -1 (1-@var{alpha})/4 ## @var{alpha}/4 (1-@var{alpha})/4 @var{alpha}/4 ]; ## @end example ## ## where @var{alpha} is a number between 0 and 1. This number can be controlled ## via the optional input argument @var{arg1}. By default it is @math{0.2}. ## ## @item @qcode{"unsharp"} ## Sharpening filter. The following filter is returned ## @example ## (1/(@var{alpha}+1)) * [-@var{alpha} @var{alpha}-1 -@var{alpha} ## @var{alpha}-1 @var{alpha}+5 @var{alpha}-1 ## -@var{alpha} @var{alpha}-1 -@var{alpha}]; ## @end example ## ## where @var{alpha} is a number between 0 and 1. This number can be controlled ## via the optional input argument @var{arg1}. By default it is @math{0.2}. ## ## @item @qcode{"motion"} ## Moion blur filter of width 1 pixel. The optional input argument @var{arg1} ## controls the length of the filter, which by default is 9. The argument @var{arg2} ## controls the angle of the filter, which by default is 0 degrees. ## ## @item @qcode{"sobel"} ## Horizontal Sobel edge filter. The following filter is returned ## ## @example ## [ 1 2 1 ## 0 0 0 ## -1 -2 -1 ] ## @end example ## ## @item @qcode{"prewitt"} ## Horizontal Prewitt edge filter. The following filter is returned ## ## @example ## [ 1 1 1 ## 0 0 0 ## -1 -1 -1 ] ## @end example ## ## @item "kirsch" ## Horizontal Kirsch edge filter. The following filter is returned ## ## @verbatim ## [ 3 3 3 ## 3 0 3 ## -5 -5 -5 ] ## @end verbatim ## @end table ## ## @seealso{conv2, convn, filter2, imfilter} ## @end deftypefn ## Remarks by Søren Hauberg (jan. 2nd 2007) ## The motion filter and most of the documentation was taken from Peter Kovesi's ## GPL'ed implementation of fspecial from ## http://www.csse.uwa.edu.au/~pk/research/matlabfns/OctaveCode/fspecial.m function f = fspecial (type, arg1, arg2) if (nargin < 1) print_usage (); elseif (! ischar (type)) error ("fspecial: first argument must be a string"); endif switch lower (type) case "average" ## Get filtersize if (nargin > 1 && isreal (arg1) && length (arg1 (:)) <= 2) fsize = arg1 (:); else fsize = 3; endif ## Create the filter f = ones (fsize); ## Normalize the filter to integral 1 f = f / sum (f (:)); case "disk" ## Get the radius if (nargin > 1 && isreal (arg1) && isscalar (arg1)) r = arg1; else r = 5; endif ## Create the filter if (r == 0) f = 1; else ax = r + 1; # index of the "x-axis" and "y-axis" corner = floor (r / sqrt (2)+0.5)-0.5; # corner corresponding to 45 degrees rsq = r*r; ## First set values for points completely covered by the disk [X, Y] = meshgrid (-r:r, -r:r); rhi = (abs (X) +0.5).^2 + (abs (Y)+0.5).^2; f = (rhi <= rsq) / 1.0; xx = linspace (0.5, r - 0.5, r); ii = sqrt (rsq - xx.^2); # intersection points for sqrt (r^2 - x^2) ## Set the values at the axis caps tmp = sqrt (rsq -0.25); rint = (0.5*tmp + rsq * atan (0.5/tmp))/2; # value of integral on the right cap = 2*rint - r+0.5; # at the caps, lint = rint f(ax ,ax+r) = cap; f(ax ,ax-r) = cap; f(ax+r,ax ) = cap; f(ax-r,ax ) = cap; if (r == 1) y = ii(1); lint = rint; tmp = sqrt (rsq - y^2); rint = (y*tmp + rsq * atan (y/tmp))/2; val = rint - lint - 0.5 * (y-0.5); f(ax-r,ax-r) = val; f(ax+r,ax-r) = val; f(ax-r,ax+r) = val; f(ax+r,ax+r) = val; else ## Set the values elsewhere on the rim idx = 1; # index in the vector ii x = 0.5; # bottom left corner of the current square y = r-0.5; rx = 0.5; # x on the right of the integrable region ybreak = false; # did we change our y last time do i = x +0.5; j = y +0.5; lint = rint; lx = rx; if (ybreak) ybreak = false; val = lx-x; idx++; x++; rx = x; val -= y*(x-lx); elseif (ii(idx+1) < y) ybreak = true; y--; rx = ii(y+1.5); val = (y+1) * (x-rx); else val = -y; idx++; x++; rx = x; if (floor (ii(idx)-0.5) == y) y++; endif endif tmp = sqrt (rsq - rx*rx); rint = (rx*tmp + rsq * atan (rx/tmp))/2; val += rint - lint; f(ax+i, ax+j) = val; f(ax+i, ax-j) = val; f(ax-i, ax+j) = val; f(ax-i, ax-j) = val; f(ax+j, ax+i) = val; f(ax+j, ax-i) = val; f(ax-j, ax+i) = val; f(ax-j, ax-i) = val; until (y < corner || x > corner) endif # Normalize f /= pi * rsq; endif case "gaussian" ## Get hsize if (nargin > 1 && isreal (arg1)) if (length (arg1 (:)) == 1) hsize = [arg1, arg1]; elseif (length (arg1 (:)) == 2) hsize = arg1; else error ("fspecial: second argument must be a scalar or a vector of two scalars"); endif else hsize = [3, 3]; endif ## Get sigma if (nargin > 2 && isreal (arg2) && length (arg2 (:)) == 1) sigma = arg2; else sigma = 0.5; endif h1 = hsize (1)-1; h2 = hsize (2)-1; [x, y] = meshgrid(0:h2, 0:h1); x = x-h2/2; y = y-h1/2; gauss = exp( -( x.^2 + y.^2 ) / (2*sigma^2) ); f = gauss / sum (gauss (:)); case "laplacian" ## Get alpha if (nargin > 1 && isscalar (arg1)) alpha = arg1; if (alpha < 0 || alpha > 1) error ("fspecial: second argument must be between 0 and 1"); endif else alpha = 0.2; endif ## Compute filter f = (4/(alpha+1))*[alpha/4, (1-alpha)/4, alpha/4; ... (1-alpha)/4, -1, (1-alpha)/4; ... alpha/4, (1-alpha)/4, alpha/4]; case "log" ## Get hsize if (nargin > 1 && isreal (arg1)) if (length (arg1 (:)) == 1) hsize = [arg1, arg1]; elseif (length (arg1 (:)) == 2) hsize = arg1; else error ("fspecial: second argument must be a scalar or a vector of two scalars"); endif else hsize = [5, 5]; endif ## Get sigma if (nargin > 2 && isreal (arg2) && length (arg2 (:)) == 1) sigma = arg2; else sigma = 0.5; endif ## Compute the filter h1 = hsize (1)-1; h2 = hsize (2)-1; [x, y] = meshgrid(0:h2, 0:h1); x = x-h2/2; y = y = y-h1/2; gauss = exp( -( x.^2 + y.^2 ) / (2*sigma^2) ); f = ( (x.^2 + y.^2 - 2*sigma^2).*gauss )/( 2*pi*sigma^6*sum(gauss(:)) ); case "motion" ## Taken (with some changes) from Peter Kovesis implementation ## (http://www.csse.uwa.edu.au/~pk/research/matlabfns/OctaveCode/fspecial.m) ## FIXME: The implementation is not quite matlab compatible. if (nargin > 1 && isreal (arg1)) len = arg1; else len = 9; endif if (mod (len, 2) == 1) sze = [len, len]; else sze = [len+1, len+1]; end if (nargin > 2 && isreal (arg2)) angle = arg2; else angle = 0; endif ## First generate a horizontal line across the middle f = zeros (sze); f (floor (len/2)+1, 1:len) = 1; # Then rotate to specified angle f = imrotate (f, angle, "bilinear", "loose"); f = f / sum (f (:)); case "prewitt" ## The filter f = [1, 1, 1; 0, 0, 0; -1, -1, -1]; case "sobel" ## The filter f = [1, 2, 1; 0, 0, 0; -1, -2, -1]; case "kirsch" ## The filter f = [3, 3, 3; 3, 0, 3; -5, -5, -5]; case "unsharp" ## Get alpha if (nargin > 1 && isscalar (arg1)) alpha = arg1; if (alpha < 0 || alpha > 1) error ("fspecial: second argument must be between 0 and 1"); endif else alpha = 0.2; endif ## Compute filter f = (1/(alpha+1))*[-alpha, alpha-1, -alpha; ... alpha-1, alpha+5, alpha-1; ... -alpha, alpha-1, -alpha]; otherwise error ("fspecial: filter type '%s' is not supported", type); endswitch endfunction ## Test that the disk filter's error does not grow unreasonably large %!test %! for i = 1:9 %! n = 2^i; %! assert (sum (fspecial ("disk", n)(:)), 1, eps*n*n); %! endfor ## Test that all squares completely under the disk or completely out of it are ## being assigned the correct values. %!test %! for r = [3 5 9 17] %! f = fspecial ("disk", r); %! [X, Y] = meshgrid (-r:r, -r:r); %! rhi = (abs (X) + 0.5).^2 + (abs (Y) + 0.5).^2; %! rlo = (abs (X) - 0.5).^2 + (abs (Y) - 0.5).^2; %! fhi = (rhi <= (r^2)); %! flo = (rlo >= (r^2)); %! for i = 1:(2*r+1) %! for j = 1:(2*r+1) %! if (fhi(i,j)) %! assert (f(i,j), 1/(pi*r^2), eps); %! endif %! if (flo(i,j)) %! assert (f(i,j), 0); %! endif %! endfor %! endfor %! endfor image-2.4.1/inst/PaxHeaders.6632/findbounds.m0000644000000000000000000000013212561122761015546 xustar0030 mtime=1438950897.734252238 30 atime=1438950897.734252238 30 ctime=1438950899.342252237 image-2.4.1/inst/findbounds.m0000644000175000017500000000541012561122761020371 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{outbnd} =} findbounds (@var{T}, @var{inbnd}) ## Estimate bounds for spatial transformation. ## ## Given a transformation structure @var{T} (see e.g. maketform) ## and bounds @var{inbnd} (2-by-ndims_in) in an input space, returns ## an estimation of the bounds in the output space @var{outbnd} ## (2-by-ndims_out). For instance two dimensionnal bounds could ## be represented as : [xmin ymin; xmax ymax]. If @var{T} does not ## define a forward transform (i.e. for 'polynomial'), the output ## bounds are infered using fsolve and the inverse transform. ## ## @seealso{maketform, cp2tform, tformfwd} ## @end deftypefn ## Author: Pantxo Diribarne function [outbnd] = findbounds (T, inbnd) if (nargin != 2) print_usage (); elseif (! istform (T)) error ("imtransform: T must be a transformation structure (see `maketform')"); elseif (! all (size (inbnd) == [2 T.ndims_in])) error ("imtransform: INBDN must have same size as T.ndims_in"); endif ## Control points grid if (columns (inbnd) == 2) [xcp, ycp] = meshgrid (linspace (inbnd(1,1), inbnd(2,1), 3), linspace (inbnd(1,2), inbnd(2,2), 3)); xcp = reshape (xcp, numel (xcp), 1); ycp = reshape (ycp, numel (ycp), 1); xycp = [xcp, ycp]; else error ("findbounds: support only 2D inputbounds."); endif ## Output bounds if (!is_function_handle (T.forward_fcn)) outbnd = zeros (size (xycp)); for ii = 1:rows (xycp) fun = @(x) tforminv (T, x) - xycp(ii,:); outbnd(ii,:) = fsolve (fun, xycp(ii,:)); endfor else outbnd = tformfwd (T, xycp); endif outbnd = [min(outbnd); max(outbnd)]; endfunction %!test %! im = checkerboard (); %! theta = pi/6; %! T = maketform ('affine', [cos(theta) -sin(theta); ... %! sin(theta) cos(theta); 0 0]); %! inbnd = [0 0; 1 1]; %! outbnd = findbounds (T, inbnd); %! diag = 2^.5; %! ang = pi/4; %! assert (diff (outbnd(:,1)), diag * abs (cos (theta - ang)), eps) %! assert (diff (outbnd(:,2)), diag * abs (cos (theta - ang)), eps) image-2.4.1/inst/PaxHeaders.6632/imrotate.m0000644000000000000000000000013212561122761015237 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imrotate.m0000644000175000017500000003241012561122761020062 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2002 Jeff Orchard ## Copyright (C) 2004-2005 Justus H. Piater ## ## 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 3 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} {} imrotate (@var{imgPre}, @var{theta}, @var{method}, @var{bbox}, @var{extrapval}) ## Rotate image about its center. ## ## Input parameters: ## ## @var{imgPre} a gray-level image matrix ## ## @var{theta} the rotation angle in degrees counterclockwise ## ## The optional argument @var{method} defines the interpolation method to be ## used. All methods supported by @code{interp2} can be used. In addition, ## Fourier interpolation by decomposing the rotation matrix into 3 shears can ## be used with the @code{fourier} method. By default, the @code{nearest} method ## is used. ## ## For @sc{matlab} compatibility, the methods @code{bicubic} (same as ## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as ## @code{linear}) are also supported. ## ## @var{bbox} ## @itemize @w ## @item "loose" grows the image to accommodate the rotated image (default). ## @item "crop" rotates the image about its center, clipping any part of the image that is moved outside its boundaries. ## @end itemize ## ## @var{extrapval} sets the value used for extrapolation. The default value ## is 0. This argument is ignored of Fourier interpolation is used. ## ## Output parameters: ## ## @var{imgPost} the rotated image matrix ## ## @var{H} the homography mapping original to rotated pixel ## coordinates. To map a coordinate vector c = [x;y] to its ## rotated location, compute round((@var{H} * [c; 1])(1:2)). ## ## @var{valid} a binary matrix describing which pixels are valid, ## and which pixels are extrapolated. This output is ## not available if Fourier interpolation is used. ## @end deftypefn function [imgPost, H, valid] = imrotate (imgPre, thetaDeg, interp = "nearest", bbox = "loose", extrapval = 0) if (nargin < 2 || nargin > 5) print_usage (); elseif (! isimage (imgPre)) error ("imrotate: IMGPRE must be a grayscale or RGB image.") elseif (! isscalar (thetaDeg)) error("imrotate: THETA must be a scalar"); elseif (! ischar (interp)) error("imrotate: interpolation METHOD must be a character array"); elseif (! isscalar (extrapval)) error("imrotate: EXTRAPVAL must be a scalar"); elseif (! ischar (bbox) || ! any (strcmpi (bbox, {"loose", "crop"}))) error("imrotate: BBOX must be 'loose' or 'crop'"); endif interp = interp_method (interp); ## Input checking done. Start working thetaDeg = mod(thetaDeg, 360); # some code below relies on positive angles theta = thetaDeg * pi/180; sizePre = size(imgPre); ## We think in x,y coordinates here (rather than row,column), except ## for size... variables that follow the usual size() convention. The ## coordinate system is aligned with the pixel centers. R = [cos(theta) sin(theta); -sin(theta) cos(theta)]; if (nargin >= 4 && strcmpi(bbox, "crop")) sizePost = sizePre; else ## Compute new size by projecting zero-base image corner pixel ## coordinates through the rotation: corners = [0, 0; (R * [sizePre(2) - 1; 0 ])'; (R * [sizePre(2) - 1; sizePre(1) - 1])'; (R * [0 ; sizePre(1) - 1])' ]; sizePost(2) = round(max(corners(:,1)) - min(corners(:,1))) + 1; sizePost(1) = round(max(corners(:,2)) - min(corners(:,2))) + 1; ## This size computation yields perfect results for 0-degree (mod ## 90) rotations and, together with the computation of the center of ## rotation below, yields an image whose corresponding region is ## identical to "crop". However, we may lose a boundary of a ## fractional pixel for general angles. endif ## Compute the center of rotation and the translational part of the ## homography: oPre = ([ sizePre(2); sizePre(1)] + 1) / 2; oPost = ([sizePost(2); sizePost(1)] + 1) / 2; T = oPost - R * oPre; # translation part of the homography ## And here is the homography mapping old to new coordinates: H = [[R; 0 0] [T; 1]]; ## Treat trivial rotations specially (multiples of 90 degrees): if (mod(thetaDeg, 90) == 0) nRot90 = mod(thetaDeg, 360) / 90; if (mod(thetaDeg, 180) == 0 || sizePre(1) == sizePre(2) || strcmpi(bbox, "loose")) imgPost = rotdim (imgPre, nRot90, [1 2]); return; elseif (mod(sizePre(1), 2) == mod(sizePre(2), 2)) ## Here, bbox is "crop" and the rotation angle is +/- 90 degrees. ## This works only if the image dimensions are of equal parity. imgRot = rotdim (imgPre, nRot90, [1 2]); imgPost = zeros(sizePre); hw = min(sizePre) / 2 - 0.5; imgPost (round(oPost(2) - hw) : round(oPost(2) + hw), round(oPost(1) - hw) : round(oPost(1) + hw) ) = ... imgRot(round(oPost(1) - hw) : round(oPost(1) + hw), round(oPost(2) - hw) : round(oPost(2) + hw) ); return; else ## Here, bbox is "crop", the rotation angle is +/- 90 degrees, and ## the image dimensions are of unequal parity. This case cannot ## correctly be handled by rot90() because the image square to be ## cropped does not align with the pixels - we must interpolate. A ## caller who wants to avoid this should ensure that the image ## dimensions are of equal parity. endif endif ## Now the actual rotations happen if (strcmpi (interp, "fourier")) in_class = class (imgPre); imgPre = im2double (imgPre); if (isgray(imgPre)) imgPost = imrotate_Fourier(imgPre, thetaDeg, interp, bbox); else # rgb image for i = 3:-1:1 imgPost(:,:,i) = imrotate_Fourier(imgPre(:,:,i), thetaDeg, interp, bbox); endfor endif valid = NA; imgPost = imcast (imgPost, in_class); else [imgPost, valid] = imperspectivewarp(imgPre, H, interp, bbox, extrapval); endif endfunction function fs = imrotate_Fourier (f, theta, method, bbox) # Get original dimensions. [ydim_orig, xdim_orig] = size(f); # This finds the index coords of the centre of the image (indices are base-1) # eg. if xdim_orig=8, then xcentre_orig=4.5 (half-way between 1 and 8) xcentre_orig = (xdim_orig+1) / 2; ycentre_orig = (ydim_orig+1) / 2; # Pre-process the angle =========================================================== # Whichever 90 degree multiple theta is closest to, that multiple of 90 will # be implemented by rot90. The remainder will be done by shears. # This ensures that 0 <= theta < 360. theta = rem( rem(theta,360) + 360, 360 ); # This is a flag to keep track of 90-degree rotations. perp = 0; if ( theta>=0 && theta<=45 ) phi = theta; elseif ( theta>45 && theta<=135 ) phi = theta - 90; f = rotdim(f,1, [1 2]); perp = 1; elseif ( theta>135 && theta<=225 ) phi = theta - 180; f = rotdim(f,2, [1 2]); elseif ( theta>225 && theta<=315 ) phi = theta - 270; f = rotdim(f,3, [1 2]); perp = 1; else phi = theta; endif if ( phi == 0 ) fs = f; if ( strcmp(bbox,"loose") == 1 ) return; else xmax = xcentre_orig; ymax = ycentre_orig; if ( perp == 1 ) xmax = max([xmax ycentre_orig]); ymax = max([ymax xcentre_orig]); [ydim xdim] = size(fs); xpad = ceil( xmax - (xdim+1)/2 ); ypad = ceil( ymax - (ydim+1)/2 ); fs = padarray (fs, [ypad xpad]); endif xcentre_new = (size(fs,2)+1) / 2; ycentre_new = (size(fs,1)+1) / 2; endif else # At this point, we can assume -451) = 1; fs(fs<0) = 0; endif endfunction #%!test #%! ## Verify minimal loss across six rotations that add up to 360 +/- 1 deg.: #%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; #%! angles = [ 59 60 61 ]; #%! tolerances = [ 7.4 8.5 8.6 # nearest #%! 3.5 3.1 3.5 # bilinear #%! 2.7 2.0 2.7 # bicubic #%! 2.7 1.6 2.8 ]/8; # Fourier #%! #%! # This is peaks(50) without the dependency on the plot package #%! x = y = linspace(-3,3,50); #%! [X,Y] = meshgrid(x,y); #%! x = 3*(1-X).^2.*exp(-X.^2 - (Y+1).^2) ... #%! - 10*(X/5 - X.^3 - Y.^5).*exp(-X.^2-Y.^2) ... #%! - 1/3*exp(-(X+1).^2 - Y.^2); #%! #%! x -= min(x(:)); # Fourier does not handle neg. values well #%! x = x./max(x(:)); #%! for m = 1:(length(methods)) #%! y = x; #%! for i = 1:5 #%! y = imrotate(y, 60, methods{m}, "crop", 0); #%! end #%! for a = 1:(length(angles)) #%! assert(norm((x - imrotate(y, angles(a), methods{m}, "crop", 0)) #%! (10:40, 10:40)) < tolerances(m,a)); #%! end #%! end #%!xtest #%! ## Verify exactness of near-90 and 90-degree rotations: #%! X = rand(99); #%! for angle = [90 180 270] #%! for da = [-0.1 0.1] #%! Y = imrotate(X, angle + da , "nearest", :, 0); #%! Z = imrotate(Y, -(angle + da), "nearest", :, 0); #%! assert(norm(X - Z) == 0); # exact zero-sum rotation #%! assert(norm(Y - imrotate(X, angle, "nearest", :, 0)) == 0); # near zero-sum #%! end #%! end #%!test #%! ## Verify preserved pixel density: #%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; #%! ## This test does not seem to do justice to the Fourier method...: #%! tolerances = [ 4 2.2 2.0 209 ]; #%! range = 3:9:100; #%! for m = 1:(length(methods)) #%! t = []; #%! for n = range #%! t(end + 1) = sum(imrotate(eye(n), 20, methods{m}, :, 0)(:)); #%! end #%! assert(t, range, tolerances(m)); #%! end %!test %! a = reshape (1:18, [2 3 3]); %! %! a90(:,:,1) = [5 6; 3 4; 1 2]; %! a90(:,:,2) = a90(:,:,1) + 6; %! a90(:,:,3) = a90(:,:,2) + 6; %! %! a180(:,:,1) = [6 4 2; 5 3 1]; %! a180(:,:,2) = a180(:,:,1) + 6; %! a180(:,:,3) = a180(:,:,2) + 6; %! %! am90(:,:,1) = [2 1; 4 3; 6 5]; %! am90(:,:,2) = am90(:,:,1) + 6; %! am90(:,:,3) = am90(:,:,2) + 6; %! %! assert (imrotate (a, 0), a); %! assert (imrotate (a, 90), a90); %! assert (imrotate (a, -90), am90); %! assert (imrotate (a, 180), a180); %! assert (imrotate (a, -180), a180); %! assert (imrotate (a, 270), am90); %! assert (imrotate (a, -270), a90); %! assert (imrotate (a, 360), a); image-2.4.1/inst/PaxHeaders.6632/rangefilt.m0000644000000000000000000000013212561122761015366 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/rangefilt.m0000644000175000017500000000507712561122761020222 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## ## 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 3 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{R} =} rangefilt (@var{im}) ## @deftypefnx{Function File} {@var{R} =} rangefilt (@var{im}, @var{domain}) ## @deftypefnx{Function File} {@var{R} =} rangefilt (@var{im}, @var{domain}, @var{padding}, @dots{}) ## Computes the local intensity range in a neighbourhood around each pixel in ## an image. ## ## The intensity range of the pixels of a neighbourhood is computed as ## ## @example ## @var{R} = max (@var{x}) - min (@var{x}) ## @end example ## ## where @var{x} is the value of the pixels in the neighbourhood, ## ## The neighbourhood is defined by the @var{domain} binary mask. Elements of the ## mask with a non-zero value are considered part of the neighbourhood. By default ## a 3 by 3 matrix containing only non-zero values is used. ## ## At the border of the image, extrapolation is used. By default symmetric ## extrapolation is used, but any method supported by the @code{padarray} function ## can be used. ## ## @seealso{paddarray, entropyfilt, stdfilt} ## @end deftypefn function retval = rangefilt (I, domain = true (3), padding = "symmetric", varargin) ## Check input if (nargin == 0) error ("rangefilt: not enough input arguments"); endif if (! isnumeric (I) && ! islogical (I)) error ("rangefilt: I must be a numeric or logical array"); endif if (! isnumeric (domain) && ! islogical (domain)) error ("rangefilt: DOMAIN must be a logical array"); endif domain = logical (domain); ## Pad image pad = floor (size (domain)/2); I = padarray (I, pad, padding, varargin {:}); even = (round (size (domain)/2) == size (domain)/2); idx = cell (1, ndims (I)); for k = 1:ndims (I) idx {k} = (even (k)+1):size (I, k); endfor I = I (idx {:}); ## Perform filtering retval = __spatial_filtering__ (I, domain, "range", I, 0); endfunction %!test %! im = rangefilt (ones (5)); %! assert (im, zeros (5)); image-2.4.1/inst/PaxHeaders.6632/intlut.m0000644000000000000000000000013212561122761014732 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/intlut.m0000644000175000017500000000543712561122761017566 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} intlut (@var{A}, @var{LUT}) ## Convert matrix from look up table (LUT). ## ## Replaces the values from the matrix @var{A} with the corresponding value ## from the look up table @var{LUT} (this is the grayscale equivalent to an ## indexed image). ## ## @var{A} and @var{LUT} must be of the same class, and uint8, uint16, or int16. ## @var{LUT} must have exactly 256 elements for class uint8, and 65536 for ## classes uint16 and int16. Output is of same class as @var{LUT}. ## ## @seealso{ind2gray, ind2rgb, rgb2ind} ## @end deftypefn function B = intlut (A, LUT) if (nargin != 2) print_usage (); elseif (! strcmp (class (A), class (LUT))) error ("intlut: A and LUT must be of same class"); elseif (! isvector (LUT)) error ("intlut: LUT must be a vector"); endif cl= class (A); switch (cl) case {"uint8"}, max_numel = 256; case {"int16", "uint16"}, max_numel = 65536; otherwise error ("intlut: A must be of class uint8, uint16, or int16"); endswitch if (max_numel != numel (LUT)) error ("intlut: LUT must have %d elements for class %s", max_numel, cl); endif ## We need to convert to double in case of the values in A is ## equal to intmax (class (A)) A = double (A); if (strcmp ("int16", cl)) A += 32769; else A += 1; endif B = LUT(A); endfunction %!demo %! ## Returns an uint8 array [254 253 252 251] %! intlut (uint8 ([1 2 3 4]), uint8 ([255:-1:0])); %!assert (intlut (uint8 (1:4), uint8 ( 255:-1:0)), uint8 (254:-1:251)); %!assert (intlut (uint16 (1:4), uint16 (65535:-1:0)), uint16 (65534:-1:65531)); %!assert (intlut (int16 (1:4), int16 (32767:-1:-32768)), int16 (-2:-1:-5)); %!assert (intlut (uint8 (255), uint8 (0:255)), uint8 (255)); %!assert (intlut (uint16 (65535), uint16 (0:65535)), uint16 (65535)); %!assert (intlut (int16 (32767), int16 (-32768:32767)), int16 (32767)); %!error intlut () %!error intlut ("text") %!error intlut (1:20, uint8(0:255)); %!error intlut (uint16(1:20), uint8(0:255)); %!error intlut (uint8 (1:20), uint8 (0:200)); image-2.4.1/inst/PaxHeaders.6632/qtsetblk.m0000644000000000000000000000013212561122761015244 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/qtsetblk.m0000644000175000017500000000505112561122761020070 0ustar00carandraugcarandraug00000000000000## 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 3 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{J} =} qtsetblk (@var{I}, @var{S}, @var{dim}, @var{vals}) ## Set block values in a quadtree decomposition. ## ## J=qtsetblk(I,S,dim,vals) sets all the @var{dim}-by-@var{dim} blocks ## in the quadtree decomposition (@var{S} returned by qtdecomp) of ## @var{I} to @var{dim}-by-@var{dim} blocks in @var{vals}, which is ## itself a @var{dim}-by-@var{dim}-by-k array. k is the number of ## @var{dim}-by-@var{dim} blocks in the quadtree decomposition. ## @seealso{qtdecomp, qtgetblk} ## @end deftypefn function J = qtsetblk (I, S, dim, vals) if (nargin != 4) print_usage; endif ## get blocks [ii,ji,v]=find(S); ## filter the ones which match dim idx=find(v==dim); if(size(vals,3)num blocks error("qtsetblk: k (vals 3rd dimension) is not equal to number of blocks."); endif ii=ii(idx); ji=ji(idx); ## calc end vertex ie=ii+dim-1; je=ji+dim-1; J=I; for b=1:length(idx) J(ii(b):ie(b),ji(b):je(b))=vals(:,:,b); endfor endfunction %!demo %! J=qtsetblk(eye(4),qtdecomp(eye(4)),2,ones(2,2,2)) %! % Sets upper-right and lower-left blocks of 2*2 zeros to ones %!shared A, S %! A=[ 1, 4, 2, 5,54,55,61,62; %! 3, 6, 3, 1,58,53,67,65; %! 3, 6, 3, 1,58,53,67,65; %! 3, 6, 3, 1,58,53,67,65; %! 23,42,42,42,99,99,99,99; %! 27,42,42,42,99,99,99,99; %! 23,22,26,25,99,99,99,99; %! 22,22,24,22,99,99,99,99]; %! S = qtdecomp (A, 10); %!test %! R=A; %! vals=zeros(4,4,2); %! vals(:,:,1)=reshape([1:16],4,4); %! vals(:,:,2)=reshape([21:36],4,4); %! R(1:4,1:4)=reshape([1:16],4,4); %! R(5:8,5:8)=reshape([21:36],4,4); %! assert(qtsetblk(A,S,4,vals),R); %!test %! R=A; %! R(1:4,5:8)=1; %! R(7:8,1:4)=1; %! R(5:6,3:4)=1; %! assert(qtsetblk(A,S,2,ones(2,2,7)),R); %!test %! R=A; %! R(5:6,1:2)=10; %! assert(qtsetblk(A,S,1,ones(1,1,4)*10),R); image-2.4.1/inst/PaxHeaders.6632/roicolor.m0000644000000000000000000000013212561122761015243 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/roicolor.m0000644000175000017500000000414312561122761020070 0ustar00carandraugcarandraug00000000000000## 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 3 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{BW} =} roicolor (@var{A}, @var{low}, @var{high}) ## @deftypefnx {Function File} {@var{BW} = } roicolor (@var{A},@var{v}) ## Select a Region Of Interest of an image based on color. ## ## BW = roicolor(A,low,high) selects a region of interest (ROI) of an ## image @var{A} returning a black and white image in a logical array (1 for ## pixels inside ROI and 0 outside ROI), which is formed by all pixels ## whose values lie within the colormap range specified by [@var{low} ## @var{high}]. ## ## BW = roicolor(A,v) selects a region of interest (ROI) formed by all ## pixels that match values in @var{v}. ## @end deftypefn function BW = roicolor (A, p1, p2) if (nargin < 2 || nargin > 3) print_usage; endif if (nargin == 2) if (!isvector(p1)) error("BW = roicolor(A, v): v should be a vector."); endif BW=logical(zeros(size(A))); for c=p1 BW|=(A==c); endfor elseif (nargin==3) if (!isscalar(p1) || !isscalar(p2)) error("BW = roicolor(A, low, high): low and high must be scalars."); endif BW=logical((A>=p1)&(A<=p2)); endif endfunction %!demo %! roicolor([1:10],2,4); %! % Returns '1' where input values are between 2 and 4 (both included). %!assert(roicolor([1:10],2,4),logical([0,1,1,1,zeros(1,6)])); %!assert(roicolor([1,2;3,4],3,3),logical([0,0;1,0])); %!assert(roicolor([1,2;3,4],[1,4]),logical([1,0;0,1])); image-2.4.1/inst/PaxHeaders.6632/bwarea.m0000644000000000000000000000013212561122761014654 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwarea.m0000644000175000017500000000351612561122761017504 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2005 Søren Hauberg ## ## 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 3 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{total} =} bwarea (@var{bw}) ## Estimate total area of objects on the image @var{bw}. ## ## The image @var{bw} can be of any class, even non-logical, in which case non ## zero valued pixels are considered to be an object. ## ## This algorithm is not the same as counting the number of pixels belonging to ## an object as it tries to estimate the area of the original object. The value ## of each pixel to the total area is weighted in relation to its neighbour ## pixels. ## ## @seealso{im2bw, bweuler, bwperim, regionprops} ## @end deftypefn function total = bwarea (bw) if (nargin != 1) print_usage; elseif (!isimage (bw) || ndims (bw) != 2) error("bwarea: input image must be a 2D image"); elseif (!islogical (bw)) bw = (bw != 0) endif four = ones (2); two = diag ([1 1]); fours = conv2 (bw, four); twos = conv2 (bw, two); nQ1 = sum (fours(:) == 1); nQ3 = sum (fours(:) == 3); nQ4 = sum (fours(:) == 4); nQD = sum (fours(:) == 2 & twos(:) != 1); nQ2 = sum (fours(:) == 2 & twos(:) == 1); total = 0.25*nQ1 + 0.5*nQ2 + 0.875*nQ3 + nQ4 + 0.75*nQD; endfunction image-2.4.1/inst/PaxHeaders.6632/imcomplement.m0000644000000000000000000000013212561122761016104 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imcomplement.m0000644000175000017500000000542312561122761020733 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imcomplement (@var{A}) ## Compute image complement or negative. ## ## Intuitively this corresponds to the intensity of bright and dark ## regions being reversed. The exact operation performed is dependent ## on the class of the image. ## ## @table @asis ## @item floating point ## Since floating point images are meant to have values in the range [0 1], ## this is equivalent @code{A -1}. This leads to values within the range ## to be inverted while others to stay equally distant from the limits. ## ## @item logical ## Equivalent to @code{! A} ## ## @item integer ## Inverts the values within the range of the data type. This is ## equivalent to @code{bitcmp (@var{A})}. ## ## @end table ## ## @seealso{imadd, imdivide, imlincomb, immultiply, imsubtract} ## @end deftypefn function B = imcomplement (A) if (nargin != 1) print_usage (); endif if (isfloat (A)) B = 1 - A; elseif (islogical (A)) B = ! A; elseif (isinteger (A)) if (intmin (class (A)) < 0) ## for signed integers, we use bitcmp B = bitcmp (A); else ## this is currently more efficient than bitcmp (but hopefully core ## will change) B = intmax (class (A)) - A; endif else error("imcomplement: A must be an image but is of class `%s'", class (A)); endif endfunction %!assert (imcomplement (10), -9); %!assert (imcomplement (single (10)), single (-9)); %!assert (imcomplement (0.2), 0.8); %!assert (imcomplement (uint8 (0)), uint8 (255)); %!assert (imcomplement (uint8 (1)), uint8 (254)); %!assert (imcomplement (uint16 (0)), uint16 (65535)); %!assert (imcomplement (uint16 (1)), uint16 (65534)); %!assert (imcomplement (int8 (-128)), int8 ( 127)); %!assert (imcomplement (int8 ( 127)), int8 (-128)); %!assert (imcomplement (int16 (-1)), int16 ( 0)); %!assert (imcomplement (int16 ( 0)), int16 (-1)); %!assert (imcomplement (int16 ( 1)), int16 (-2)); %!assert (imcomplement ([true false true]), [false true false]) %!error imcomplement ("not an image") image-2.4.1/inst/PaxHeaders.6632/cp2tform.m0000644000000000000000000000013212561122761015147 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/cp2tform.m0000644000175000017500000002620412561122761017776 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{T} =} cp2tform (@var{rw_pt}, @var{ap_pt}, @var{transtype}) ## @deftypefnx {Function File} {@var{T} =} cp2tform (@var{rw_pt}, @var{ap_pt}, @var{transtype}, @var{opt}) ## Returns a transformation structure @var{T} (see "help maketform" ## for the form of the structure) that can be further used to ## transform coordinates from one space (here denoted "RW" for "real ## world") to another (here denoted "AP" for "apparent"). The transform ## is inferred from two n-by-2 arrays, @var{rw_pt} and @var{ap_pt}, which ## contain the coordinates of n control points in the two 2D spaces. ## Transform coefficients are stored ## in @var{T}.tdata. Interpretation of transform coefficients depends on the ## requested transform type @var{transtype}: ## ## @table @asis ## @item "affine" ## Return both forward (RW->AP) and inverse (AP->RW) transform ## coefficients @var{T}.tdata.T and @var{T}.tdata.Tinv. Transform ## coefficients are 3x2 matrices which can ## be used as follows: ## ## @example ## @group ## @var{rw_pt} = [@var{ap_pt} ones(rows (ap_pt,1))] * Tinv ## @var{ap_pt} = [@var{rw_pt} ones(rows (rw_pt,1))] * T ## @end group ## @end example ## This transformation is well suited when parallel lines in one space ## are still parallel in the other space (e.g. shear, translation, @dots{}). ## ## @item "nonreflective similarity" ## Same as "affine" except that the transform matrices T and Tinv have ## the form ## @example ## @group ## Tcoefs = [a -b; ## b a; ## c d] ## @end group ## @end example ## This transformation may represent rotation, scaling and ## translation. Reflection is not included. ## ## @item "similarity" ## Same as "nonreflective similarity" except that the transform matrices T and Tinv may also have ## the form ## @example ## @group ## Tcoefs = [a b; ## b -a; ## c d] ## @end group ## @end example ## This transformation may represent reflection, rotation, scaling and ## translation. Generates a warning if the nonreflective similarity is ## better suited. ## ## @item "projective" ## Return both forward (RW->AP) and inverse (AP->RW) transform ## coefficients @var{T}.tdata.T and @var{T}.tdata.Tinv. Transform ## coefficients are 3x3 matrices which can ## be used as follows: ## ## @example ## @group ## [u v w] = [@var{ap_pt} ones(rows (ap_pt,1))] * Tinv ## @var{rw_pt} = [u./w, v./w]; ## [x y z] = [@var{rw_pt} ones(rows (rw_pt,1))] * T ## @var{ap_pt} = [x./z y./z]; ## @end group ## @end example ## This transformation is well suited when parallel lines in one space ## all converge toward a vanishing point in the other space. ## ## @item "polynomial" ## Here the @var{opt} input argument is the order of the polynomial ## fit. @var{opt} must be 2, 3 or 4 and input control points number must ## be respectively at least 6, 10 and 15. Only the inverse transform ## (AP->RW) is included in the structure @var{T}. ## Denoting x and y the apparent coordinates vector and xrw, yrw the ## the real world coordinates. Inverse transform coefficients are ## stored in a (6,10 or 15)x2 matrix which can be used as follows: ## ## @example ## @group ## Second order: ## [xrw yrw] = [1 x y x*y x^2 y^2] * Tinv ## @end group ## @group ## Third order: ## [xrw yrw] = [1 x y x*y x^2 y^2 y*x^2 x*y^2 x^3 y^3] * Tinv ## @end group ## @group ## Fourth order: ## [xrw yrw] = [1 x y x*y x^2 y^2 y*x^2 x*y^2 x^3 y^3 x^3*y x^2*y^2 x*y^3 x^4 y^4] * Tinv ## @end group ## @end example ## This transform is well suited when lines in one space become curves ## in the other space. ## @end table ## @seealso{tformfwd, tforminv, maketform} ## @end deftypefn ## Author: Pantxo Diribarne ## Created: 2012-09-05 function trans = cp2tform (crw, cap, ttype, opt) if (nargin < 3) print_usage (); endif if (! all (size (crw) == size (cap)) || columns (crw) != 2) error ("cp2tform: expect the 2 first input arguments to be (m x 2) matrices") elseif (! ischar (ttype)) error ("cp2tform: expect a string as third input argument") endif ttype = lower (ttype); switch ttype case {'nonreflective similarity', 'similarity', 'affine', 'projective'} trans = gettrans (ttype, cap, crw); case 'polynomial' if (nargin < 4) error ("cp2tform: expect a fourth input argument for 'polynomial'") elseif (! isscalar (opt)) error ("cp2tform: expect a scalar as fourth argument") endif trans = gettrans (ttype, cap, crw, round (opt)); otherwise error ("cp2tform: expect 'nonreflective similarity', 'similarity', 'affine' or 'polynomial' as third input argument") endswitch endfunction function trans = gettrans (ttype, cap, crw, ord = 0) switch ttype case "nonreflective similarity" x = cap(:,1); y = cap(:,2); u = crw(:,1); v = crw(:,2); tmp0 = zeros(size(u)); tmp1 = ones(size(u)); A = [u v tmp1 tmp0 ; v -u tmp0 tmp1]; B = [x; y]; tmat = A\B; tmat = [tmat(1) -tmat(2); tmat(2) tmat(1); tmat(3) tmat(4)]; trans = maketform ("affine", tmat); case "similarity" x = cap(:,1); y = cap(:,2); u = crw(:,1); v = crw(:,2); tmp0 = zeros(size(u)); tmp1 = ones(size(u)); #without reflection A = [u v tmp1 tmp0 ; v -u tmp0 tmp1]; B = [x; y]; tmat1 = A\B; resid = norm (A*tmat1 - B); #with reflection A = [u v tmp1 tmp0 ; -v u tmp0 tmp1]; tmat2 = A\B; if (norm (A*tmat2 - B) < resid) tmat = [tmat2(1) tmat2(2); tmat2(2) -tmat2(1); tmat2(3) tmat2(4)]; else tmat = [tmat1(1) -tmat1(2); tmat1(2) tmat1(1); tmat1(3) tmat1(4)]; warning ("cp2tform: reflection not included.") endif trans = maketform ("affine", tmat); case "affine" tmat = [crw ones(rows(crw), 1)]\cap; trans = maketform ("affine", tmat); case "projective" x = cap(:,1); y = cap(:,2); u = crw(:,1); v = crw(:,2); tmp0 = zeros(size(u)); tmp1 = ones(size(u)); A = [-u -v -tmp1 tmp0 tmp0 tmp0 x.*u x.*v x; tmp0 tmp0 tmp0 -u -v -tmp1 y.*u y.*v y]; B = - A(:,end); A(:,end) = []; tmat = A\B; tmat(9) = 1; tmat = reshape (tmat, 3, 3); trans = maketform ("projective", tmat); case "polynomial" x = cap(:,1); y = cap(:,2); u = crw(:,1); v = crw(:,2); tmp1 = ones(size(x)); ndims_in = 2; ndims_out = 2; forward_fcn = []; inverse_fcn = @inv_polynomial; A = [tmp1, x, y, x.*y, x.^2, y.^2]; B = [u v]; switch ord case 2 case 3 A = [A, y.*x.^2 x.*y.^2 x.^3 y.^3]; case 4 A = [A, y.*x.^2 x.*y.^2 x.^3 y.^3]; A = [A, x.^3.*y x.^2.*y.^2 x.*y.^3 x.^4 y.^4]; otherwise error ("cp2tform: supported polynomial orders are 2, 3 and 4.") endswitch tmat = A\B; trans = maketform ("custom", ndims_in, ndims_out, ... forward_fcn, inverse_fcn, tmat); otherwise error ("cp2tform: invalid TRANSTYPE %s.", ttype); endswitch endfunction function out = inv_polynomial (x, pst) out = []; for ii = 1:2 p = pst.tdata(:,ii); if (rows (p) == 6) ## 2nd order out(:,ii) = p(1) + p(2)*x(:,1) + p(3)*x(:,2) + p(4)*x(:,1).*x(:,2) + ... p(5)*x(:,1).^2 + p(6)*x(:,2).^2; elseif (rows (p) == 10) ## 3rd order out(:,ii) = p(1) + p(2)*x(:,1) + p(3)*x(:,2) + p(4)*x(:,1).*x(:,2) + ... p(5)*x(:,1).^2 + p(6)*x(:,2).^2 + p(7)*x(:,2).*x(:,1).^2 + ... p(8)*x(:,1).*x(:,2).^2 + p(9)*x(:,1).^3 + p(10)*x(:,2).^3; elseif (rows (p) == 15) ## 4th order out(:,ii) = p(1) + p(2)*x(:,1) + p(3)*x(:,2) + p(4)*x(:,1).*x(:,2) + ... p(5)*x(:,1).^2 + p(6)*x(:,2).^2 + p(7)*x(:,2).*x(:,1).^2 + ... p(8)*x(:,1).*x(:,2).^2 + p(9)*x(:,1).^3 + p(10)*x(:,2).^3 + ... p(11)*x(:,2).*x(:,1).^3 + p(12)*x(:,2).^2.*x(:,1).^2+ ... p(13)*x(:,1).*x(:,2).^3 + p(14)*x(:,1).^4 + p(15)*x(:,2).^4; endif endfor endfunction %!function [crw, cap] = coords (npt = 1000, scale = 2, dtheta = pi/3, dx = 2, dy = -6, sig2noise = 1e32) %! theta = (rand(npt, 1)*2-1)*2*pi; %! R = rand(npt,1); %! y = R.*sin(theta); %! x = R.*cos(theta); %! crw = [y x]; %! %! thetap = theta + dtheta; %! Rap = R * scale; %! %! yap = Rap.*sin(thetap); %! yap = yap + dy; %! yap = yap + rand (size (yap)) * norm (yap) / sig2noise; %! %! xap = Rap.*cos(thetap); %! xap = xap + dx; %! xap = xap + rand (size (xap)) * norm (xap) / sig2noise; %! cap = [yap xap]; %!endfunction %!test %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'projective'; %! T = cp2tform (crw, cap, ttype); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!test %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'affine'; %! T = cp2tform (crw, cap, ttype); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!test %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'nonreflective similarity'; %! T = cp2tform (crw, cap, ttype); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!test %! npt = 100000; %! [crw, cap] = coords (npt); %! cap(:,2) *= -1; % reflection around y axis %! ttype = 'similarity'; %! T = cp2tform (crw, cap, ttype); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!xtest %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'polynomial'; %! ord = 2; %! T = cp2tform (crw, cap, ttype, ord); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!xtest %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'polynomial'; %! ord = 3; %! T = cp2tform (crw, cap, ttype, ord); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) %!xtest %! npt = 100000; %! [crw, cap] = coords (npt); %! ttype = 'polynomial'; %! ord = 4; %! T = cp2tform (crw, cap, ttype, ord); %! crw2 = tforminv (T, cap); %! finalerr = norm (crw - crw2)/npt; %! assert (finalerr < eps, "norm = %3.2e ( > eps)", finalerr) image-2.4.1/inst/PaxHeaders.6632/psnr.m0000644000000000000000000000013212561122761014375 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/psnr.m0000644000175000017500000000415512561122761017225 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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{peaksnr}] =} psnr (@var{A}, @var{ref}) ## @deftypefnx {Function File} {[@var{peaksnr}] =} psnr (@var{A}, @var{ref}, @var{peak}) ## @deftypefnx {Function File} {[@var{peaksnr}, @var{snr}] =} psnr (@dots{}) ## Compute peak signal-to-noise ratio. ## ## Computes the peak signal-to-noise ratio for image @var{A}, using ## @var{ref} as reference. @var{A} and @var{ref} must be of same size ## and class. ## ## The optional value @var{peak} defines the highest value for the image ## and its default is class dependent (see @code{getrangefromclass}). ## ## The second output @var{snr} is the simple signal-to-noise ratio. ## ## @seealso{immse} ## @end deftypefn function [peaksnr, snr] = psnr (A, ref, peak) if (nargin < 2 || nargin > 3) print_usage (); elseif (! size_equal (A, ref)) error ("psnr: A and REF must be of same size"); elseif (! strcmp (class (A), class (ref))) error ("psnr: A and REF must have same class"); end if (nargin < 3) peak = getrangefromclass (A)(2); elseif (! isscalar (peak)) error ("psnr: PEAK must be a scalar value"); endif ## simpler way to keep single precision if they are single if (isinteger (A)) A = double (A); ref = double (ref); endif mse = immse (A, ref); peaksnr = 10 * log10 ((peak.^2) / mse); if (nargout > 1) snr = 10 * log10 ((sumsq (A(:)) / numel (A)) / mse); endif endfunction image-2.4.1/inst/PaxHeaders.6632/tiff_tag_read.m0000644000000000000000000000013212561122761016171 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/inst/tiff_tag_read.m0000644000175000017500000003326612561122761021026 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010-2012 Carnë Draug ## ## 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 3 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{value}, @var{offset}] =} tiff_tag_read (@var{file}, @var{tag}) ## @deftypefnx {Function File} {[@var{value}, @var{offset}] =} tiff_tag_read (@var{file}, @var{tag}, @var{ifd}) ## @deftypefnx {Function File} {[@var{value}, @var{offset}] =} tiff_tag_read (@var{file}, @var{tag}, "all") ## Read value of @var{tag}s from TIFF files. ## ## @var{file} must be a TIFF file and @var{tag} should be a tag ID. To check ## multiple tags, @var{tag} can be a vector. If @var{ifd} is supplied, only ## those IFDs (Image File Directory) will be read. As with @var{tag}, multiple ## IFDs can be checked by using a vector or with the string `all'. By default, ## only the first IFD is read. ## ## @var{value} and @var{offset} will be a matrix with a number of rows and ## columns equal to the number of @var{tag}s and @var{ifd}s requested. The index ## relate to the same order as the input. @var{offset} has the same structure as ## @var{value} and when equal to 1 its matching value on @var{value} will be an ## offset to a position in the file. ## ## @var{tag}s that can't be found will have a value of 0 and the corresponding ## @var{offset} will be 2. ## ## If an error occurs when reading @var{file} (such as lack of permissions of file ## is not a TIFF file), @var{offset} is set to -1 and @var{value} contains the ## error message. ## ## See the following examples: ## @example ## @group ## ## read value of tag 258 on IFD 1 (`off' will be 1 if `val' is an offset or 2 if not found) ## [val, off] = tiff_tag_read (filepath, 258); ## @end group ## @end example ## ## @example ## @group ## ## read value 258, 262, 254 o IFD 1 (`val' and `off' will be a 1x3 matrix) ## [val, off] = tiff_tag_read (filepath, [258 262 254]); ## if (off(1) == -1), error ("something happened: %s", val); endif ## off(2,1) # will be 1 if val(2,1) is an offset to a file position or 2 if tag was not found ## val(2,1) # value of tag 262 on IFD 1 ## @end group ## @end example ## ## @example ## @group ## ## read value 258, 262, 254 on the first 10 IFDs 1 (`val' and `off' will be a 1x10 matrix) ## [val, off] = tiff_tag_read (filepath, [258 262 254], 1:10); ## val(2,5) # value of tag 262 on IFD 5 ## @end group ## @end example ## ## @example ## @group ## ## read value 258, 262, 254 o IFD 1 (`val' and `off' will be a 1x3 matrix) ## [val, off] = tiff_tag_read (filepath, [258 262 254], "all"); ## val(2,end) # value of tag 262 on the last IFD ## @end group ## @end example ## ## @seealso{imread, imfinfo} ## @end deftypefn ## Based on the documentation at ## * http://en.wikipedia.org/wiki/Tagged_Image_File_Format ## * http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf ## * http://ibb.gsf.de/homepage/karsten.rodenacker/IDL/Lsmfile.doc ## * http://www.awaresystems.be/imaging/tiff/faq.html ## ## and the function tiff_read by F. Nedelec, EMBL (www.cytosim.org) ## * http://www.cytosim.org/misc/index.html ## ## Explanation of the TIFF file structure: ## ## The idea of multi-page images needs to be understood first. These allow one file ## to have multiple images. This may sound strange but consider situations such as ## an MRI scan (one file can then contain one scan which is multiple images across ## one of the axis) or time-lapse experiment (where one file is not unlike a movie). ## TIFF files support this by being like a container of single images, called IFD ## (Image File Directory). For each page there will be a single IFD. One can see a ## TIFF as an archive file of multiple images files that many times have a single file. ## ## Each TIFF file starts with a small header that identifies the file as TIFF. The ## header ends with the position on the file for the first IFD. Each IFD has multiple ## entries that hold information about the image of that IFD including where on the ## file is the actual image. Each IFD entry is identified by a tag. Each tag has a ## unique meaning; for example, the IFD entry with tag 259 will say the compression ## type (if any), of the image in that IFD. ## ## A TIFF file will always have at least one IFD and each IFD will always have at ## least one IFD entry. ## ## * On the TIFF image file header: ## bytes 00-01 --> byte order used within the file: "II" for little endian ## and "MM" for big endian byte ordering. ## bytes 02-03 --> number 42 that identifies the file as TIFF ## bytes 04-07 --> file offset (in bytes) of the first IFD (Image File Directory) ## ## Note: offset is always from the start of the file ("bof" in fread) and first ## byte has an offset of zero. ## ## * On a TIFF's IFD structure: ## bytes 00-01 --> number of entries (or tags or fields or directories) ## bytes 02-13 --> the IFD entry #0 ## bytes 14+=11 -> the IFD entry #N. Each will have exactly 12 bytes (the ## number of IFD entries was specified at the start of the IFD) ## bytes XX-XX --> file offset for next IFD (last 4 bytes of the IFD) or 0 ## if it's the last IFD ## ## * On an IFD entry structure: ## bytes 00-01 --> tag that identifies the entry ## bytes 02-03 --> entry type ## 1 --> BYTE (uint8) ## 2 --> ASCII ## 3 --> SHORT (uint16) ## 4 --> LONG (uint32) ## 5 --> RATIONAL (two LONGS) ## 6 --> SBYTE (int8) ## 7 --> UNDEFINED (8 bit) ## 8 --> SSHORT (int16) ## 9 --> SLONG (int32) ## 10 --> FLOAT (single IEEE precision) ## 11 --> DOUBLE (double IEEE precision) ## bytes 04-07 --> number of values (count) ## bytes 08-11 --> file offset (from the beginning of file) or value (only if ## it fits in 4 bytes). It is possible that the offset is for ## a structure and not a value so we return the offset ## ## Note: file offset of the value may point anywhere in the file, even after the image. ## ## Tags numbered >= 32768 are private tags ## Tags numbered on the 65000--65535 range are reusable tags function [val, off] = tiff_tag_read (file, tag, ifd = 1) if (nargin < 2 || nargin > 3) print_usage; elseif (!isnumeric (tag) || !isvector (tag)) error ("`tag' must be either a numeric scalar or vector with tags -- identifying number of a field"); elseif (!(ischar (ifd) && strcmpi (ifd, "all")) && !(isnumeric (ifd) && isvector (ifd) && all (ifd == fix (ifd)) && all (ifd > 0))) error ("`ifd' must be either the string `all' or numeric scalar or vector of positive integers with the IFD index"); endif [FID, msg] = fopen (file, "r", "native"); if (FID == -1) [val, off] = bad_exit (FID, sprintf ("Unable to fopen '%s': %s.", file, msg)); return endif ## read byte order byte_order = fread (FID, 2, "char=>char")'; # if we are retrieving a char, we need to transpose to get the string if (strcmp (byte_order, "II")) arch = "ieee-le"; # IEEE little endian format elseif (strcmp (byte_order,"MM")) arch = "ieee-be"; # IEEE big endian format else [val, off] = bad_exit (FID, sprintf ("First 2 bytes of '%s' returned '%s'. For TIFF should either be 'II' or 'MM'. Are you sure it's a TIFF.", file, byte_order)); return endif ## read number 42 nTIFF = fread (FID, 1, "uint16", arch); if (nTIFF != 42) [val, off] = bad_exit (FID, sprintf ("'%s' is not a TIFF (missing value 42 on header at offset 2. Instead got '%g').", file, tiff_id)); return endif if (ischar (ifd) && strcmpi (ifd, "all")) all_ifd = true; else all_ifd = false; endif ## default values for val and off def_val = 0; def_off = 2; ## start output values with default values if (ischar (ifd) && strcmpi (ifd, "all")) val = def_val * ones (numel (tag), 1); off = def_off * ones (numel (tag), 1); else val = def_val * ones (numel (tag), numel (ifd)); off = def_off * ones (numel (tag), numel (ifd)); endif ## read offset for the first IFD and move into it offset_IFD = fread (FID, 1, "uint32", arch); cIFD = 1; # current IFD while (offset_IFD != 0 && (all_ifd || any (ifd >= cIFD))) status = fseek (FID, offset_IFD, "bof"); if (status != 0) [val, off] = bad_exit (FID, sprintf ("error on fseek when moving to IFD #%g", cIFD)); return endif ## if checking on all IFD, add one column to the output if (all_ifd) val(:, end+1) = def_val; off(:, end+1) = def_off; endif ## read number of entries (nTag) and look for the desired tag ID nTag = fread (FID, 1, "uint16", arch); # number of tags in the IFD cTag = 1; # current tag while (nTag >= cTag) tagID = fread (FID, 1, "uint16", arch); # current tag ID if (any(tagID == tag)) # found one ## column number of this IFD in the output matrix: ## we don't know at start the number of IFD so if all IFD have been requested ## we can't find them in `ifd', we need to set the index for output manually if (all_ifd) iCol = cIFD; else iCol = (ifd == cIFD); endif [val(tagID == tag, iCol), ... off(tagID == tag, iCol) ] = read_value (FID, arch); # read tag value elseif (all (tag < tagID)) ## tags are in numeric order so if they wanted tags are all below current tag ID ## we can jump over to the next IFD skip_bytes = 10 + (12 * (nTag - cTag)); status = fseek (FID, skip_bytes, "cof"); # Move to the next IFD break else status = fseek (FID, 10, "cof"); # Move to the next tag if (status != 0) [val, off] = bad_exit (FID, sprintf ("error on fseek when moving out of tag #%g (tagID %g) on IFD %g.", cTag, tagID, cIFD)); return endif endif cTag++; endwhile offset_IFD = fread (FID, 1, "uint32", arch); cIFD++; endwhile fclose (FID); endfunction function [val, off] = read_value (FID, arch) position = ftell (FID); field_type = fread (FID, 1, "uint16", arch); count = fread (FID, 1, "uint32", arch); switch (field_type) case 1, nBytes = 1; precision = "uint8"; # BYTE = 8-bit unsigned integer case 2, nBytes = 1; precision = "uchar"; # ASCII = 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero) case 3, nBytes = 2; precision = "uint16"; # SHORT = 16-bit (2-byte) unsigned integer case 4, nBytes = 4; precision = "uint32"; # LONG = 32-bit (4-byte) unsigned integer case 5, nBytes = 8; precision = "uint32"; # RATIONAL = Two LONGs: the first represents the numerator of a fraction; the second, the denominator case 6, nBytes = 1; precision = "int8"; # SBYTE = An 8-bit signed (twos-complement) integer case 7, nBytes = 1; precision = "uchar"; # UNDEFINED = An 8-bit byte that may contain anything, depending on the definition of the field case 8, nBytes = 2; precision = "int16"; # SSHORT = A 16-bit (2-byte) signed (twos-complement) integer case 9, nBytes = 4; precision = "int32"; # SLONG = A 32-bit (4-byte) signed (twos-complement) integer case 10, nBytes = 8; precision = "int32"; # SRATIONAL = Two SLONG’s: the first represents the numerator of a fraction, the second the denominator case 11, nBytes = 4; precision = "float32"; # FLOAT = Single precision (4-byte) IEEE format case 12, nBytes = 8; precision = "float64"; # DOUBLE = Double precision (8-byte) IEEE format otherwise ## From the TIFF file specification (page 16, section 2: TIFF structure): ## "Warning: It is possible that other TIFF field types will be added in the ## future. Readers should skip over fields containing an unexpected field type." ## ## However, we only get to this point of the code if we are in the tag requested ## by the use so it makes sense to error if we don't supported it yet. error ("TIFF type %i not supported", field_type); endswitch if ((nBytes*count) > 4) off = true; val = fread (FID, 1, "uint32", arch); if (rem (val, 2) != 0) # file offset must be an even number warning ("Found an offset with an odd value %g (offsets should always be even numbers.", val); endif else off = false; switch precision case {5, 10} val = fread (FID, 2*count, precision, arch); val = val(1)/val(2); # the first represents the numerator of a fraction; the second, the denominator case {2} val = fread (FID, count, [precision "=>char"], arch)'; # if we are retrieving a char, we need to transpose to get the string otherwise val = fread (FID, count, precision, arch); endswitch ## adjust position to end of IFD entry (not all take up 4 Bytes) fseek (FID, 4 - (nBytes*count), "cof"); endif endfunction function [val, off] = bad_exit (FID, msg) off = -1; val = sprintf (msg); fclose (FID); endfunction image-2.4.1/inst/PaxHeaders.6632/histeq.m0000644000000000000000000000013212561122761014710 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/histeq.m0000644000175000017500000000673512561122761017546 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2008 Jonas Wagner ## ## 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 3 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{J} =} histeq (@var{I}, @var{n}) ## Equalize histogram of grayscale image. ## ## The histogram contains ## @var{n} bins, which defaults to 64. ## ## @var{I}: Image in double format, with values from 0.0 to 1.0. ## ## @var{J}: Returned image, in double format as well. ## ## Note that the algorithm used for histogram equalization gives results ## qualitatively comparable but numerically different from @sc{matlab} ## implementation. ## ## @seealso{imhist, mat2gray, brighten} ## @end deftypefn function J = histeq (I, n = 64) if (nargin < 1 || nargin > 3) print_usage (); endif if (isempty (I)) J = []; return endif [r, c] = size (I); I = mat2gray (I); [X, map] = gray2ind (I, n); [nn, xx] = imhist (I, n); Icdf = 1 / prod (size (I)) * cumsum (nn); J = reshape (Icdf(X + 1), r, c); endfunction ## FIXME: the method we are using is different from Matlab so our results ## are slightly different. The following xtest show the Matlab ## results that we should be aiming at. %!assert (histeq ([]), []); ## One value %!assert (histeq (0), 1); %!assert (histeq (1), 1); %!assert (histeq (1.5), 1); %!assert (histeq (zeros (100, 200)), ones (100, 200)); # matrix ## Two values %!xtest assert (histeq ([0 1]), [0.4920634921 1], 10^-8); %!xtest assert (histeq ([0 1]'), [0.4920634921 1]', 10^-8); # column array %!xtest assert (histeq ([0 255]), [0.4920634921 1], 10^-8); %!xtest assert (histeq (uint8 ([0 1])), [ 125 190]); # uint8 %!xtest assert (histeq (uint8 ([0 255])), [ 125 255]); %!xtest assert (histeq (uint16 ([0 1])), [65535 65535]); # uint16 %!xtest assert (histeq (uint16 ([0 255])), [32247 48891]); %!xtest assert (histeq (uint16 ([0 256])), [32247 48891]); %!xtest assert (histeq (uint16 ([0 65535])), [32247 65535]); ## Three values %!test assert (histeq ([0 1 1] ), [ 1/3 1 1] , 10^-8); %!test assert (histeq ([0 0 1]'), [ 2/3 2/3 1]', 10^-8); %!xtest assert (histeq ([0 1 2] ), [ 1/3 1 1] , 10^-8); %!xtest assert (histeq (uint8 ([0 1 2])), [ 85 125 215]); %!xtest assert (histeq (uint16 ([0 1 2])), [65535 65535 65535]); %!xtest assert (histeq (uint16 ([0 100 200])), [43690 43690 55133]); ## Many values %!xtest %! J = [20 32 57 81 105 125 150 174 198 223 247]; %! assert (histeq (uint8 (0:10:100)), J); %!xtest %! J = [0.0793650794 %! 0.1269841270 %! 0.2222222222 %! 0.3174603175 %! 0.4126984127 %! 0.4920634921 %! 0.5873015873 %! 0.6825396825 %! 0.7777777778 %! 0.8730158730 %! 1.0000000000]; %! assert (histeq (0:0.1:1), J', 10^-8); image-2.4.1/inst/PaxHeaders.6632/imhist.m0000644000000000000000000000013212561122761014710 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imhist.m0000644000175000017500000001561612561122761017544 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011, 2012 Carnë Draug ## ## 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 3 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} {} imhist (@var{I}) ## @deftypefnx {Function File} {} imhist (@var{I}, @var{n}) ## @deftypefnx {Function File} {} imhist (@var{X}, @var{cmap}) ## @deftypefnx {Function File} {[@var{counts}, @var{x}] =} imhist (@dots{}) ## Produce histogram counts of image @var{I}. ## ## The second argument can either be @var{n}, a scalar that specifies the number ## of bins; or @var{cmap}, a colormap in which case @var{X} is expected to be ## an indexed image. If not specified, @var{n} defaults to 2 for binary images, ## and 256 for grayscale images. ## ## If output is requested, @var{counts} is the number of counts for each bin and ## @var{x} is a range for the bins so that @code{stem (@var{x}, @var{counts})} will ## show the histogram. ## ## @emph{Note:} specially high peaks that may prevent an overview of the histogram ## may not be displayed. To avoid this, use @code{axis "auto y"} after the call ## to @code{imhist}. ## ## @seealso{hist, histc, histeq} ## @end deftypefn function [varargout] = imhist (img, b) ## "img" can be a normal or indexed image. We need to check "b" to find out indexed = false; if (nargin < 1 || nargin > 2) print_usage; elseif (nargin == 1) if (islogical (img)) b = 2; else b = 256; endif elseif (nargin == 2) if (iscolormap (b)) if (!isind(img)) error ("imhist: second argument is a colormap but first argument is not an indexed image."); endif indexed = true; ## an indexed image reads differently wether it's uint8/16 or double ## If uint8/16, index+1 is the colormap row number (0 on the image ## corresponds to the 1st column on the colormap). ## If double, index is the colormap row number (no offset). ## isind above already checks for double/uint8/uint16 so we can use isinteger ## and isfloat safely if ( (isfloat (img) && max (img(:)) > rows(b) ) || (isinteger (img) && max (img(:)) > rows(b)-1) ) warning ("imhist: largest index in image exceeds length of colormap."); endif elseif (isnumeric (b) && isscalar (b) && fix(b) == b && b > 0) if (islogical (img) && b != 2) error ("imhist: there can only be 2 bins when input image is binary") endif else error ("imhist: second argument must be a positive integer scalar or a colormap"); endif endif ## prepare bins and image if (indexed) if (isinteger (img)) bins = 0:rows(b)-1; else bins = 1:rows(b); endif else if (isinteger (img)) bins = linspace (intmin (class (img)), intmax (class (img)), b); elseif (islogical (img)) bins = 0:1; else ## image must be single or double bins = linspace (0, 1, b); endif ## we will use this bins with histc() where their values will be edges for ## each bin. However, what we actually want is for their values to be the ## center of each bin. To do this, we decrease their values by half of bin ## width and will increase it back at the end of the function. We could do ## it on the image and it would be a single step but it would be an heavier ## operation since images are likely to be much longer than the bins. ## The use of hist() is also not simple for this since values right in the ## middle of two bins will go to the bottom bin (4.5 will be placed on the ## bin 4 instead of 5 and we must keep matlab compatibility). ## Of course, none of this needed for binary images. if (!islogical (img)) bins_adjustment = ((bins(2) - bins(1))/2); bins -= bins_adjustment; endif ## matlab returns bins as one column instead of a row but only for non ## indexed images bins = bins'; ## histc does not counts values outside the edges of the bins so we need to ## truncate their values. ## truncate the minimum... integers could in no way have a value below the ## minimum of their class so truncation on this side is only required for if (isfloat (img) && min (img(:)) < 0) img(img < 0) = 0; endif ## truncating the maximum... also adjusts floats above 1. We might need if (max (img(:)) > bins(end)) ## bins (end) is probably a decimal number. If an image is an int, we ## can't assign the new value since it will be fix(). So we need to change ## the image class to double but that will take more memory so let's ## avoid it if we can if (fix (bins(end)) != bins(end)) img = double (img); endif img(img > bins(end)) = bins(end); endif endif [nn] = histc (img(:), bins); if (!indexed && !islogical(img)) bins += bins_adjustment; endif if (nargout != 0) varargout{1} = nn; varargout{2} = bins; else stem (bins, nn, "marker", "none"); xlim ([bins(1) bins(end)]); box off; # remove the box to see bar for the last bin ## If we have a few very high peaks, it prevents the overview of the ## histogram since the axis are set automatically. So we consider the ## automatic y axis bad if it's 10 times above the median of the ## histogram. ## The (ylimit != 0) is for cases when most of the bins is zero. In ## such cases, the median is zero and we'd get an error trying to set ## "ylim ([0 0])". We could adjust it to [0 1] but in such cases, it's ## probably important to show how high those few peaks are. ylimit = round (median (nn) * 10); if (ylim()(2) > ylimit && ylimit != 0) ylim ([0 ylimit]); endif if (indexed) colormap (b); else colormap (gray (b)); endif colorbar ("SouthOutside", "xticklabel", []); endif endfunction %!shared nn, bb, enn, ebb %! [nn, bb] = imhist(logical([0 1 0 0 1])); %!assert({nn, bb}, {[3 2]', [0 1]'}) %! [nn, bb] = imhist([0 0.2 0.4 0.9 1], 5); %!assert({nn, bb}, {[1 1 1 0 2]', [0 0.25 0.5 0.75 1]'}) %! [nn, bb] = imhist([-2 0 0.2 0.4 0.9 1 5], 5); %!assert({nn, bb}, {[2 1 1 0 3]', [0 0.25 0.5 0.75 1]'}) %! [nn, bb] = imhist(uint8([0 32 255]), 256); %! enn = zeros(256, 1); enn([1, 33, 256]) = 1; %! ebb = 0:255; %!assert({nn, bb}, {enn, ebb'}) %! [nn, bb] = imhist(int8([-50 0 100]), 31); %! enn = zeros(31, 1); enn([10, 16, 28]) = 1; %! ebb = -128:8.5:127; %!assert({nn, bb}, {enn, ebb'}) image-2.4.1/inst/PaxHeaders.6632/immultiply.m0000644000000000000000000000013212561122761015620 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/immultiply.m0000644000175000017500000000532012561122761020443 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} immultiply (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{out} =} immultiply (@var{a}, @var{b}, @var{class}) ## Multiply image by another image or constant. ## ## If @var{a} and @var{b} are two images of same size and class, the images are ## multiplied. Alternatively, if @var{b} is a floating-point scalar, @var{a} is ## multiplied by it. ## ## The class of @var{out} will be the same as @var{a} unless @var{a} is logical ## in which case @var{out} will be double. Alternatively, it can be ## specified with @var{class}. ## ## @emph{Note}: the values are truncated to the mininum value of the output ## class. ## @seealso{imabsdiff, imadd, imcomplement, imdivide, imlincomb, imsubtract} ## @end deftypefn function img = immultiply (img, val, out_class = class (img)) if (nargin < 2 || nargin > 3) print_usage; endif [img, val] = imarithmetics ("immultiply", img, val, out_class, nargin); ## have to check how matlab behaves in this situation. Their documentation ## does not say anything but add and subtract silently ignore it and return ## double anyway. This may be done in the call to imarithmetics if (nargin > 2 && strcmpi (out_class, "logical")) warning ("Ignoring request to return logical as output of multiplication."); endif img = img .* val; endfunction %!assert (immultiply (uint8 ([255 50]), uint16 ([300 50])), uint8 ([255 255])); # default to first class and truncate %!assert (immultiply (uint8 ([250 50]), uint16 ([ 3 4]), "uint32"), uint32 ([750 200])); # defining output class works (not in matlab?) %!assert (immultiply (uint8 ([255 50]), 4), uint8 ([255 200])); # works multiplying by a scalar %!assert (immultiply (logical ([ 1 0]), uint16 ([300 50])), uint16 ([300 0])); # output class defaults to whatever input is not logical %!assert (immultiply (logical ([ 1 0]), logical ([ 1 1])), double ([ 1 0])); # tested on matlab for compatibility image-2.4.1/inst/PaxHeaders.6632/colorgradient.m0000644000000000000000000000013212561122761016247 xustar0030 mtime=1438950897.722252238 30 atime=1438950897.722252238 30 ctime=1438950899.342252237 image-2.4.1/inst/colorgradient.m0000644000175000017500000000300712561122761021072 0ustar00carandraugcarandraug00000000000000## Author: Paul Kienzle ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{M} =} colorgradient (@var{C}, @var{w}, @var{n}) ## Define a colour map which smoothly traverses the given colors. ## @var{C} contains the colours, one row per r,g,b value. ## @var{w}(i) is the relative length of the transition from colour i to colour i+1 ## in the entire gradient. The default is ones(rows(C)-1,1). ## n is the length of the colour map. The default is rows(colormap). ## ## E.g., ## @example ## colorgradient([0,0,1; 1,1,0; 1,0,0]) # blue -> yellow -> red ## x = linspace(0,1,200); ## imagesc(x(:,ones(30,1)))'; ## @end example ## @end deftypefn function ret = colorgradient (C, w, n) if nargin < 1 || nargin > 3 print_usage; endif if nargin == 1 n = rows(colormap); w = ones(length(C)-1,1); elseif nargin == 2 if (length(w) == 1) n = w; w = ones(rows(C)-1,1); else n = rows(colormap); endif endif if (length(w)+1 != rows(C)) error("must have one weight for each color interval"); endif w = 1+round((n-1)*cumsum([0;w(:)])/sum(w)); map = zeros(n,3); for i=1:length(w)-1 if (w(i) != w(i+1)) map(w(i):w(i+1),1) = linspace(C(i,1),C(i+1,1),w(i+1)-w(i)+1)'; map(w(i):w(i+1),2) = linspace(C(i,2),C(i+1,2),w(i+1)-w(i)+1)'; map(w(i):w(i+1),3) = linspace(C(i,3),C(i+1,3),w(i+1)-w(i)+1)'; endif endfor if nargout == 0 colormap(map); else ret = map; endif endfunction image-2.4.1/inst/PaxHeaders.6632/bwperim.m0000644000000000000000000000013212561122761015060 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwperim.m0000644000175000017500000002061212561122761017704 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} bwperim (@var{bw}) ## @deftypefnx {Function File} {} bwperim (@var{bw}, @var{conn}) ## Find perimeter of objects in binary images. ## ## Values from the matrix @var{bw} are considered part of an object perimeter ## if their value is non-zero and is connected to at least one zero-valued ## element. ## ## Element connectivity @var{conn}, to define the size of objects, can be ## specified with a numeric scalar (number of elements in the neighborhood): ## ## @table @samp ## @item 4 or 8 ## for 2 dimensional matrices; ## @item 6, 18 or 26 ## for 3 dimensional matrices; ## @end table ## ## or with a binary matrix representing a connectivity array. Defaults to ## @code{conndef (ndims (@var{bw}), "minimal")} which is equivalent to ## @var{conn} of 4 and 6 for 2 and 3 dimensional matrices respectively. ## ## @seealso{bwarea, bwboundaries, imerode, mmgrad} ## @end deftypefn function varargout = bwperim (bw, conn) if (nargin < 1 || nargin > 2) print_usage (); endif if (! isnumeric (bw) && ! islogical (bw)) error("bwperim: BW must be a numeric or logical matrix"); endif bw = logical (bw); if (nargin < 2) conn = conndef (ndims (bw), "minimal"); else conn = conndef (conn); endif ## Recover the elements that would get removed by erosion perim = (! imerode (bw, conn)) & bw; ## Get the borders back which are removed during erosion ## FIXME this is a bit too convoluted and not elegant at all. I am also ## unsure if it is correct for N dimensional stuff and unusual ## connectivities. We should probably be using the output from ## bwboundaries() but bwboundaries() seems buggy in the case of ## holes. tmp_idx = repmat ({":"}, [1 ndims(perim)]); tmp_conn_idx = repmat ({":"}, [1 ndims(conn)]); p_size = size (perim); for dim = 1:min (ndims (perim), ndims (conn)) conn_idx = tmp_conn_idx; conn_idx{dim} = [1 3]; if (p_size(dim) == 1 || ! any (conn(conn_idx{:})(:))) continue endif idx = tmp_idx; idx{dim} = [1 p_size(dim)]; perim(idx{:}) = bw(idx{:}); endfor if (nargout > 0) varargout{1} = perim; else imshow (perim); endif endfunction %!shared in, out %! in = [ 1 1 1 1 0 1 1 0 1 1 %! 1 1 0 1 1 1 1 1 1 0 %! 1 1 1 0 1 1 1 1 1 1 %! 1 1 1 1 0 1 1 1 0 1 %! 1 1 1 0 1 1 1 1 1 0 %! 1 1 1 1 1 1 0 1 0 1 %! 1 1 1 1 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 0 0 1 1 %! 1 1 1 1 0 1 0 1 1 0]; %! %! out = [1 1 1 1 0 1 1 0 1 1 %! 1 1 0 1 1 0 0 1 1 0 %! 1 0 1 0 1 0 0 0 1 1 %! 1 0 0 1 0 1 0 1 0 1 %! 1 0 1 0 1 0 1 0 1 0 %! 1 0 0 1 0 1 0 1 0 1 %! 1 0 0 0 0 0 1 0 1 0 %! 1 0 0 0 0 0 1 1 0 1 %! 1 0 0 0 1 1 0 0 1 1 %! 1 1 1 1 0 1 0 1 1 0]; %!assert (bwperim (in), logical (out)); %!assert (bwperim (in, 4), logical (out)); %! %! out = [1 1 1 1 0 1 1 0 1 1 %! 1 1 0 1 1 1 1 1 1 0 %! 1 1 1 0 1 1 0 1 1 1 %! 1 0 1 1 0 1 0 1 0 1 %! 1 0 1 0 1 1 1 1 1 0 %! 1 0 1 1 1 1 0 1 0 1 %! 1 0 0 0 0 1 1 1 1 0 %! 1 0 0 0 0 1 1 1 1 1 %! 1 0 0 1 1 1 0 0 1 1 %! 1 1 1 1 0 1 0 1 1 0]; %!assert (bwperim (in, 8), logical (out)); %! %! out = [1 1 1 1 0 1 1 0 1 1 %! 1 0 0 0 0 1 0 0 1 0 %! 1 0 0 0 0 0 0 1 0 1 %! 1 0 1 0 0 0 0 0 0 1 %! 1 0 0 0 0 1 0 1 0 0 %! 1 0 0 0 1 0 0 0 0 1 %! 1 0 0 0 0 0 0 1 0 0 %! 1 0 0 0 0 1 1 0 0 1 %! 1 0 0 1 0 1 0 0 1 1 %! 1 1 1 1 0 1 0 1 1 0]; %!assert (bwperim (in, [1 0 0; 0 1 0; 0 0 1]), logical (out)); ## test that any non-zero value is valid (even i and Inf) %!shared in, out %! in = [ 0 0 0 0 0 0 0 %! 0 0 5 0 0 1 9 %! 0 Inf 9 7 0 0 0 %! 0 1.5 5 7 1 0 0 %! 0 0.5 -1 89 i 0 0 %! 0 4 10 15 1 0 0 %! 0 0 0 0 0 0 0]; %! out = [0 0 0 0 0 0 0 %! 0 0 1 0 0 1 1 %! 0 1 0 1 0 0 0 %! 0 1 0 0 1 0 0 %! 0 1 0 0 1 0 0 %! 0 1 1 1 1 0 0 %! 0 0 0 0 0 0 0]; %!assert (bwperim (in), logical (out)); ## test for 3D %!shared in, out %! in = reshape (magic(16), [8 8 4]) > 50; %! out(:,:,1) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 1 1 1 1 0 1 %! 1 1 0 1 1 1 1 1 %! 1 1 1 1 1 1 1 1 %! 1 1 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,2) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 0 1 1 0 1 %! 0 1 0 0 0 1 0 1 %! 1 0 1 0 0 0 1 1 %! 1 0 0 1 0 1 0 1 %! 1 0 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,3) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 0 1 1 0 1 %! 0 1 0 0 0 1 0 1 %! 1 0 0 0 0 0 1 1 %! 1 0 0 1 0 1 0 1 %! 1 0 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,4) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 1 1 1 1 0 1 %! 1 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 1 0 %! 1 1 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %!assert (bwperim (in), logical (out)); %! %! out(:,:,1) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 1 1 1 1 0 1 %! 1 1 0 1 1 1 1 1 %! 1 1 1 1 1 1 1 1 %! 1 1 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,2) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 1 0 0 1 0 1 %! 1 1 1 1 0 1 1 1 %! 1 0 1 1 1 1 1 1 %! 1 0 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,3) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 0 0 0 1 0 1 %! 1 1 0 0 0 1 1 1 %! 1 0 1 1 1 1 1 1 %! 1 0 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %! out(:,:,4) = [ %! 1 1 0 1 0 1 1 1 %! 0 1 1 1 1 1 0 1 %! 0 1 1 1 1 1 0 1 %! 1 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 1 0 %! 1 1 1 0 1 0 1 1 %! 1 1 1 0 1 0 1 1 %! 1 0 1 1 1 1 1 0]; %!assert (bwperim (in, 18), logical (out)); %!error bwperim ("text") %!error bwperim (rand (10), 5) %!error bwperim (rand (10), "text") %!test %! a = false (5); %! a(1:4,2:4) = true; %! %! p = false (5); %! p(1:4,[2 4]) = true; %! assert (bwperim (a, [0 0 0; 1 1 1; 0 0 0]), p) image-2.4.1/inst/PaxHeaders.6632/imgradientxy.m0000644000000000000000000000013212561122761016117 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imgradientxy.m0000644000175000017500000000770012561122761020746 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Brandon Miles ## ## 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 3 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{gradX}, @var{gradY}] =} imgradientxy (@var{img}) ## @deftypefnx {Function File} {[@var{gradX}, @var{gradY}] =} imgradientxy (@var{img}, @var{method}) ## Compute the x and y gradients of an image using various methods. ## ## The first input @var{img} is the gray scale image to compute the edges ## on. The second input @var{method} controls the method used to calculate ## the gradients. ## ## The first output @var{gradX} returns the gradient in the x direction. ## The second output @var{gradY} returns the gradient in the y direction. ## ## The @var{method} input argument can be any of the following strings: ## ## @table @asis ## @item @qcode{"sobel"} (default) ## Calculates the gradient using the Sobel approximation to the ## derivatives. ## ## @item @qcode{"prewitt"} ## Calculates the gradient using the Prewitt approximation to the ## derivatives. This method works just like Sobel except a different ## approximation of the gradient is used. ## ## @item @qcode{"central difference"} ## Calculates the gradient using the central difference approximation to the ## derivatives: @code{(x(i-1) - x(i+1))/2}. ## ## @item @qcode{"intermediate difference"} ## Calculates the gradient in using the intermediate difference approximation ## to the derivatives: @code{x(i) - x(i+1)}. ## ## @end table ## ## @seealso{edge, imgradient} ## @end deftypefn function [gradX, gradY] = imgradientxy (img, method = "sobel") if (nargin < 1 || nargin > 2) print_usage (); elseif (! isgray (img)) error ("imgradientxy: IMG must be a gray-scale image"); elseif (! ischar (method)) error ("imgradientxy: METHOD must be a string"); endif switch (tolower (method)) case {"sobel", "prewitt"} ker = fspecial (method); # horizontal case {"centraldifference"} ker = [0.5; 0; -0.5]; case {"intermediatedifference"} ker = [1; -1]; otherwise error("imgradientxy: unrecognized METHOD %s", method); endswitch gradX = conv2 (img, ker', "same"); if (nargout > 1) gradY = conv2 (img, ker, "same"); endif endfunction %!test %! A = [0 1 0 %! 1 1 1 %! 0 1 0]; %! %! [gxSobel, gySobel] = imgradientxy (A); %! [gxSobel2, gySobel2] = imgradientxy (A, "Sobel"); %! assert (gxSobel, %! [ 3 0 -3 %! 4 0 -4 %! 3 0 -3]); %! assert (gySobel, %! [ 3 4 3 %! 0 0 0 %! -3 -4 -3]); %! %! ## test default method %! assert(gxSobel, gxSobel2); %! assert(gySobel, gySobel2); %! %! [gxPrewitt, gyPrewitt] = imgradientxy (A, "Prewitt"); %! assert (gxPrewitt, %! [ 2 0 -2 %! 3 0 -3 %! 2 0 -2]); %! assert (gyPrewitt, %! [ 2 3 2 %! 0 0 0 %! -2 -3 -2]); %! %! [gxCd, gyCd] = imgradientxy (A, "CentralDifference"); %! assert (gxCd, %! [ 0.5 0.0 -0.5 %! 0.5 0.0 -0.5 %! 0.5 0.0 -0.5]); %! assert (gyCd, %! [ 0.5 0.5 0.5 %! 0 0 0 %! -0.5 -0.5 -0.5]); %! %! [gxId, gyId] = imgradientxy(A, "IntermediateDifference"); %! assert (gxId, %! [ 1 -1 0 %! 0 0 -1 %! 1 -1 0]); %! assert (gyId, %! [ 1 0 1 %! -1 0 -1 %! 0 -1 0]); image-2.4.1/inst/PaxHeaders.6632/imadjust.m0000644000000000000000000000013212561122761015233 xustar0030 mtime=1438950897.742252238 30 atime=1438950897.742252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imadjust.m0000644000175000017500000002676212561122761020073 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999,2000 Kai Habel ## 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 3 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{J} =} imadjust (@var{I}) ## @deftypefnx {Function File} {@var{J} =} imadjust (@var{I},[@var{low_in};@var{high_in}]) ## @deftypefnx {Function File} {@var{J} =} imadjust (@var{I},[@var{low_in};@var{high_in}],[@var{low_out};@var{high_out}]) ## @deftypefnx {Function File} {@var{J} =} imadjust (@dots{}, @var{gamma}) ## @deftypefnx {Function File} {@var{newmap} =} imadjust (@var{map}, @dots{}) ## @deftypefnx {Function File} {@var{RGB_out} =} imadjust (@var{RGB}, @dots{}) ## Adjust image or colormap values to a specified range. ## ## @code{J=imadjust(I)} adjusts intensity image @var{I} values so that ## 1% of data on lower and higher values (2% in total) of the image is ## saturated; choosing for that the corresponding lower and higher ## bounds (using @code{stretchlim}) and mapping them to 0 and 1. @var{J} ## is an image of the same size as @var{I} which contains mapped values. ## This is equivalent to @code{imadjust(I,stretchlim(I))}. ## ## @code{J=imadjust(I,[low_in;high_in])} behaves as described but uses ## @var{low_in} and @var{high_in} values instead of calculating them. It ## maps those values to 0 and 1; saturates values lower than first limit ## to 0 and values higher than second to 1; and finally maps all values ## between limits linearly to a value between 0 and 1. If @code{[]} is ## passes as @code{[low_in;high_in]} value, then @code{[0;1]} is taken ## as a default value. ## ## @code{J=imadjust(I,[low_in;high_in],[low_out;high_out])} behaves as ## described but maps output values between @var{low_out} and ## @var{high_out} instead of 0 and 1. A default value @code{[]} can also ## be used for this parameter, which is taken as @code{[0;1]}. ## ## @code{J=imadjust(@dots{},gamma)} takes, in addition of 3 parameters ## explained above, an extra parameter @var{gamma}, which specifies the ## shape of the mapping curve between input elements and output ## elements, which is linear (as taken if this parameter is omitted). If ## @var{gamma} is above 1, then function is weighted towards lower ## values, and if below 1, towards higher values. ## ## @code{newmap=imadjust(map,@dots{})} applies a transformation to a ## colormap @var{map}, which output is @var{newmap}. This transformation ## is the same as explained above, just using a map instead of an image. ## @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and ## @var{gamma} can be scalars, in which case the same values are applied ## for all three color components of a map; or it can be 1-by-3 ## vectors, to define unique mappings for each component. ## ## @code{RGB_out=imadjust(RGB,@dots{})} adjust RGB image @var{RGB} (a ## M-by-N-by-3 array) the same way as specified in images and colormaps. ## Here too @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and ## @var{gamma} can be scalars or 1-by-3 matrices, to specify the same ## mapping for all planes, or unique mappings for each. ## ## The formula used to realize the mapping (if we omit saturation) is: ## ## @code{J = low_out + (high_out - low_out) .* ((I - low_in) / (high_in - low_in)) .^ gamma;} ## ## @strong{Compatibility notes:} ## ## @itemize @bullet ## @item ## Prior versions of imadjust allowed @code{[low_in; high_in]} and ## @code{[low_out; high_out]} to be row vectors. Compatibility with this ## behaviour has been kept, although preferred form is vertical vector ## (since it extends nicely to 2-by-3 matrices for RGB images and ## colormaps). ## @item ## Previous version of imadjust, if @code{low_in>high_in} it "negated" output. ## Now it is negated if @code{low_out>high_out}, for compatibility with ## MATLAB. ## @item ## Class of @var{I} is not considered, so limit values are not ## modified depending on class of the image, just treated "as is". When ## Octave 2.1.58 is out, limits will be multiplied by 255 for uint8 ## images and by 65535 for uint16 as in MATLAB. ## @end itemize ## ## @seealso{stretchlim, brighten} ## @end deftypefn ## TODO: When Octave 2.1.58 is out multiply indices if input argument is ## TODO: of class int* or uint*. function ret = imadjust (image, in = stretchlim (image), out = [0;1], gamma = 1) if (nargin < 1 || nargin > 4) print_usage; endif if (! isimage (image) && ! iscolormap (image)) error ("imadjust(image,...) first parameter must be a image matrix or colormap"); endif ## IN and OUT can be empty to use default values if (! isnumeric (in) || ! isnumeric (out)) error ("imadjust: IN and OUT must be numeric arrays"); endif if (isempty (in)) in=[0;1]; ## default in endif if (isempty (out)) out=[0;1]; ## default out endif simage=size(image); if (length(simage)==3 && simage(3)==3) ## image is rgb [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); ## make room ret=zeros(size(image)); ## process each plane for i=1:3 ret(:,:,i)=__imadjust_plane__(image(:,:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(1,i)); endfor elseif (length(simage)==2) if(simage(2)==3 && ... (size(in)==[2,3] || size(out)==[2,3] || size(gamma)==[1,3]) ) ## image is a colormap [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); ret=[]; ## process each color for i=1:3 ret=horzcat(ret,__imadjust_plane__(image(:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(i))); endfor else ## image is a intensity image if( !isvector(in) || length(in)!=2 || !isvector(out) || length(out)!=2 || !isscalar(gamma) || (gamma<0) || (gamma==Inf) ) error("imadjust: on an intensity image, in and out must be 2-by-1 and gamma a positive scalar."); endif ret=__imadjust_plane__(image,in(1),in(2),out(1),out(2),gamma); endif else error("imadjust: first parameter must be a colormap, an intensity image or a RGB image"); endif endfunction ## This does all the work. I has a plane; li and hi input low and high ## values; and lo and ho, output bottom and top values. ## Image negative is computed if ho= li & I < hi) .* (lo + (ho - lo) .* ((I - li) / (hi - li)) .^ gamma); ret = ret + (I >= hi) .* ho; endfunction ## Checks in, out and gamma to see if they are ok for colormap and RGB ## cases. function [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma) switch(size(in)) case([2,3]) ## ok! case([2,1]) in=repmat(in,1,3); case([1,2]) ## Compatibility behaviour! in=repmat(in',1,3); otherwise error("imadjust: in must be 2-by-3 or 2-by-1."); endswitch switch(size(out)) case([2,3]) ## ok! case([2,1]) out=repmat(out,1,3); case([1,2]) ## Compatibility behaviour! out=repmat(out',1,3); otherwise error("imadjust: out must be 2-by-3 or 2-by-1."); endswitch switch(size(gamma)) case([1,3]) ## ok! case([1,1]) gamma=repmat(gamma,1,3); otherwise error("imadjust: gamma must be a scalar or a 1-by-3 matrix."); endswitch ## check gamma allowed range if(!all((gamma>=0)&(gamma ## ## 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 3 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{S} =} stdfilt (@var{im}) ## @deftypefnx{Function File} {@var{S} =} stdfilt (@var{im}, @var{domain}) ## @deftypefnx{Function File} {@var{S} =} stdfilt (@var{im}, @var{domain}, @var{padding}, @dots{}) ## Computes the local standard deviation in a neighbourhood around each pixel in ## an image. ## ## The standard deviation of the pixels of a neighbourhood is computed as ## ## @example ## @var{S} = sqrt ((sum (@var{x} - @var{mu}).^2)/(@var{N}-1)) ## @end example ## ## where @var{mu} is the mean value of the pixels in the neighbourhood, ## @var{N} is the number of pixels in the neighbourhood. So, an unbiased estimator ## is used. ## ## The neighbourhood is defined by the @var{domain} binary mask. Elements of the ## mask with a non-zero value are considered part of the neighbourhood. By default ## a 3 by 3 matrix containing only non-zero values is used. ## ## At the border of the image, extrapolation is used. By default symmetric ## extrapolation is used, but any method supported by the @code{padarray} function ## can be used. Since extrapolation is used, one can expect a lower deviation near ## the image border. ## ## @seealso{std2, paddarray, entropyfilt} ## @end deftypefn function retval = stdfilt (I, domain = true (3), padding = "symmetric", varargin) ## Check input if (nargin == 0) error ("stdfilt: not enough input arguments"); endif if (! isimage (I)) error ("stdfilt: first input must be a matrix"); endif if (! isnumeric (domain) && ! islogical (domain)) error ("stdfilt: second input argument must be a logical matrix"); endif domain = logical (domain); ## Pad image pad = floor (size (domain)/2); I = padarray (I, pad, padding, varargin {:}); even = (round (size (domain)/2) == size (domain)/2); idx = cell (1, ndims (I)); for k = 1:ndims (I) idx {k} = (even (k)+1):size (I, k); endfor I = I (idx {:}); ## Perform filtering retval = __spatial_filtering__ (I, domain, "std", I, 0); endfunction %!test %! im = stdfilt (ones (5)); %! assert (im, zeros (5)); image-2.4.1/inst/PaxHeaders.6632/imtransform.m0000644000000000000000000000013212561122761015754 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imtransform.m0000644000175000017500000003330612561122761020604 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{B} =} imtransform (@var{A}, @var{T}) ## @deftypefnx {Function File} {@var{B} =} imtransform (@var{A}, @var{T}, @var{interp}) ## @deftypefnx {Function File} {@var{B} =} imtransform (@dots{}, @var{prop}, @var{val}) ## @deftypefnx {Function File} {[@var{B}, @var{xdata}, @var{ydata}] =} imtransform (@dots{}) ## Transform image. ## ## Given an image @var{A} in one space, returns an image @var{B} ## resulting from the forward transform defined in the transformation ## structure @var{T}. An additionnal input argument @var{interp}, ## 'bicubic', 'bilinear' (default) or 'nearest', ## specifies the interpolation method to be used. Finally, the ## transformation can be tuned using @var{prop}/@var{val} pairs. The ## following properties are supported: ## ## @table @asis ## @item "udata" ## Specifies the input space horizontal limits. Value must be a two ## elements vector [minval maxval]. Default: [1 columns(@var{A})] ## ## @item "vdata" ## Specifies the input space vertical limits. Value must be a two ## elements vector [minval maxval]. Default: [1 rows(@var{A})] ## ## @item "xdata" ## Specifies the required output space horizontal limits. Value must ## be a two elements vector [minval maxval]. Default: estimated using ## udata, vdata and findbounds function. ## ## @item "ydata" ## Specifies the required output space vertical limits. Value must ## be a two elements vector [minval maxval]. Default: estimated using ## udata, vdata and findbounds function. ## ## @item "xyscale" ## Specifies the output scale in outputspace_units/pixel. If a scalar ## is provided, both vertical and horizontal dimensions are scaled the ## same way. If @var{val} is a two element vector, it must indicate ## consecutively horizontal and vertical scales. Default value is ## computed using the input space scale provided ## that the number of pixel of any dimension of the output image does ## not exceed 20000. ## ## @item "size" ## Size of the output image (1-by-2 vector). Overrides the effect of ## "xyscale" property. ## ## @item "fillvalues" ## Color of the areas where no interpolation where possible, e.g. when ## coorfinates of points in the output space are out of the limits of ## the input space. @var{val} must be coherent with the input image ## format: for grayscale and indexed images (2D) @var{val} must be ## scalar, for RGB (n-by-m-by-3) @var{val} must be a 3 element vector. ## ## @end table ## ## The actual output limits, @var{xdata} and @var{ydata} vectors, ## are returned respectively as second and third output variables. ## @seealso{maketform, cp2tform, tforminv, tformfwd, findbounds} ## @end deftypefn ## Author: Pantxo Diribarne function [varargout] = imtransform (im, T, varargin) if (nargin < 2) print_usage (); elseif (! istform (T)) error ("imtransform: T must be a transformation structure (see `maketform')"); endif ## Parameters interp = "linear"; imdepth = size (im, 3); maximsize = [20000 20000]; udata = [1; columns(im)]; vdata = [1; rows(im)]; xdata = ydata = []; xyscale = []; imsize = []; fillvalues = ones (1, imdepth) * NaN; if (isempty (varargin)) xydata = findbounds (T, [udata vdata]); xdata = xydata(:,1); ydata = xydata(:,2); else ## interp if (floor (numel (varargin)/2) != numel (varargin)/2) allowed = {"bicubic", "bilinear", "nearest"}; tst = strcmp (varargin{1}, allowed); if (!any (tst)) error ("imtransform: expect one of %s as interp method", disp (allowed)); else interp = {"pchip", "linear", "nearest"}{find (tst)}; endif varargin = varargin(2:end); endif ## options allowed = {"udata", "vdata", "xdata", "ydata", ... "xyscale", "size", "fillvalues"}; props = varargin(1:2:end); vals = varargin(2:2:end); np = numel (props); if (!all (cellfun (@ischar, props))) error ("imtransform: expect property/value pairs."); endif props = tolower (props); tst = cellfun (@(x) any (strcmp (x, allowed)), props); if (!all (tst)) error ("imtransform: unknown property %s", disp (props{!tst})); endif ## u(vxy)data iolims = allowed(1:4); for ii = 1:numel (iolims) tst = cellfun (@(x) any (strcmp (x, iolims{ii})), props); if (any (tst)) prop = props{find (tst)(1)}; val = vals{find (tst)(1)}; if (isnumeric (val) && numel (val) == 2) if (isrow (val)) val = val'; endif eval (sprintf ("%s = val;", prop), "error (\"imtransform: %s\n\", lasterr ());"); else error ("imtransform: expect 2 elements real vector for %s", prop) endif endif endfor if (isempty (xdata) && isempty (ydata)) xydata = findbounds (T, [udata vdata]); xdata = xydata(:,1); ydata = xydata(:,2); elseif (isempty (xdata)) xydata = findbounds (T, [udata vdata]); xdata = xydata(:,1); elseif (isempty (ydata)) xydata = findbounds (T, [udata vdata]); ydata = xydata(:,2); endif ## size and xyscale tst = strcmp ("size", props); if (any (tst)) val = vals{find (tst)(1)}; if (isnumeric (val) && numel (val) == 2 && all (val > 0)) imsize = val; else error ("imtransform: expect 2 elements real vector for size"); endif elseif (any (tst = strcmp ("xyscale", props))) val = vals{find (tst)(1)}; if (isnumeric (val) && all (val > 0)) if (numel (val) == 1) xyscale(1:2) = val; elseif (numel (val) == 2) xyscale = val; else error ("imtransform: expect 1 or 2 element(s) real vector for xyscale"); endif else error ("imtransform: expect 1 or 2 elements real vector for xyscale"); endif else xyscale = [(diff (udata) / columns (im)) (diff (vdata) / rows (im))]; endif ## Fillvalues tst = strcmp ("fillvalues", props); if (any (tst)) val = vals{find (tst)(1)}; if (isnumeric (val) && numel (val) == 1) fillvalues(1:end) = val; elseif (isnumeric (val) && numel (val) == 3) fillvalues = val; else error ("imtransform: expect 1 or 3 elements real vector for `fillvalues'"); endif endif endif ## Output/Input pixels if (isempty (imsize)) if (isempty (xyscale)) xyscale = [(diff (udata) / columns (im)) (diff (vdata) / rows (im))]; endif xscale = xyscale(1); yscale = xyscale(2); xsize = floor (diff (xdata) / xscale); ysize = floor (diff (ydata) / yscale); if (xsize > maximsize(2) || ysize > maximsize(1)) if (xsize >= ysize) scalefactor = (diff (xdata) / maximsize(2)) / xscale; else scalefactor = (diff (ydata) / maximsize(1)) / yscale; endif xscale *= scalefactor yscale *= scalefactor xsize = floor (diff (xdata) / xscale); ysize = floor (diff (ydata) / yscale); warning ("imtransform: output image two large, adjusting the largest dimension to %d", maximsize); endif imsize = [ysize xsize]; endif [xx yy] = meshgrid (linspace (xdata(1), xdata(2), imsize(2)), linspace (ydata(1), ydata(2), imsize(1))); [uu vv] = meshgrid (linspace (udata(1), udata(2), size(im)(2)), linspace (vdata(1), vdata(2), size(im)(1))); ## Input coordinates [uui, vvi] = tforminv (T, reshape (xx, numel (xx), 1), reshape (yy, numel (yy), 1)); uui = reshape (uui, size (xx)); vvi = reshape (vvi, size (yy)); ## Interpolation for layer = 1:imdepth imout(:,:,layer) = interp2 (uu, vv, im(:,:,layer), ... uui, vvi, interp, fillvalues(layer)); endfor if (nargout == 1) varargout{1} = imout; else varargout = {imout, xdata, ydata}; endif endfunction %!demo %! ## Various linear transforms %! figure (); %! im = [checkerboard(20, 2, 4); checkerboard(40, 1, 2)]; %! %input space corners %! incp = [1 1; 160 1; 160 160; 1 160]; %! udata = [min(incp(:,1)) max(incp(:,1))]; %! vdata = [min(incp(:,2)) max(incp(:,2))]; %! subplot (2,3,1); %! imshow (im) %! hold on %! plot (incp(:,1), incp(:,2), 'ob') %! axis on %! xlabel ('Original') %! %! % Translation and scaling %! outcp = incp * 2; %! outcp(:,1) += 200; %! outcp(:,2) += 500; %! T = maketform ('affine', incp(1:3,:), outcp(1:3,:)); %! subplot (2,3,2); %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata, %! 'vdata', vdata, 'fillvalues', 1); %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! axis on, hold on, xlabel ('Translation / Scaling'); %! plot (outcp(:,1), outcp(:,2), 'or') %! %! % Shear %! outcp = [1 1; 160 1; 140 160; -19 160]; % affine only needs 3 control points %! T = maketform ('affine', incp(1:3,:), outcp(1:3,:)); %! subplot (2,3,3); %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata, %! 'vdata', vdata, 'fillvalues', 1); %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! axis on, hold on, xlabel ('Shear'); %! plot (outcp(:,1), outcp(:,2), 'or') %! %! % Rotation %! theta = pi/4; %! T = maketform ('affine', [cos(theta) -sin(theta); ... %! sin(theta) cos(theta); 0 0]); %! outcp = tformfwd (T, incp); %! subplot (2,3,4); %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata, %! 'vdata', vdata, 'fillvalues', 1 ); %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! axis on, hold on, xlabel ('Rotation'); %! plot (outcp(:,1), outcp(:,2), 'or') %! %! % Reflection around x axis %! outcp = incp; %! outcp(:,2) *= -1; %! T = cp2tform (incp, outcp, 'similarity'); %! subplot (2,3,5); %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata, %! 'vdata', vdata, 'fillvalues', 1 ); %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! axis on, hold on, xlabel ('Reflection'); %! plot (outcp(:,1), outcp(:,2), 'or') %! %! % Projection %! outcp = [1 1; 160 -40; 220 220; 12 140]; %! T = maketform ('projective', incp, outcp); %! subplot (2,3,6); %! [im2 xdata ydata] = imtransform (im, T, 'udata', udata, %! 'vdata', vdata, 'fillvalues', 1 ); %! imh = imshow (im2); set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! axis on, hold on, xlabel ('Projection'); %! plot (outcp(:,1), outcp(:,2), 'or') %!demo %! ## Streched image %! rad = 2; % minimum value: 4/pi %! [uu vv] = meshgrid ((-2:2)/rad, (-2:2)/rad); %! rescfactor = sin ((uu.^2 + vv.^2).^.5); %! inpts = [(reshape (uu, numel (uu), 1)), (reshape (vv, numel (uu), 1))]; %! xx = rescfactor .* sign(uu); %! yy = rescfactor .* sign(vv); %! outpts = [reshape(xx, numel (xx), 1) reshape(yy, numel (yy), 1)]; %! %! T = cp2tform (inpts, outpts, "polynomial", 4); %! figure; %! subplot (1,2,1) %! im = zeros (800, 800, 3); %! im(:,:,1) = checkerboard (100) > 0.2; %! im(:,:,3) = checkerboard (100) < 0.2; %! [im2 xdata ydata] = imtransform (im, T, 'udata', [-2 2], %! 'vdata', [-2 2], 'fillvalues', %! [0 1 0]); %! imh = imshow (im2); %! set (imh, 'xdata', xdata, 'ydata', ydata) %! set (gca, 'xlim', xdata, 'ylim', ydata) %! [im cmap] = imread ('default.img'); %! subplot (1,2,2) %! [im2 xdata ydata] = imtransform (im, T, 'udata', [-1 1], %! 'vdata', [-1 1], 'fillvalues', %! round (length (cmap) / 2)); %! imh = imshow (im2, cmap); %!test %! im = checkerboard (); %! incp = [0 0; 0 1; 1 1]; %! scl = 10; %! outcp = scl * incp; %! T = maketform ('affine', incp, outcp); %! [im2 xdata ydata] = imtransform (im, T, 'udata', [0 1], %! 'vdata', [0 1], 'size', [500 500]); %! assert (xdata, scl * ([0; 1])) %! assert (ydata, scl * ([0; 1])) %! assert (size (im2), [500 500]) %!test %! im = checkerboard (); %! incp = [0 0; 0 1; 1 1]; %! scl = 10; %! outcp = scl * incp; %! xyscale = scl; %! T = maketform ('affine', incp, outcp); %! [im2 xdata ydata] = imtransform (im, T, 'xyscale', xyscale); %! assert (size (im2), size (im), 1) %!test %! im = checkerboard (100, 10, 4); %! theta = 2 * pi; %! T = maketform ('affine', [cos(theta) -sin(theta); ... %! sin(theta) cos(theta); 0 0]); %! im2 = imtransform (im, T, 'nearest'); %! im = im(2:end-1, 2:end-1); %avoid boundaries %! im2 = im2(2:end-1, 2:end-1); %! assert (im, im2) %!test %! im = checkerboard (20, 10, 4); %! theta = pi/6; %! T = maketform ('affine', [cos(theta) -sin(theta); ... %! sin(theta) cos(theta); 0 0]); %! [im2 xdata ydata] = imtransform (im, T); %! udata = [1 columns(im)]; %! vdata = [1 rows(im)]; %! diag = sqrt (udata(2)^2 + vdata(2)^2); %! ang = atan (vdata(2) / udata(2)); %! assert (max (abs (xdata)), diag * abs (cos (theta - ang)), %! max (size (im)) * eps) image-2.4.1/inst/PaxHeaders.6632/rgb2gray.m0000644000000000000000000000013212561122761015132 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/rgb2gray.m0000644000175000017500000000461212561122761017760 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000, 2001 Kai Habel ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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{gray}= rgb2gray (@var{rgb}) ## Convert RGB image or colormap to grayscale. ## ## If @var{rgb} is an RGB image, the conversion to grayscale is weighted based ## on the luminance values (see @code{rgb2ntsc}). Supported classes are single, ## double, uint8 and uint16. ## ## If @var{rgb} is a colormap it is converted into the YIQ space of ntsc. The ## luminance value (Y) is taken to create a gray colormap. ## ## @seealso{mat2gray, ntsc2rgb, rgb2ind, rgb2ntsc, rgb2ycbcr} ## @end deftypefn function gray = rgb2gray (rgb) if (nargin != 1) print_usage(); endif if (iscolormap (rgb)) gray = rgb2ntsc (rgb) (:, 1) * ones (1, 3); elseif (isimage (rgb) && ndims (rgb) == 3) ## multiply each color by the luminance factor (this is also matlab compatible) ## 0.29894 * red + 0.58704 * green + 0.11402 * blue gray = im2double (rgb) .* permute ([0.29894, 0.58704, 0.11402], [1, 3, 2]); gray = sum (gray, 3); switch (class (rgb)) case {"single", "double"} ## do nothing. All is good case "uint8" gray = im2uint8 (gray); case "uint16" gray = im2uint16 (gray); otherwise error ("rgb2gray: unsupported class %s", class(rgb)); endswitch else error ("rgb2gray: the input must either be an RGB image or a colormap"); endif endfunction # simplest test, double image, each channel on its own and then all maxed %!shared img %! img = zeros (2, 2, 3); %! img(:,:,1) = [1 0; 0 1]; %! img(:,:,2) = [0 1; 0 1]; %! img(:,:,3) = [0 0; 1 1]; %! img = rgb2gray (img); %!assert ([img(1,1) img(1,2) img(2,1) img(2,2)], [0.29894 0.58704 0.11402 1]); image-2.4.1/inst/PaxHeaders.6632/bwboundaries.m0000644000000000000000000000013212561122761016077 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwboundaries.m0000644000175000017500000000733512561122761020732 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Søren Hauberg ## Copyright (C) Andrew Kelly, IPS Radio & Space Services ## ## 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 3 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{boundaries} = } bwboundaries(@var{BW}) ## @deftypefnx {Function File} {@var{boundaries} = } bwboundaries(@var{BW}, @var{conn}) ## @deftypefnx {Function File} {@var{boundaries} = } bwboundaries(@var{BW}, @var{conn}, @var{holes}) ## @deftypefnx {Function File} {[@var{boundaries}, @var{labels}] = } bwboundaries(@dots{}) ## @deftypefnx {Function File} {[@var{boundaries}, @var{labels}, @var{num_labels}] = } bwboundaries(@dots{}) ## Trace the boundaries of the objects in a binary image. ## ## @var{boundaries} is a cell array in which each element is the boundary of an ## object in the binary image @var{BW}. The clockwise boundary of each object is ## computed by the @code{boundary} function. ## ## By default the boundaries are computed using 8-connectivity. This can be ## changed to 4-connectivity by setting @var{conn} to 4. ## ## By default @code{bwboundaries} computes all boundaries in the image, i.e. ## both interior and exterior object boundaries. This behaviour can be changed ## through the @var{holes} input argument. If this is @t{'holes'}, ## both boundary types are considered. If it is instead @t{'noholes'}, only exterior ## boundaries will be traced. ## ## If two or more output arguments are requested, the algorithm also returns ## the labelled image computed by @code{bwlabel} in @var{labels}. The number ## of labels in this image is optionally returned in @var{num_labels}. ## @seealso{bwlabel, bwlabeln, bwperim, fchcode} ## @end deftypefn function [bound, labels, num_labels] = bwboundaries (bw, conn=8, holes="holes") # check arguments if (nargin < 1) error ("bwboundaries: not enough input arguments"); endif if (! ismatrix (bw)) error ("bwboundaries: first input argument must be a NxM matrix"); endif if (!isscalar (conn) || (conn != 4 && conn != 8)) error ("bwboundaries: second input argument must be 4 or 8"); endif if (!ischar (holes) || !any (strcmpi (holes, {'holes', 'noholes'}))) error ("bwboundaries: third input must be either \'holes\' or \'noholes\'"); endif bw = logical (bw); # process each connected region separately [labels, num_labels] = bwlabel (bw, conn); bound = cell (num_labels, 1); for k = 1:num_labels bound {k} = __boundary__ ((labels == k), conn); endfor # compute internal boundaries as well? if (strcmpi (holes, "holes")) filled = bwfill (bw, "holes", conn); holes = (filled & !bw); [intBounds, intLabels, numIntLabels] = bwboundaries (holes, conn, "noholes"); bound (end+1 : end+numIntLabels, 1) = intBounds; intLabels (intLabels != 0) += num_labels; labels += intLabels; endif endfunction %!demo %! ## Generate a simple image %! bw = false (100); %! bw (10:30, 40:80) = true; %! bw (40:45, 40:80) = true; %! %! ## Find boundaries %! bounds = bwboundaries (bw); %! %! ## Plot result %! imshow (bw); %! hold on %! for k = 1:numel (bounds) %! plot (bounds {k} (:, 2), bounds {k} (:, 1), 'r', 'linewidth', 2); %! endfor %! hold off image-2.4.1/inst/PaxHeaders.6632/analyze75read.m0000644000000000000000000000013212561122761016066 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/analyze75read.m0000644000175000017500000000502312561122761020711 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012-2013 Adam H Aitkenhead ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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{image} =} analyze75read (@var{filename}) ## @deftypefnx {Function File} {@var{image} =} analyze75read (@var{header}) ## Read image data of an Analyze 7.5 file. ## ## @var{filename} must be the path for an Analyze 7.5 file or the path for a ## directory with a single .hdr file can be specified. Alternatively, the file ## @var{header} can be specified as returned by @code{analyze75info}. ## ## @seealso{analyze75info, analyze75write} ## @end deftypefn function data = analyze75read (filename) if (nargin != 1) print_usage; elseif (isstruct (filename)) if (!isfield (filename, "Filename")) error ("analyze75read: structure given does not have a `Filename' field."); else header = filename; filename = filename.Filename; endif elseif (!ischar (filename)) error ("analyze75read: `filename' must be either a string or a structure."); endif fileprefix = analyze75filename (filename); if (!exist ("header", "var")) header = analyze75info ([fileprefix, ".hdr"]); endif ## Finally start reading the actual file [fidI, err] = fopen ([fileprefix, ".img"]); if (fidI < 0) error ("analyze75read: unable to fopen `%s': %s", [fileprefix, ".img"], err); endif if (strcmp (header.ImgDataType, "DT_SIGNED_SHORT")); datatype = "int16"; elseif (strcmp (header.ImgDataType, "DT_SIGNED_INT")); datatype = "int32"; elseif (strcmp (header.ImgDataType, "DT_FLOAT")); datatype = "single"; elseif (strcmp (header.ImgDataType, "DT_DOUBLE")); datatype = "double"; endif data = zeros (header.Dimensions, datatype); data(:) = fread (fidI, datatype, header.ByteOrder); fclose (fidI); ## Rearrange the data data = permute (data, [2,1,3]); endfunction image-2.4.1/inst/PaxHeaders.6632/bestblk.m0000644000000000000000000000013212561122761015041 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bestblk.m0000644000175000017500000000654312561122761017674 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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{blk_size} =} bestblk (@var{IMS}) ## @deftypefnx {Function File} {@var{blk_size} =} bestblk (@var{IMS}, @var{max}) ## @deftypefnx {Function File} {[@var{Mb}, @var{Nb}, @dots{}] =} bestblk (@dots{}) ## Calculate block best size for block processing. ## ## Given a matrix of size @var{IMS}, calculates the largest size for distinct ## blocks @var{blk_size}, that minimize padding and is smaller than or equal to ## @var{k} (defaults to 100) ## ## The output @var{blk_size} is a row vector for the block size. If there are ## multiple output arguments, the number of rows is assigned to the first ## (@var{Mb}), and the number of columns to the second (@var{Nb}), etc. ## ## To determine @var{blk_size}, the following is performed for each ## dimension: ## ## @enumerate ## @item ## If dimension @var{IMS} is less or equal than @var{k}, it returns the ## dimension value. ## ## @item ## If not, find the highest value between @code{min (dimension/10, k/2)} ## which minimizes padding. ## ## @end enumerate ## ## @seealso{blockproc, col2im, im2col} ## @end deftypefn function [varargout] = bestblk (ims, k = 100) if (nargin < 1 || nargin > 2) print_usage (); elseif (! isnumeric (ims) || ! isvector (ims) || any (ims(:) < 1)) error("bestblk: IMS must be a numeric vector of positive integers."); elseif (numel (ims) < 2) error ("bestblk: IMS must have at least 2 elements"); elseif (! isnumeric (k) || ! isscalar (k) || k < 1) error ("bestblk: K must be a positive scalar"); endif ims = floor (ims(:).'); k = floor (k); out = zeros (size (ims)); for dim = 1:numel (ims) if (ims(dim) <= k) out(dim) = ims(dim); else possible = k:-1:min (ims(dim) /10, k /2); [~, ind] = min (mod (-ims(dim), possible)); out(dim) = possible(ind); endif endfor if (nargout <= 1) varargout{1} = out; else varargout = mat2cell (out', ones (1, numel (out))); endif endfunction %!demo %! siz = bestblk ([200; 10], 50); %! disp (siz) %!error bestblk ("string") %!error bestblk ([100 200], "string") %!error <2 elements> bestblk ([100], 5) %!assert (bestblk ([ 10 12], 2), [ 2 2]); %!assert (bestblk ([ 10 12], 3), [ 2 3]); %!assert (bestblk ([300 100], 150), [150 100]); %!assert (bestblk ([256 128], 17), [ 16 16]); ## make sure we really pick the highest one %!assert (bestblk ([ 17 17], 3), [ 3 3]); ## Test default %!assert (bestblk ([230 470]), bestblk ([230 470], 100)) ## Test N-dimensional %!assert (bestblk ([10 12 10], 3), [2 3 2]); %!assert (bestblk ([ 9 12 9], 3), [3 3 3]); %!assert (bestblk ([10 12 10 11], 5), [5 4 5 4]); image-2.4.1/inst/PaxHeaders.6632/impixel.m0000644000000000000000000000013212561122761015062 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/impixel.m0000644000175000017500000001501012561122761017702 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} impixel () ## @deftypefnx {Function File} {} impixel (@var{img}, @var{x}, @var{y}) ## @deftypefnx {Function File} {} impixel (@var{ind}, @var{map}, @var{x}, @var{y}) ## @deftypefnx {Function File} {} impixel (@var{xdata}, @var{ydata}, @var{img}, @var{x}, @var{y}) ## @deftypefnx {Function File} {} impixel (@var{xdata}, @var{ydata}, @var{ind}, @var{map}, @var{x}, @var{y}) ## @deftypefnx {Function File} {[@var{x}, @var{y}, @var{p}] =} impixel (@dots{}) ## Get pixel values. ## ## For any image @var{img}, or indexed image @var{ind} with colormap @var{map}, ## returns the pixel values at the image coordinates @var{x} and @var{y}. ## ## The 2 element vectors @var{xdata} and @var{ydata} can be used to set an ## alternative coordinate system. ## ## If more than one output argument is requested, also returns the @var{x} and ## @var{y} coordinates for the image. ## ## @itemize @bullet ## @item ## The pixel values are always returned in RGB style triples, even when ## @var{img} is a grayscale image. ## ## @item ## The value for pixel coordinates outside the image limits is NaN. ## ## @item ## Because a floating-point is required to represent a NaN, the pixel ## values will be of class double if input is double, and single otherwise. ## @end itemize ## ## @end deftypefn function varargout = impixel (varargin) if (nargin > 6) print_usage (); ## interactive usage elseif (nargin <= 2) ## FIXME not yet implemented print_usage (); if (nargin == 0) ## If using the current image, it is possible that xData and yData ## were changed? We will confirm later is they were tampered with. xData = get (gcf (), "xData"); yData = get (gcf (), "yData"); else ## with given image, otherwise we will use current image [img, map, is_indexed] = get_image (varargin{:}); endif ## If only 2 output arguments are requested in interactive mode, then ## only the coordinates are required, no need to do anything else. if (nargout <= 2) varargout(1:2) = {x y}; return endif ## non-interactive usage else x = varargin{end-1}; y = varargin{end}; if (! isnumeric (x) || ! isreal (x) || ! isnumeric (y) || ! isreal (y)) error ("impixel: X and Y must be real numbers"); endif x = x(:); y = y(:); if (nargin >= 5) [img, map, is_indexed] = get_image (varargin{3:end-2}); xData = varargin{1}; yData = varargin{2}; if (! isnumeric (xData) || ! isnumeric (yData)) ## For Matlab compatibility we do not check if there's ## only 2 elements, or if they are real numbers error ("impixel: XDATA and YDATA must be numeric"); endif else [img, map, is_indexed] = get_image (varargin{1:end-2}); xData = 1:columns (img); yData = 1:rows (img); endif endif ## We need to return NaN if the requested pixels are outside the image ## limits. interp2() will respect the input class, which means it will ## return a 0 instead of NaN if the image is an integer class. Because ## of that, we convert it to single. If the input image was double, then ## we let it be. if (isinteger (img)) img = single (img); if (is_indexed) ## There's an offset in indexed images depending on their class. An ## indexed image from integer class, matches the value 0 to row 1 of the ## colormap. An indexed image from a float class, matches value 1 to ## row 1. Since we are changing the class, we need to readjust it. img++; endif endif xx = linspace (min (xData), max (xData), columns (img)); yy = linspace (min (yData), max (yData), rows (img)); data = interp2 (xx, yy, img(:,:,1), x, y, "nearest"); if (ndims (img) == 3 && size (img, 3) == 3) ## We can't use interp3() because XI and YI will be used to select entire ## columns and vectors instead of matched coordinates for ch = 2:3 data(:,ch) = interp2 (xx, yy, img(:,:,ch), x, y, "nearest"); endfor endif if (is_indexed) bad = isnan (data); data(bad) = 1; data = map(data(:),:); data([bad bad bad]) = NA; elseif (isvector (data)) ## If we have a vector but the image was not indexed, it must have ## been a grayscale image. We need to repeat the values into a Nx3 ## matrix as if they were RGB values. data = [data(:) data(:) data(:)]; endif if (nargout > 1) varargout(1:3) = {x y data} else varargout(1) = {data}; endif endfunction function [img, map, is_indexed] = get_image (img, map = []) if (! isimage (img)) error ("impixel: invalid image"); endif is_indexed = false; if (nargin > 2) error ("impixel: too many input arguments"); elseif (nargin == 2) is_indexed = true; if (! iscolormap (map)) error ("impixel: invalid colormap"); elseif (! isind (img)) error ("impixel: invalid indexed image"); endif endif endfunction %!shared img2d, img3d %! img2d = uint8 (magic (10)); %! img3d(:,:,1) = img2d; %! img3d(:,:,2) = img2d + 1; %! img3d(:,:,3) = img2d + 2; %! img3d = uint8 (img3d); %! %!assert (impixel (img2d, 2, 2), single ([80 80 80])); %!assert (impixel (img2d, -2, 2), single ([NA NA NA])); %! %!assert (impixel (img2d, [1 10], [1 10]), single ([92 92 92; 59 59 59])); %!assert (impixel (img3d, [1 10], [1 10]), single ([92 93 94; 59 60 61])); %!assert (impixel (double (img2d), [1 10], [1 10]), [92 92 92; 59 59 59]); %! %!assert (impixel ([1 10], [1 10], img2d, [1 10], [1 10]), single ([92 92 92; 59 59 59])); %!assert (impixel ([3 12], [-4 12], img2d, [1 10], [1 10]), single ([NA NA NA; 44 44 44])); %!assert (impixel ([3 5], [-4 3], img2d, [1 10], [1 10]), single ([NA NA NA; NA NA NA])); %! %! ## the following returns double because it's an indexed image %!assert (impixel ([3 12], [-4 12], img2d, gray (100), [1 10], [1 10]), [NA NA NA; 4/9 4/9 4/9]); image-2.4.1/inst/PaxHeaders.6632/imperspectivewarp.m0000644000000000000000000000013212561122761017164 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imperspectivewarp.m0000644000175000017500000001272012561122761022011 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2006 Søren Hauberg ## ## 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 3 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{warped} = imperspectivewarp(@var{im}, @var{P}, @var{interp}, @var{bbox}, @var{extrapval}) ## @deftypefnx{Function File} [@var{warped}, @var{valid}] = imperspectivewarp(@dots{}) ## Applies the spatial perspective homogeneous transformation @var{P} to the image @var{im}. ## The transformation matrix @var{P} must be a 3x3 homogeneous matrix, or 2x2 or 2x3 ## affine transformation matrix. ## ## The optional argument @var{method} defines the interpolation method to be ## used. All methods supported by @code{interp2} can be used. By default, the ## @code{linear} method is used. ## ## For @sc{matlab} compatibility, the methods @code{bicubic} (same as ## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as ## @code{linear}) are also supported. ## ## By default the resulting image contains the entire warped image. In some situation ## you only parts of the warped image. The argument @var{bbox} controls this, and can ## be one of the following strings ## @table @code ## @item "loose" ## The entire warped result is returned. This is the default behavior. ## @item "crop" ## The central part of the image of the same size as the input image is returned. ## @item "same" ## The size and coordinate system, of the input image, are kept. ## @end table ## ## All values of the result that fall outside the original image will ## be set to @var{extrapval}. The default value of @var{extrapval} is 0. ## ## The optional output @var{valid} is a matrix of the same size as @var{warped} ## that contains the value 1 in pixels where @var{warped} contains an interpolated ## value, and 0 in pixels where @var{warped} contains an extrapolated value. ## @seealso{imremap, imrotate, imresize, imshear, interp2} ## @end deftypefn function [warped, valid] = imperspectivewarp(im, P, interp = "linear", bbox = "loose", extrapolation_value = 0) if (nargin < 2 || nargin > 5) print_usage (); elseif (! isimage (im)) error ("imperspectivewarp: IM must be a grayscale or RGB image.") elseif (! ischar (interp)) error ("imperspectivewarp: INTERP must be a string with interpolation method") elseif (! ischar (bbox) || ! any (strcmpi (bbox, {"loose", "crop", "same"}))) error ("imperspectivewarp: BBOX must be 'loose', 'crop' or 'same'"); elseif (! isscalar (extrapolation_value)) error ("imperspectivewarp: EXTRAPVAL must be a scalar"); endif interp = interp_method (interp); if (isnumeric (P) && ismatrix (P)) if (issquare(P) && rows(P) == 3) # 3x3 matrix if (P(3,3) != 0) P /= P(3,3); else error ("imperspectivewarp: P(3,3) must be non-zero"); endif elseif (rows(P) == 2 && (columns(P) == 2 || columns(P) == 3)) # 2x2 or 2x3 matrix P(3,3) = 1; else # unsupported matrix size error ("imperspectivewarp: transformation matrix must be 2x2, 2x3, or 3x3"); endif else error ("imperspectivewarp: transformation matrix not valid"); endif ## Do the transformation [y, x, tmp] = size(im); ## Transform corners corners = [1, 1, 1; 1, y, 1; x, 1, 1; x, y, 1]'; Tcorners = P*corners; Tx = Tcorners(1,:)./Tcorners(3,:); Ty = Tcorners(2,:)./Tcorners(3,:); ## Do cropping? x1 = round(min(Tx)); x2 = round(max(Tx)); y1 = round(min(Ty)); y2 = round(max(Ty)); # FIXME: This seems to work fine for rotations, but # somebody who knows computational geometry should # be able to come up with a better algorithm. if (strcmpi(bbox, "crop")) xl = x2 - x1 + 1; yl = y2 - y1 + 1; xd = (xl - x)/2; yd = (yl - y)/2; x1 += xd; x2 -= xd; y1 += yd; y2 -= yd; elseif (strcmpi(bbox, "same")) x1 = 1; x2 = x; y1 = 1; y2 = y; endif ## Transform coordinates [X, Y] = meshgrid(x1:x2, y1:y2); [sy, sx] = size(X); D = [X(:), Y(:), ones(sx*sy, 1)]'; PD = inv(P)*D; XI = PD(1,:)./PD(3,:); YI = PD(2,:)./PD(3,:); XI = reshape(XI, sy, sx); YI = reshape(YI, sy, sx); clear X Y D PD; [warped, valid] = imremap (im, XI, YI, interp, extrapolation_value); endfunction %!demo %! ## Generate a synthetic image and show it %! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1; %! I(20:30, 20:30) = !I(20:30, 20:30); %! I(70:80, 70:80) = !I(70:80, 70:80); %! figure(), imshow(I); %! ## Resize the image to the double size and show it %! P = diag([1, 1, 0.5]); %! warped = imperspectivewarp(I, P); %! figure(), imshow(warped); %!demo %! ## Generate a synthetic image and show it %! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1; %! I(20:30, 20:30) = !I(20:30, 20:30); %! I(70:80, 70:80) = !I(70:80, 70:80); %! figure(), imshow(I); %! ## Rotate the image around (0, 0) by -0.4 radians and show it %! R = [cos(-0.4) sin(-0.4); -sin(-0.4) cos(-0.4)]; %! warped = imperspectivewarp(I, R, :, :, 0); %! figure(), imshow(warped); image-2.4.1/inst/PaxHeaders.6632/makelut.m0000644000000000000000000000013212561122761015055 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/makelut.m0000644000175000017500000000525612561122761017710 0ustar00carandraugcarandraug00000000000000## 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 3 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{lut} =} makelut (@var{fun}, @var{n}) ## @deftypefnx {Function File} {@var{lut} =} makelut (@var{fun}, @var{n}, @var{P1}, @var{P2}, @dots{}) ## Create a lookup table which can be used by applylut. ## ## lut = makelut(fun,n) returns a vector which can be used by applylut ## as a lookup table. ## ## @var{fun} can be a function object as created by inline, or simply a ## string which contains the name of a function. @var{fun} should accept a ## @var{n}-by-@var{n} matrix whose elements are binary (0 or 1) and ## returns an scalar (actually anything suitable to be included in a ## vector). ## ## makelut calls @var{fun} with all possible matrices and builds a ## vector with its result, suitable to be used by applylut. The length ## of this vector is 2^(@var{n}^2), so 16 for 2-by-2 and 512 for 3-by-3. ## ## makelut also passes parameters @var{P1}, @var{P2}, .... to @var{fun}. ## ## @seealso{applylut} ## @end deftypefn function lut = makelut (fun, n, varargin) if (nargin < 2) print_usage; elseif (n < 2) error ("makelut: n should be a natural number >= 2"); endif nq=n^2; c=2^nq; lut=zeros(c,1); w=reshape(2.^[nq-1:-1:0],n,n); for i=0:c-1 idx=bitand(w,i)>0; lut(i+1)= feval(fun, idx, varargin{:}); endfor endfunction %!demo %! makelut(inline('sum(x(:))>=3','x'), 2) %! % Returns '1' if one or more values %! % in the input matrix are 1 %!assert(prod(makelut(inline('sum(x(:))==2','x'),2)==makelut(inline('sum(x(:))==a*b*c*d','x','a','b','c','d'),2,2/(3*4*5),3,4,5))); # test multiple params %!assert(prod(makelut(inline('x(1,1)==1','x'),2)==[zeros(2^3,1);ones(2^3,1)])==1); # test 2-by-2 %!assert(prod(makelut(inline('x(1,1)==1','x'),3)==[zeros(2^8,1);ones(2^8,1)])==1); # test 3-by-3 %!assert(prod(makelut(inline('x(1,1)==1','x'),4)==[zeros(2^15,1);ones(2^15,1)])==1); # test 4-by-4 %!assert(prod(makelut(inline('x(2,1)==1','x'),3)==[zeros(2^7,1);ones(2^7,1);zeros(2^7,1);ones(2^7,1)])==1); # another test for 3-by-3 image-2.4.1/inst/PaxHeaders.6632/private0000644000000000000000000000013212561122761014632 xustar0030 mtime=1438950897.774252238 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/inst/private/0000755000175000017500000000000012561122761017532 5ustar00carandraugcarandraug00000000000000image-2.4.1/inst/private/PaxHeaders.6632/interp_method.m0000644000000000000000000000013212561122761017726 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/interp_method.m0000644000175000017500000000254712561122761022561 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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 . ## This private function is to be common to all functions that have an option ## for the interpolation method to use. For matlab compatibility, bicubic and ## bilinear are accepted which are the same as cubic and linear. This does not ## actually check if the method is valid, we leave that to interp2. The reason ## is that if interp2 implements a new method, all this functions will ## automatically work with it. function method = interp_method (method) method = tolower (method); switch method case "bicubic", method = "cubic"; case "bilinear", method = "linear"; case "triangle", method = "linear"; # interpolation kernel endswitch endfunction image-2.4.1/inst/private/PaxHeaders.6632/is_double_image.m0000644000000000000000000000013212561122761020174 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/is_double_image.m0000644000175000017500000000166112561122761023023 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## ## 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 3 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 . ## simple check used by some functions. Images of the double class must have ## all their values between 0 and 1 or be NaN function bool = is_double_image (img) bool = all ((img(:) >= 0 & img(:) <= 1) | isnan (img(:))); endfunction image-2.4.1/inst/private/PaxHeaders.6632/prepare_strel.m0000644000000000000000000000013212561122761017734 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/prepare_strel.m0000644000175000017500000000272312561122761022563 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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 . ## This function will be common to imopen, imclose, imbothat, imtophat, ## and any other function that can take a strel object or a matrix of 0 ## and 1. It checks the input and gets a strel object in the later case. function se = prepare_strel (func, se) ## We could do a lot more of input checking but it'd be repeated again ## in imerode and imdilate. We just do the minimum for strel as well. ## Since imerode and imdilate will create a strel object out of the SE ## we pass them, we can create it now ourselves. if (! strcmpi (class (se), "strel")) if (! islogical (se) && (isnumeric (se) && any (se(:) != 1 & se(:) != 0))) error ("%s: SE must be a strel object or matrix of 0 and 1", func); endif se = strel ("arbitrary", se); endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/handle_colorspec.m0000644000000000000000000000013212561122761020371 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/handle_colorspec.m0000644000175000017500000000274412561122761023223 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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 . ## There's 3 ways to specify colors: ## RGB triplet values ## short names ## long names ## ## And probably more undocumented ways to do it. function rgb = handle_colorspec (func, spec) if (iscolormap (spec)) rgb = spec; elseif (ischar (spec)) switch (tolower (spec)) case {"b", "blue" }, rgb = [0 0 1]; case {"c", "cyan" }, rgb = [0 1 1]; case {"g", "green" }, rgb = [0 1 0]; case {"k", "black" }, rgb = [0 0 0]; case {"m", "magenta"}, rgb = [1 0 1]; case {"r", "red" }, rgb = [1 0 0]; case {"w", "white" }, rgb = [1 1 1]; case {"y", "yellow" }, rgb = [1 1 0]; otherwise error("%s: unknown color '%s'", func, spec); endswitch else error ("%s: invalid color specification"); endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/ispart.m0000644000000000000000000000013212561122761016367 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/ispart.m0000644000175000017500000000211612561122761021212 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## ## 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 3 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 . ## This a private function for the is... type of functions for the image package ## Rather than checking the whol image, there can be a speed up by checking only ## a corner of the image first and then the rest if that part is true. function bool = ispart (foo, in) bool = foo (in(1:ceil (rows (in) /100), 1:ceil (columns (in) /100))); if (bool) bool = foo (in); endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/imarithmetics.m0000644000000000000000000000013212561122761017727 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/imarithmetics.m0000644000175000017500000000716712561122761022565 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} imarithmetics () ## This is a private function common to the likes of imadd, imsubtract, etc. ## ## First argument is the function name for the error message, while the others are ## the same order as the original function. It returns the two first input of the ## original function ## @end deftypefn function [img, val] = imarithmetics (func, img, val, out_class, in_args) is_valid = @(x) ((!isnumeric (x) && !islogical (x)) || isempty (x) || issparse (x) || !isreal (x)); if (is_valid (img) || is_valid (val)) error ("%s: input must be a numeric or logical, non-empty, non-sparse real matrix", func) elseif (!ischar (out_class)) error ("%s: third argument must be a string that specifies the output class", func) endif same_size = all (size (img) == size (val)); if (same_size && strcmpi (class (img), class (val))) [img, val] = convert (out_class, img, val); ## multiplication doesn't require same input class and output class defaults to ## whatever input class is not logical (first img, then val) elseif (strcmp (func, "immultiply") && same_size) if (in_args > 2) ## user defined, do nothing elseif (islogical (img) && !islogical (val)) out_class = class (val); endif [img, val] = convert (out_class, img, val); elseif (isscalar (val) && isfloat (val) && !strcmp (func, "imabsdiff")) ## according to matlab's documentation, if val is not an image of same size ## and class as img, then it must be a double scalar. But why not also support ## a single scalar and use isfloat? img = convert (out_class, img); else error ("%s: second argument must either be of same class and size of the first or a floating point scalar", func) end endfunction function [a, b] = convert (out_class, a, b = 0) ## in the case that we only want to convert one matrix, this subfunction is called ## with 2 arguments only. Then, b takes the value of zero so that the call to the ## functions that change the class is insignificant if ((nargin == 3 && any (!strcmpi ({class(a), class(b)}, out_class))) || (nargin == 2 && !strcmpi (class (a), out_class))) switch tolower (out_class) case {"logical"} a = logical (a); b = logical (b); case {"uint8"} a = uint8 (a); b = uint8 (b); case {"uint16"} a = uint16 (a); b = uint16 (b); case {"uint32"} a = uint32 (a); b = uint32 (b); case {"uint64"} a = uint64 (a); b = uint64 (b); case {"int8"} a = int8 (a); b = int8 (b); case {"int16"} a = int16 (a); b = int16 (b); case {"int32"} a = int32 (a); b = int32 (b); case {"int64"} a = int64 (a); b = int64 (b); case {"double"} a = double (a); b = double (b); case {"single"} a = single (a); b = single (b); otherwise error ("%s: requested class '%s' for output is not supported", func, out_class) endswitch endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/isimage.m0000644000000000000000000000013212561122761016503 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/isimage.m0000644000175000017500000000175712561122761021340 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Carnë Draug ## ## 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 3 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 . ## This a private function for the is... type of functions for the image package ## It simply checks if the input really is an image. function retval = isimage (img) retval = ((isnumeric (img) || islogical (img)) && ! issparse (img) && ! isempty (img) && isreal (img)); endfunction image-2.4.1/inst/private/PaxHeaders.6632/analyze75filename.m0000644000000000000000000000013212561122761020405 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/analyze75filename.m0000644000175000017500000000325012561122761023230 0ustar00carandraugcarandraug00000000000000%% Copyright (C) 2012 Adam H Aitkenhead %% Copyright (C) 2012 Carnë Draug %% %% 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 3 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 . %% private function with common code for the analyze75info and read functions function filename = analyze75filename (filename) %% Check filename if (exist (filename, 'dir')) filelist = dir ([filename, filesep, '*.hdr']); if (numel (filelist) == 1) filename = [filename, filesep, filelist.name]; elseif (numel (filelist) > 1) error ('analyze75: `filename'' is a directory with multiple hdr files.') else error ('analyze75: `filename'' is a directory with no hdr files.') end elseif (~exist (filename, 'file')) error ('analyze75: no file `%s''', filename) end %% Strip the filename of the extension fileextH = strfind (filename, '.hdr'); fileextI = strfind (filename, '.img'); if (~isempty (fileextH)) filename = filename(1:fileextH(end)-1); elseif (~isempty (fileextI)) filename = filename(1:fileextI(end)-1); else filename = filename; end end image-2.4.1/inst/private/PaxHeaders.6632/im2col_check.m0000644000000000000000000000013212561122761017407 xustar0030 mtime=1438950897.770252238 30 atime=1438950897.770252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/im2col_check.m0000644000175000017500000000373112561122761022236 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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 . ## A private function originally written for im2col but that can also ## be used by colfilt and nlfilt, since the syntax is very similar. function [p, block_size, padval] = im2col_check (func, nargin, A, varargin) if (nargin < 2) print_usage (func); elseif (! isnumeric (A) && ! islogical (A)) error ("%s: A must be a numeric of logical matrix", func); endif p = 1; # varargin param being processsed padval = 0; ## Check for 'indexed' presence if (ischar (varargin{p}) && strcmpi (varargin{p}, "indexed")) if (nargin < 3) print_usage (func); endif ## We pad with value of 0 for indexed images of uint8 or uint16 class. ## Indexed images of signed integer, or above uint16, are treated the ## same as floating point (a value of 1 is index 1 on the colormap) if (any (isa (A, {"uint8", "uint16"}))) padval = 0; else padval = 1; endif p++; endif ## check [m,n] block_size = varargin{p++}; if (! isnumeric (block_size) || ! isvector (block_size) || any (block_size(:) < 1)) error ("%s: BLOCK_SIZE must be a vector of positive elements.", func); endif block_size(end+1:ndims(A)) = 1; # expand singleton dimensions if required block_size = block_size(:).'; # make sure it's a row vector endfunction image-2.4.1/inst/private/PaxHeaders.6632/pad_for_sliding_filter.m0000644000000000000000000000013212561122761021555 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/pad_for_sliding_filter.m0000644000175000017500000000316312561122761024403 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2008 Søren Hauberg ## Copyright (C) 2012 Carnë Draug ## ## 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 3 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 . ## This private function is to be common to all functions that call ## __spatial_filtering__. It may be better to have __spatial_filtering__ do this ## part as well then function im = pad_for_sliding_filter (im, window_size, padval) if (ndims (im) != numel (window_size)) error ("image and domain must have the same number of dimensions") endif pad = floor (window_size / 2); im = padarray (im, pad, padval); even = ! mod (window_size, 2); ## if one of the domain dimensions is even, its origin is must be ## floor ([size(domain)/2] + 1) ## so after padarray, we need to remove the 1st element (1st row or column for ## dimension 1 and 2) from the dimensions where the domain is even if (any (even)) idx = cell (1, ndims (im)); for k = 1:ndims(im) idx{k} = (even(k)+1):size(im, k); endfor im = im(idx{:}); endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/ycbcrfunc.m0000644000000000000000000000013212561122761017043 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/ycbcrfunc.m0000644000175000017500000000746512561122761021702 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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 . ## Private function for ycbcr2rgb and rgb2ycbcr functions which are ## very similar function out = ycbcrfunc (func, in, standard) img = false; # was input an image? if (iscolormap (in)) ## do nothing, it's a colormap elseif (isrgb (in)) img = true; ## we shape it as a colormap (2D matrix) so we can use matrix multiplcation nRows = rows (in); nCols = columns (in); in = reshape (in, [nRows*nCols 3]); else error ("%s: input must be a colormap (Nx3) or RGB image (NxMx3)", func); endif if (ischar (standard)) if (strcmpi (standard, "601")) # for ITU-R BT.601 Kb = 0.114; Kr = 0.299; elseif (strcmpi (standard, "709")) # for ITU-R BT.709 Kb = 0.0722; Kr = 0.2126; else error ("%s: unknown standard `%s'", func, standard); endif elseif (isnumeric (standard) && numel (standard) == 2) Kb = standard(1); Kr = standard(2); else error ("%s: must specify a standard (string), or Kb and Kr values", func); endif ## the color matrix for the conversion. Derived from: ## Y = Kr*R + (1-Kr-Kb)*G + kb*B ## Cb = (1/2) * ((B-Y)/(1-Kb)) ## Cr = (1/2) * ((R-Y)/(1-Kr)) ## It expects RGB values in the range [0 1], and returns Y in the ## range [0 1], and Cb and Cr in the range [-0.5 0.5] cmat = [ Kr (1-Kr-Kb) Kb -(Kr/(2-2*Kb)) -(1-Kr-Kb)/(2-2*Kb) 0.5 0.5 -(1-Kr-Kb)/(2-2*Kr) -(Kb/(2-2*Kr)) ]; cls = class (in); in = im2double (in); ## note that these blocks are the inverse of one another. Changes ## in one will most likely require a change on the other if (strcmp (func, "rgb2ycbcr")) ## convert to YCbCr colorspace out = in * cmat'; ## rescale Cb and Cr to range [0 1] out(:, [2 3]) += 0.5; ## the actual range of Cb, Cr and Y will be smaller. The values at the ## extremes are named footroom and headroom. Cb, Cr, and Y have different ## ranges for footroom and headroom ## ## Cb and Cr: footroom -> [0 16/255[ ## Y : footroom -> [0 16/255[ ## Cb and Cr: headroom -> ]240/255 1 ] ## Y : headroom -> ]235/255 1 ] ## ## So we first compress the values to the actual available range (the whole ## [0 1] interval minus headroom and footroom), and then shift forward out(:,1) = (out(:,1) * 219/255) + 16/255; out(:,[2 3]) = (out(:,[2 3]) * 224/255) + 16/255; elseif (strcmp (func, "ycbcr2rgb")) ## just the inverse of the rgb2ycbcr conversion in(:,[2 3]) = (in(:,[2 3]) - 16/255) / (224/255); in(:,1) = (in(:,1) - 16/255) / (219/255); in(:,[2 3]) -= 0.5; out = in * inv (cmat'); else error ("internal error for YCbCr conversion. Unknown function %s", func); endif switch (cls) case {"single", "double"} ## do nothing. All is good case "uint8" out = im2uint8 (out); case "uint16" out = im2uint16 (out); otherwise error ("%s: unsupported image class %s", func, cls); endswitch if (img) ## put the image back together out = reshape (out, [nRows nCols 3]); endif endfunction image-2.4.1/inst/private/PaxHeaders.6632/istform.m0000644000000000000000000000013212561122761016550 xustar0030 mtime=1438950897.774252238 30 atime=1438950897.774252238 30 ctime=1438950899.342252237 image-2.4.1/inst/private/istform.m0000644000175000017500000000241212561122761021372 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## Private internal function to check if a argument is a transformation ## structure (as created by maketform and to be use by findbounds, ## imtransform, and the like) ## Author: Pantxo Diribarne function out = istform (T) out = true; if (!isstruct (T)) out = false; else required = {"ndims_in";"ndims_out"; ... "forward_fcn"; "inverse_fcn"; ... "tdata"}; fields = fieldnames (T); tst = cellfun (@(x) any (strcmp (fields, x)), required); if (! all (tst)) out = false endif endif endfunction image-2.4.1/inst/PaxHeaders.6632/imlincomb.m0000644000000000000000000000013212561122761015364 xustar0030 mtime=1438950897.750252238 30 atime=1438950897.750252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imlincomb.m0000644000175000017500000000747712561122761020226 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} imlincomb (@var{fac}, @var{img}) ## @deftypefnx {Function File} {@var{out} =} imlincomb (@var{fac1}, @var{img1}, @var{fac2}, @var{img2}, @dots{}) ## @deftypefnx {Function File} {@var{out} =} imlincomb (@dots{}, @var{class}) ## Combine images linearly. ## ## Returns the computed image as per: ## ## @var{out} = @var{fac}1*@var{img}1 + @var{fac}2*@var{img}2 + @dots{} + @var{fac}n*@var{img}n ## ## The images @var{img}1..n must all be of same size and class. The factors @var{fac}1..n ## must all be floating-point scalars. ## ## The class of @var{out} will be the same as @var{img}s unless @var{img}s are logical ## in which case @var{out} will be double. Alternatively, it can be specified ## with @var{class}. ## ## If applying several arithmetic operations on images, @code{imlincomb} is more ## precise since calculations are performed at double precision. ## ## @emph{Note 1}: you can force output class to be logical by specifying ## @var{class} though it possibly doesn't make a lot of sense. ## ## @seealso{imadd, imcomplement, imdivide, immultiply, imsubtract} ## @end deftypefn function out = imlincomb (varargin) if (nargin < 2) print_usage; else if (rem (nargin, 2) == 0) ## use default for output class; the class of first image (second argument) out_class = class (varargin{2}); def_class = true; else ## last argument is requested output class out_class = varargin{end}; def_class = false; endif endif facI = 1:2:nargin-1; # index for factors imgI = 2:2:nargin; # index for images imgC = class (varargin{2}); # class of the first image out = zeros (size (varargin{2})); for i = 1:numel (imgI) ## we keep index the images from varargin rather than copying to new variable to ## avoid taking up a lot of memory if (!isreal (varargin{facI(i)}) || !isscalar (varargin{facI(i)}) || !isfloat (varargin{facI(i)})) error ("factor to multiply each image must be a real, floating-point, scalar."); elseif ((!isnumeric (varargin{imgI(i)}) && !islogical (varargin{imgI(i)})) ... || isempty (varargin{imgI(i)}) || issparse (varargin{imgI(i)}) ... || !isreal (varargin{imgI(i)}) || !isa (varargin{imgI(i)}, imgC)) error ("images must be a numeric or logical, non-empty, non-sparse real matrix of the same class."); endif img = double(varargin{imgI(i)}) .* double(varargin{facI(i)}); out += img; endfor ## this is probably matlab imcompatible since by their documentation, they don't even ## support logical matrix. If specified by user, respect and return a logical ## matrix. Otherwise, return a double, even if images were all logical if (strcmpi (out_class, "logical") && def_class) cnv = @double; else cnv = str2func (tolower (out_class)); endif out = cnv (out); endfunction %!assert (imlincomb (0.5, uint8 ([255 10]), 0.5, uint8 ([50 20])), uint8 ([153 15])); # default to first class and truncate %!assert (imlincomb (0.5, uint8 ([255 10]), 0.5, uint8 ([50 20]), "uint16"), uint16 ([153 15])); # defining output class works image-2.4.1/inst/PaxHeaders.6632/imtophat.m0000644000000000000000000000013212561122761015240 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imtophat.m0000644000175000017500000001530712561122761020071 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2005 Carvalho-Mariel ## Copyright (C) 2010-2013 Carnë Draug ## ## 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 3 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} {} imtophat (@var{img}, @var{SE}) ## Perform morphological top hat filtering. ## ## The matrix @var{img} must be numeric while @var{SE} can be a: ## @itemize @bullet ## @item ## strel object; ## @item ## array of strel objects as returned by `@@strel/getsequence'; ## @item ## matrix of 0's and 1's. ## @end itemize ## ## A top hat transform corresponds to the difference between @var{img}, ## and the opening of @var{img}, i.e., it is equivalent to: ## @example ## img - imopen (img, se); ## @end example ## ## Use @code{imbothat} to perform a 'black' or 'closing', top-hat transform ## (is is also known as bottom-hat transform). ## ## @seealso{imerode, imdilate, imopen, imclose, imbothat, mmgradm} ## @end deftypefn function white = imtophat (img, se) if (nargin != 2) print_usage (); elseif (! isimage (img)) error("imtophat: IMG must be a numeric matrix"); endif se = prepare_strel ("imtophat", se); ## Perform filtering ## Note that in case that the transform is to applied to a logical image, ## subtraction must be handled in a different way (x & !y) instead of (x - y) ## or it will return a double precision matrix if (islogical (img)) white = img & ! imopen (img, se); else white = img - imopen (img, se); endif endfunction %!assert (imtophat (ones (3), [1 1; 0 1]), zeros (3)); %!assert (imtophat (true (3), [1 1; 0 1]), false (3)); %!shared in, out, se %! in = [ 0 0 0 1 1 1 0 0 1 1 %! 0 1 0 1 1 1 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 0 %! 0 1 1 1 1 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 1 1 1 %! 0 0 0 0 1 0 1 0 1 0 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 0 1 1 1 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! %! out = [ 0 0 0 0 0 0 0 0 1 1 %! 0 1 0 0 0 0 0 0 0 1 %! 1 1 1 1 1 0 0 0 0 0 %! 0 1 1 1 1 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 1 0 %! 0 0 0 0 0 0 0 1 1 1 %! 0 0 0 0 1 0 1 0 1 0 %! 0 0 0 1 1 1 1 1 0 0 %! 0 0 0 0 1 1 1 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %!assert (imtophat (logical (in), ones (3)), logical (out)); %! %! out = [12 19 0 0 0 16 23 0 7 0 %! 18 0 0 6 1 19 0 2 9 1 %! 0 74 81 12 7 0 1 8 15 7 %! 68 70 2 14 0 6 7 14 16 0 %! 69 76 8 0 0 7 14 21 0 1 %! 0 7 59 54 61 13 20 0 0 32 %! 18 0 69 60 62 19 0 0 0 27 %! 73 0 0 66 68 0 1 6 6 33 %! 0 0 17 19 1 0 2 9 7 14 %! 1 6 23 0 7 1 8 15 0 32]; %!assert (imtophat (magic (10), ones (3)), out); %!assert (imtophat (uint8 (magic (10)), strel ("square", 3)), uint8 (out)); %! %! ## using a se that will be decomposed in 2 pieces %! out =[91 98 0 0 0 27 34 11 18 0 %! 94 76 3 6 1 33 15 17 24 1 %! 0 77 84 12 7 14 16 23 30 7 %! 80 82 14 18 0 32 34 41 43 0 %! 81 88 20 0 0 33 40 47 24 6 %! 12 19 63 57 64 16 23 0 7 39 %! 18 0 69 60 62 19 1 3 12 39 %! 73 0 0 66 68 0 2 9 18 45 %! 4 6 81 67 49 6 8 15 19 26 %! 5 12 87 48 55 7 14 21 0 32]; %!assert (imtophat (magic (10), ones(5)), out); %! %! ## using a weird non-symmetric and even-size se %! out =[85 92 0 0 0 12 23 0 17 0 %! 91 73 0 6 0 18 0 2 13 0 %! 0 72 81 13 6 0 1 9 15 0 %! 60 62 10 12 0 8 8 17 17 0 %! 61 69 0 0 0 28 16 41 0 0 %! 0 0 47 52 61 12 16 0 0 31 %! 6 0 53 58 60 17 0 0 0 33 %! 69 0 0 60 62 0 0 6 0 33 %! 0 0 17 60 42 0 2 13 1 8 %! 0 6 23 0 7 0 7 15 0 14]; %!assert (imtophat (magic (10), [1 0 0 0; 1 1 1 0; 0 1 0 1]), out); %! %! ## N dimensional and weird se %! in = reshape (magic(16), [4 8 4 2]); %! se = ones (3, 3, 3); %! se(:,:,1) = [1 0 1; 0 1 1; 0 0 0]; %! se(:,:,3) = [1 0 1; 0 1 1; 0 0 1]; %! out = zeros (size (in)); %! out(:,:,1,1) = [ %! 239 146 82 18 0 19 83 133 %! 0 35 99 163 219 128 64 0 %! 0 46 128 195 187 123 59 0 %! 157 93 47 0 14 78 142 211]; %! out(:,:,2,1) = [ %! 0 21 85 149 233 146 64 0 %! 205 128 64 0 0 41 87 151 %! 171 107 57 0 0 64 121 185 %! 0 64 142 213 169 105 41 0]; %! out(:,:,3,1) = [ %! 231 146 78 14 0 27 77 137 %! 0 43 107 167 211 128 64 0 %! 0 46 128 199 179 119 51 0 %! 149 85 39 0 18 78 142 219]; %! out(:,:,4,1) = [ %! 0 29 93 157 225 128 64 0 %! 197 128 64 0 0 31 95 159 %! 163 99 53 0 0 61 125 189 %! 0 64 146 221 161 97 33 0]; %! out(:,:,1,2) = [ %! 223 146 82 18 0 35 99 149 %! 0 48 115 179 203 128 64 0 %! 0 46 128 211 171 107 43 0 %! 141 77 31 0 14 78 142 227]; %! out(:,:,2,2) = [ %! 0 37 101 165 217 146 64 0 %! 189 125 64 0 0 57 103 167 %! 155 91 41 0 0 64 128 201 %! 0 64 142 229 153 89 25 0]; %! out(:,:,3,2) = [ %! 215 146 78 14 0 43 93 153 %! 0 48 123 183 195 128 64 0 %! 0 46 128 215 163 103 35 0 %! 133 69 23 0 18 78 142 235]; %! out(:,:,4,2) = [ %! 0 45 109 173 209 128 64 0 %! 181 117 64 0 0 47 111 175 %! 147 83 37 0 0 64 128 205 %! 0 64 146 237 145 81 17 0]; %!assert (imtophat (in, se), out); image-2.4.1/inst/PaxHeaders.6632/analyze75info.m0000644000000000000000000000013212561122761016106 xustar0030 mtime=1438950897.714252238 30 atime=1438950897.714252238 30 ctime=1438950899.342252237 image-2.4.1/inst/analyze75info.m0000644000175000017500000001441512561122761020736 0ustar00carandraugcarandraug00000000000000%% Copyright (C) 2012 Adam H Aitkenhead %% Copyright (C) 2012 Carnë Draug %% %% 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 3 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{header} =} analyze75info (@var{filename}) %% @deftypefnx {Function File} {@var{header} =} analyze75info (@var{filename}, "ByteOrder", @var{arch}) %% Read header of an Analyze 7.5 file. %% %% @var{filename} must be the path for an Analyze 7.5 file or the path for a %% directory with a single .hdr file can be specified. %% %% The optional argument @code{"ByteOrder"} reads the file with the specified %% @var{arch} ("ieee-be" or "ieee-le" for IEEE big endian or IEEE %% little endian respectively). %% %% @var{header} is a structure with the file information. %% %% @seealso{analyze75read, analyze75write} %% @end deftypefn function header = analyze75info (filename, varargin) if (nargin ~= 1 && nargin ~= 3) print_usage; elseif (~ischar (filename)) error ('analyze75info: `filename'' must be a string'); elseif (nargin == 3) %% Check the byteorder if (strcmpi (varargin{1}, 'byteorder')) error ('analyze75info: second argument must be string `ByteOrder'''); elseif (!all (strcmpi (varargin{3}, {'ieee-le', 'l', 'ieee-be', 'b'}))) error ('analyze75info: valid options for `ByteOrder'' are `ieee-le'' or `ieee-be'''); elseif (any (strcmpi (varargin{3}, {'ieee-be', 'b'}))) warning ('analyze75info: no support for big-endian. Please consider submitting a patch. Attempting to read as little-endian'); end end fileprefix = analyze75filename (filename); %% finally start reading the actual file hdrdirdata = dir ([fileprefix, '.hdr']); imgdirdata = dir ([fileprefix, '.img']); header.ImgFileSize = imgdirdata.bytes; header.Filename = [fileprefix, '.hdr']; header.FileModDate = hdrdirdata.date; header.Format = 'Analyze'; header.FormatVersion = '7.5'; header.ColorType = 'grayscale'; header.ByteOrder = 'ieee-le'; fidH = fopen ([fileprefix, '.hdr']); header.HdrFileSize = fread (fidH, 1, 'int32'); header.HdrDataType = char (fread (fidH, 10, 'char'))'; header.DatabaseName = char (fread (fidH, 18, 'char'))'; header.Extents = fread (fidH, 1, 'int32'); header.SessionError = fread (fidH, 1, 'int16'); header.Regular = char (fread (fidH, 1, 'char')); unused = char (fread (fidH, 1, 'char')); unused = fread (fidH, 1, 'int16'); header.Dimensions = zeros (size (1, 4)); header.Dimensions(1) = fread (fidH, 1, 'int16'); header.Dimensions(2) = fread (fidH, 1, 'int16'); header.Dimensions(3) = fread (fidH, 1, 'int16'); header.Dimensions(4) = fread (fidH, 1, 'int16'); unused = fread (fidH, 3, 'int16'); header.VoxelUnits = char (fread (fidH, 4, 'char'))'; header.CalibrationUnits = char (fread (fidH, 8, 'char'))'; unused = fread (fidH, 1, 'int16'); datatype = fread (fidH, 1, 'int16'); switch datatype case 0, header.ImgDataType = 'DT_UNKNOWN'; case 1, header.ImgDataType = 'DT_BINARY'; case 2, header.ImgDataType = 'DT_UNSIGNED_CHAR'; case 4, header.ImgDataType = 'DT_SIGNED_SHORT'; case 8, header.ImgDataType = 'DT_SIGNED_INT'; case 16, header.ImgDataType = 'DT_FLOAT'; case 32, header.ImgDataType = 'DT_COMPLEX'; case 64, header.ImgDataType = 'DT_DOUBLE'; case 128, header.ImgDataType = 'DT_RGB'; case 255, header.ImgDataType = 'DT_ALL'; otherwise, warning ('analyze75: unable to detect ImgDataType'); end header.BitDepth = fread (fidH, 1, 'int16'); unused = fread (fidH, 1, 'int16'); unused = fread (fidH, 1, 'float'); header.PixelDimensions = zeros (1, 3); header.PixelDimensions(1) = fread (fidH, 1, 'float'); header.PixelDimensions(2) = fread (fidH, 1, 'float'); header.PixelDimensions(3) = fread (fidH, 1, 'float'); unused = fread (fidH, 4, 'float'); header.VoxelOffset = fread (fidH, 1, 'float'); unused = fread (fidH, 3, 'float'); header.CalibrationMax = fread (fidH, 1, 'float'); header.CalibrationMin = fread (fidH, 1, 'float'); header.Compressed = fread (fidH, 1, 'float'); header.Verified = fread (fidH, 1, 'float'); header.GlobalMax = fread (fidH, 1, 'int32'); header.GlobalMin = fread (fidH, 1, 'int32'); header.Descriptor = char (fread (fidH, 80, 'char'))'; header.AuxFile = char (fread (fidH, 24, 'char'))'; header.Orientation = char (fread (fidH, 1, 'char'))'; header.Originator = char (fread (fidH, 10, 'char'))'; header.Generated = char (fread (fidH, 10, 'char'))'; header.Scannumber = char (fread (fidH, 10, 'char'))'; header.PatientID = char (fread (fidH, 10, 'char'))'; header.ExposureDate = char (fread (fidH, 10, 'char'))'; header.ExposureTime = char (fread (fidH, 10, 'char'))'; unused = char (fread (fidH, 3, 'char'))'; header.Views = fread (fidH, 1, 'int32'); header.VolumesAdded = fread (fidH, 1, 'int32'); header.StartField = fread (fidH, 1, 'int32'); header.FieldSkip = fread (fidH, 1, 'int32'); header.OMax = fread (fidH, 1, 'int32'); header.OMin = fread (fidH, 1, 'int32'); header.SMax = fread (fidH, 1, 'int32'); header.SMin = fread (fidH, 1, 'int32'); header.Width = header.Dimensions(1); header.Height = header.Dimensions(2); fclose(fidH); end image-2.4.1/inst/PaxHeaders.6632/labelmatrix.m0000644000000000000000000000013212561122761015717 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/labelmatrix.m0000644000175000017500000000411512561122761020543 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} labelmatrix (@var{cc}) ## Create labelled matrix from bwconncomp structure. ## ## Uses the structure as returned by the @code{bwconncomp} function to create ## a label matrix, where each individual object is assigned a positive number. ## A value of zero corresponds to the background. ## ## The class of the output matrix is dependent on the number of objects, being ## uint, uint16, uint32, or double, whichever is enough. ## ## @seealso{bwconncomp, bwlabel, bwlabeln, label2rgb, rgb2label} ## @end deftypefn function labelled = labelmatrix (cc) if (nargin != 1) print_usage (); elseif (! isstruct (cc) && ! all (isfield (cc, {"Connectivity", "ImageSize", "NumObjects", "PixelIdxList"}))) error ("labelmatrix: CC must be a struct as returned by bwconncomp"); endif n_obj = cc.NumObjects; if (n_obj < 256), cl = "uint8"; elseif (n_obj < 65536), cl = "uint16"; elseif (n_obj < 4294967296), cl = "uint32"; else, cl = "double"; endif ## There's certainly a more efficient way to do this... n = 1; labels = cell2mat (cellfun (@(ind) repmat (n++, 1, numel(ind)), cc.PixelIdxList, "UniformOutput", false)); ind = cell2mat (cc.PixelIdxList'); labelled = zeros (cc.ImageSize, cl); labelled(ind) = labels; endfunction image-2.4.1/inst/PaxHeaders.6632/imclearborder.m0000644000000000000000000000013212561122761016225 xustar0030 mtime=1438950897.746252238 30 atime=1438950897.746252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imclearborder.m0000644000175000017500000001150712561122761021054 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} imclearborder (@var{im}) ## @deftypefnx {Function File} {} imclearborder (@var{im}, @var{conn}) ## Clear borders of objects or ligher structures. ## ## On the simplest case of binary images, this function removes objects ## that touch the image borders. In the case of grayscale images, lighter ## regions (higher intensity values) that touch the image border get removed. ## ## To be more exact, this is equivalent to use @code{imreconstruct} using ## the @var{im} borders as marker, and setting all unchanged elements to ## a background value. ## ## Element connectivity @var{conn}, to define the size of objects, can be ## specified with a numeric scalar (number of elements in the neighborhood): ## ## @table @samp ## @item 4 or 8 ## for 2 dimensional matrices; ## @item 6, 18 or 26 ## for 3 dimensional matrices; ## @end table ## ## or with a binary matrix representing a connectivity array. Defaults to ## @code{conndef (ndims (@var{bw}), "maximal")} which is equivalent to ## @var{conn} of 8 and 26 for 2 and 3 dimensional matrices respectively. ## ## @seealso{imreconstruct} ## @end deftypefn function im = imclearborder (im, conn) if (nargin < 1 || nargin > 2) print_usage (); elseif (! isimage (im)) error ("imclearborder: IM must be an image"); endif if (nargin < 2) conn = conndef (ndims (im), "maximal"); else conn = conndef (conn); endif bg_val = cast (getrangefromclass (im)(1), class (im)); marker = get_borders (im, conn, bg_val); border_elems = imreconstruct (marker, im, conn) == im; im(border_elems) = bg_val; endfunction function borders = get_borders (im, conn, val) im_size = size (im); borders = repmat (val, im_size); tmp_idx = repmat ({":"}, [1 ndims(im)]); tmp_conn_idx = repmat ({":"}, [1 ndims(conn)]); for dim = 1:min (ndims (im), ndims (conn)) conn_idx = tmp_conn_idx; conn_idx{dim} = [1 3]; if (im_size(dim) == 1 || ! any (conn(conn_idx{:})(:))) continue endif idx = tmp_idx; idx{dim} = [1 im_size(dim)]; borders(idx{:}) = im(idx{:}); endfor endfunction ## TODO check what exactly does Matlab do with in grayscale images, specially ## in the case of signed integers and floating point with negative values. ## We are different from the Matlab documentation suggests but that's ## because Matlab documentation sounds wrong to me. %!test %! a = logical ([ %! 0 1 0 0 1 0 0 0 0 1 %! 1 0 0 0 0 1 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 0 1 0 1 0 1 0 0 1 %! 0 0 0 0 0 0 0 1 1 0 %! 0 0 1 0 0 1 0 1 0 0 %! 0 1 0 1 0 1 1 0 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 1 0 1 1 0 0 0 %! 0 0 0 1 1 0 0 0 1 0]); %! %! a4 = logical ([ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 1 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 0 0 1 0 1 0 1 0 0 0 %! 0 0 0 0 0 0 0 1 1 0 %! 0 0 1 0 0 1 0 1 0 0 %! 0 1 0 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 0 0 0]); %! %! a8 = logical ([ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0]); %! %! assert (imclearborder (a, 4), a4) %! assert (imclearborder (a, [0 1 0; 1 1 1; 0 1 0]), a4) %! assert (imclearborder (a), a8) %! assert (imclearborder (a, 8), a8) %! assert (imclearborder (a, ones (3)), a8) %!test %! a = false (5, 5, 3); %! a(2:4,2:4,:) = true; %! assert (imclearborder (a, 4), a) %! %! a(1,2) = true; %! a4 = a; %! a4(:,:,1) = false; %! assert (imclearborder (a, 4), a4) image-2.4.1/inst/PaxHeaders.6632/maketform.m0000644000000000000000000000013212561122761015400 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/maketform.m0000644000175000017500000001501712561122761020227 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012 Pantxo Diribarne ## ## 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 3 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{T} =} maketform (@var{ttype}, @var{tmat}) ## @deftypefnx {Function File} {@var{T} =} maketform (@var{ttype}, @var{inc}, @var{outc}) ## @deftypefnx {Function File} {@var{T} =} maketform ("custom", @var{ndims_in}, @var{ndims_out}, @var{forward_fcn}, @var{inverse_fcn}, @var{tdata}) ## Create structure for spatial transformations. ## ## Returns a transform structure containing fields @var{ndims_in}, ## @var{ndims_out}, @var{forward_fcn}, @var{inverse_fcn} and @var{tdata}. The ## content of each field depends on the requested transform type @var{ttype}: ## ## @table @asis ## @item "projective" ## A ndims_in = N -> @var{ndims_out} = N projective transformation structure ## is returned. ## The second input argument @var{tmat} must be a (N+1)-by-(N+1) ## transformation matrix. The ## (N+1)th column must contain projection coefficients. As an example a two ## dimensional transform from [x y] coordinates to [u v] coordinates ## is represented by a transformation matrix defined so that: ## ## @example ## [xx yy zz] = [u v 1] * [a d g; ## b e h; ## c f i] ## [x y] = [xx./zz yy./zz]; ## @end example ## ## Alternatively the transform can be specified using the coordinates ## of a quadilateral (typically the 4 corners of the ## image) in the input space (@var{inc}, 4-by-ndims_in matrix) and in ## the output space (@var{outc}, 4-by-ndims_out matrix). This is ## equivalent to building the transform using ## @code{T = cp2tform (@var{inc}, @var{outc}, "projective")}. ## ## @item "affine" ## Affine is a subset of projective transform (see above). A ## @var{ndims_in} = N -> @var{ndims_out} = N affine transformation structure is ## returned. ## The second input argument @var{tmat} must be a (N+1)-by-(N+1) or ## (N+1)-by-(N) transformation matrix. If present, the (N+1)th column must ## contain [zeros(N,1); 1] so that projection is suppressed. ## ## Alternatively the transform can be specified using the coordinates ## of a triangle (typically the 3 corners of the ## image) in the input space (@var{inc}, 3-by-ndims_in matrix) and in ## the output space (@var{outc}, 3-by-ndims_out matrix). This is ## equivalent to building the transform using "T = cp2tform (@var{inc}, @var{outc}, ## 'affine')". ## ## @item "custom" ## For user defined transforms every field of the transform structure ## must be supplied. The prototype of the transform functions, ## @var{forward_fcn} and @var{inverse_fcn}, should be X' = ## transform_fcn (X, T). X and X' are respectively p-by-ndims_in and ## p-by-ndims_out arrays for forward_fcn and reversed for inverse_fcn. ## The argument T is the transformation structure which will contain ## the user supplied transformation matrix @var{tdata}. ## @end table ## ## @seealso{tformfwd, tforminv, cp2tform} ## @end deftypefn ## Author: Pantxo Diribarne function T = maketform (ttype, varargin) if (nargin < 2 || ! any (strcmpi (ttype, {"affine", "projective", "custom"}))) print_usage (); endif if (numel (varargin) == 1) tmat = varargin {1}; ndin = rows (tmat) - 1; ndout = columns (tmat) - 1; if (ndin < 2); error ("maketform: expect at least 3-by-2 transform matrix") elseif ((ndin-ndout) > 1 || (ndout > ndin)) print_usage (); endif switch (tolower (ttype)) case "affine" if ((ndin - ndout) == 1) tmat = [tmat [zeros(ndin, 1); 1]]; ndout += 1; elseif (!all (tmat(:,end) == [zeros(ndin, 1); 1])) error ("maketform: \"%s\" expect [zeros(N,1); 1] as (N+1)th column", ttype); endif forward_fcn = @fwd_affine; inverse_fcn = @inv_affine; case "projective" if ((ndin - ndout) == 1) print_usage (); endif forward_fcn = @fwd_projective; inverse_fcn = @inv_projective; endswitch T.ndims_in = ndin; T.ndims_out = ndout; T.forward_fcn = forward_fcn; T.inverse_fcn = inverse_fcn; T.tdata.T = tmat; T.tdata.Tinv = inv (tmat); elseif (numel (varargin) == 2) inc = varargin{1}; outc = varargin{2}; if (strcmp (ttype, "affine")) if (all (size (inc) == size (outc)) && all (size (inc) == [3 2])) T = cp2tform (inc, outc, ttype); else error ("maketform: expect INC and OUTC to be 3-by-2 vectors."); endif elseif (strcmp (ttype, "projective")) if (all (size (inc) == size (outc)) && all (size (inc) == [4 2])) T = cp2tform (inc, outc, ttype); else error ("maketform: expect INC and OUTC to be 4-by-2 vectors."); endif endif elseif (numel (varargin) == 5 && strcmpi (ttype, "custom")) if (isscalar (varargin{1}) && isscalar (varargin{2}) && varargin{1} > 0 && varargin{2} > 0) T.ndims_in = varargin{1}; T.ndims_out = varargin{2}; else error ("maketform: expect positive scalars as ndims.") endif if (is_function_handle (varargin{3}) || isempty (varargin{3})) T.forward_fcn = varargin{3}; else error ("maketform: expect function handle as forward_fcn.") endif if (is_function_handle (varargin{4}) || isempty (varargin{4})) T.inverse_fcn = varargin{4}; else error ("maketform: expect function handle as inverse_fcn.") endif T.tdata = varargin{5}; else print_usage (); endif endfunction function X = fwd_affine (U, T) U = [U, ones(rows(U), 1)]; X = U * T.tdata.T(:,1:end-1); endfunction function U = inv_affine (X, T) X = [X, ones(rows(X), 1)]; U = X * T.tdata.Tinv(:,1:end-1); endfunction function X = fwd_projective (U, T) U = [U, ones(rows(U), 1)]; XX = U * T.tdata.T; X = [XX(:,1)./XX(:,3) XX(:,2)./XX(:,3)]; endfunction function U = inv_projective (X, T) X = [X, ones(rows(X), 1)]; UU = X * T.tdata.Tinv; U = [UU(:,1)./UU(:,3) UU(:,2)./UU(:,3)]; endfunction image-2.4.1/inst/PaxHeaders.6632/mmgradm.m0000644000000000000000000000013212561122761015037 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/mmgradm.m0000644000175000017500000000532512561122761017667 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010, 2013 Carnë Draug ## ## 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 3 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} {} mmgradm (@var{img}) ## @deftypefnx {Function File} {} mmgradm (@var{img}, @var{se_dil}) ## @deftypefnx {Function File} {} mmgradm (@var{img}, @var{se_dil}, @var{se_ero}) ## Perform morphological gradient. ## ## The matrix @var{img} must be numeric whose gradients is calculated, while ## @var{se_dil} and @var{se_ero} are the structuring elements for the dilation ## and erosion respectively. They can be a: ## @itemize @bullet ## @item ## strel object; ## @item ## array of strel objects as returned by `@@strel/getsequence'; ## @item ## matrix of 0's and 1's. ## @end itemize ## ## The @var{se_dil} and @var{se_ero} default to the elementary cross, i.e.: ## @example ## [ 0 1 0 ## 1 1 1 ## 0 1 0]; ## @end example ## ## The basic morphological gradient corresponds to a matrix erosion ## subtracted to its dilation, which is equivalent to: ## @example ## imdilate (img, se_dil) - imerode (img, se_ero) ## @end example ## ## To perform the half-gradients by erosion or dilation, or the internal or ## external gradients, simply pass an empty matrix as structuring element: ## @example ## mmgradm (img, [], se_ero) # half-gradient by erosion or internal gradient ## mmgradm (img, se_dil, []) # half-gradient by dilation or external gradient ## @end example ## ## @seealso{imerode, imdilate, imopen, imclose, imtophat, imbothat} ## @end deftypefn function grad = mmgradm (img, se_dil = strel ("diamond", 1), se_ero = strel ("diamond", 1)) ## This function does not exist in Matlab. It is meant to be compatible ## with the mmgradm function from the SDC morphology toolbox if (nargin < 1 || nargin > 3) print_usage (); elseif (! isimage (img)) error("imtophat: IMG must be a numeric matrix"); endif se_dil = prepare_strel ("mmgradm", se_dil); se_ero = prepare_strel ("mmgradm", se_ero); dilated = imdilate (img, se_dil); eroded = imerode (img, se_ero); if (islogical (img)) grad = dilated & ! eroded; else grad = dilated - eroded; endif endfunction image-2.4.1/inst/PaxHeaders.6632/label2rgb.m0000644000000000000000000000013212561122761015247 xustar0030 mtime=1438950897.762252238 30 atime=1438950897.762252238 30 ctime=1438950899.342252237 image-2.4.1/inst/label2rgb.m0000644000175000017500000001430512561122761020075 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2006 Søren Hauberg ## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} label2rgb (@var{L}) ## @deftypefnx{Function File} {} label2rgb (@var{L}, @var{cmap}) ## @deftypefnx{Function File} {} label2rgb (@var{L}, @var{cmap}, @var{background}) ## @deftypefnx{Function File} {} label2rgb (@var{L}, @var{cmap}, @var{background}, @var{order}) ## Convert labeled image into RGB. ## ## The labeled image @var{L} is converted into an RGB image using the ## colormap @var{cmap}. The label number of each region is used to select ## the color from @var{cmap} which can be specified as: ## ## @itemize @bullet ## @item @var{N}-by-3 colormap matrix where N must be larger than or equal ## to the highest label number; ## @item name of a function that returns a colormap; ## @item handle for a function that returns a colormap (defaults to @code{jet}). ## @end itemize ## ## In a labeled image, zero valued pixels are considered background and ## are colored according to the color @var{background}. It can be specified ## as an RGB triplet values (3 element vector of values between 0 and 1), or ## by name: ## ## @itemize @bullet ## @item @qcode{"w"} or @qcode{"white"} (default) ## @item @qcode{"b"} or @qcode{"blue"}. ## @item @qcode{"c"} or @qcode{"cyan"}. ## @item @qcode{"g"} or @qcode{"green"}. ## @item @qcode{"k"} or @qcode{"black"}. ## @item @qcode{"m"} or @qcode{"magenta"}. ## @item @qcode{"r"} or @qcode{"red"}. ## @item @qcode{"y"} or @qcode{"yellow"}. ## @end itemize ## ## The option @var{order} must be a string with values @qcode{"shuffle"} or ## @qcode{"noshuffle"} (default). If shuffled, the colors in @var{cmap} are ## permuted randomly before the image conversion. ## ## The output RGB image is always of class uint8. ## ## @seealso{bwconncomp, bwlabel, colormap, ind2rgb} ## @end deftypefn function rgb = label2rgb (L, cmap = @jet, background = "w", order = "noshuffle") if (nargin < 1 || nargin > 4) print_usage (); elseif (! isimage (L) || ndims (L) > 4 || size (L, 3) != 1 || any (L(:) != fix (L(:))) || any (L(:) < 0)) error ("label2rgb: L must be a labelled image"); elseif (! ischar (cmap) && ! isa (cmap, "function_handle") && ! iscolormap (cmap)) error ("label2rgb: CMAP must be a colormap, colormap name, or colormap function"); elseif (! ischar (background) && ! iscolormap (background)) error("label2rgb: BACKGROUND must be a colorname or a RGB triplet"); elseif (! any (strcmpi (order, {"noshuffle", "shuffle"}))) error("label2rgb: ORDER must be either 'noshuffle' or 'shuffle'"); endif ## Convert map to a matrix if needed num_objects = max (L(:)); if (ischar (cmap) || isa (cmap, "function_handle")) ## cast to double because of bug #44070 cmap = feval (cmap, double (num_objects)); endif num_colors = rows (cmap); if (num_objects > num_colors) error ("label2rgb: CMAP has not enough colors (%i) for all objects (%i) in L", num_colors, num_objects); endif background = handle_colorspec ("label2rgb", background); ## Should we shuffle the colormap? if (strcmpi (order, "shuffle")) ## Matlab does the shuffling "pseudorandomly". We don't know how it ## actually does the shuffling since it is not documented but using ## the same labeled image and colormap, Matlab always returns the same. cmap = cmap(randperm (num_colors), :); endif ## Check if the background color is in the colormap idx = find (ismember (cmap, background, "rows")); if (! isempty (idx)) if (isscalar (idx)) warning ("label2rgb: region %i has the same color as background", idx); else idx_list = sprintf ("%i, ", idx(1:end-1)); idx_list = sprintf ("%s, and %i", idx_list, idx(end)); warning ("label2rgb: regions %s, have the same color as background", idx_list); endif endif ## We will use ind2rgb for the conversion. An indexed image is interpreted ## differently depending if it's an integer or floating point image. We make ## sure we pass an integer image where value of zero is the color in the ## first row of the colormap (if it was a floating point image, the image ## could not have zero values, and a value of 1 is the color in the first ## row of the colormap). if (! isinteger (L)) if (num_objects <= intmax ("uint8")), L = uint8 (L); elseif (num_objects <= intmax ("uint16")), L = uint16 (L); elseif (num_objects <= intmax ("uint32")), L = uint32 (L); else, L = uint64 (L); endif endif ## Insert the background color at the head of the colormap rgb = ind2rgb (L, [background; cmap]); rgb = im2uint8 (rgb); endfunction %!function map = test_colormap () %! map = [0 0 0; 0.5 0.5 0.5; 0.125 0.125 0.125]; %!endfunction %!shared in, out, cmap %! in = [ 0 1 1 0 2 2 0 3 3 %! 0 1 1 0 2 2 0 3 3]; %! %! out = [255 0 0 255 128 128 255 32 32 %! 255 0 0 255 128 128 255 32 32]; %! out(:,:,2) = out(:,:,3) = out(:,:,1); %! out = uint8(out); %! %! cmap = [0 0 0; 0.5 0.5 0.5; 0.125 0.125 0.125]; %!assert (label2rgb (in, cmap), out); %!assert (label2rgb (uint8 (in), cmap), out); %!assert (label2rgb (in, "test_colormap"), out); %!assert (label2rgb (in, @test_colormap), out); %! %! out(find (in == 0)) = 0; %!assert (label2rgb (in, cmap, "cyan"), out); %!assert (label2rgb (in, cmap, [0 1 1]), out); %! %! in(1) = 10; %!error label2rgb (in, cmap); %!error label2rgb (in, cmap, 89); %!error label2rgb (in, cmap, "g", "wrong"); image-2.4.1/inst/PaxHeaders.6632/padarray.m0000644000000000000000000000013212561122761015216 xustar0030 mtime=1438950897.766252238 30 atime=1438950897.766252238 30 ctime=1438950899.342252237 image-2.4.1/inst/padarray.m0000644000175000017500000006132012561122761020043 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} padarray (@var{A}, @var{padsize}) ## @deftypefnx {Function File} {} padarray (@dots{}, @var{padval}) ## @deftypefnx {Function File} {} padarray (@dots{}, @var{pattern}) ## @deftypefnx {Function File} {} padarray (@dots{}, @var{direction}) ## Pad array or matrix. ## ## Adds padding of length @var{padsize}, to a numeric matrix @var{A}. ## @var{padsize} must be a vector of non-negative values, each of them ## defining the length of padding to its corresponding dimension. For ## example, if @var{padsize} is [4 5], it adds 4 rows (1st dimension) ## and 5 columns (2nd dimension), to both the start and end of @var{A}. ## ## If there's less values in @var{padsize} than number of dimensions in @var{A}, ## they're assumed to be zero. Singleton dimensions of @var{A} are also ## padded accordingly (except when @var{pattern} is @qcode{"reflect"}). ## ## The values used in the padding can either be a scalar value @var{padval}, or ## the name of a specific @var{pattern}. Available patterns are: ## ## @table @asis ## @item @qcode{"zeros"} (default) ## Pads with the value 0 (same as passing a @var{padval} of 0). This is the ## default. ## ## @item @qcode{"circular"} ## Pads with a circular repetition of elements in @var{A} (similar to ## tiling @var{A}). ## ## @item @qcode{"replicate"} ## Pads replicating the values at the border of @var{A}. ## ## @item @qcode{"symmetric"} ## Pads with a mirror reflection of @var{A}. ## ## @item @qcode{"reflect"} ## Same as "symmetric", but the borders are not used in the padding. Because ## of this, it is not possible to pad singleton dimensions. ## ## @end table ## ## By default, padding is done in both directions. To change this, ## @var{direction} can be one of the following values: ## ## @table @asis ## @item @qcode{"both"} (default) ## Pad each dimension before the first element of @var{A} the number ## of elements defined by @var{padsize}, and the same number again after ## the last element. This is the default. ## ## @item @qcode{"pre"} ## Pad each dimension before the first element of @var{A} the number of ## elements defined by @var{padsize}. ## ## @item @qcode{"post"} ## Pad each dimension after the last element of @var{A} the number of ## elements defined by @var{padsize}. ## ## @end table ## ## @seealso{cat, flipdim, resize, prepad, postpad} ## @end deftypefn function B = padarray(A, padsize, varargin) if (nargin < 2 || nargin > 4) print_usage (); elseif (! isvector (padsize) || ! isnumeric (padsize) || any (padsize < 0) || any (padsize != fix (padsize))) error ("padarray: PADSIZE must be a vector of non-negative integers"); endif ## Assure padsize is a row vector padsize = padsize(:).'; if (! any (padsize)) ## Nothing to do here B = A; return endif ## Default values padval = 0; pattern = ""; direction = "both"; ## There won't be more than 2 elements in varargin ## We have to support setting the padval (shape) and direction in any ## order. Both examples must work: ## padarray (A, padsize, "circular", "pre") ## padarray (A, padsize, "pre", "circular") for opt = 1:numel(varargin) val = varargin{opt}; if (ischar (val)) if (any (strcmpi (val, {"pre", "post", "both"}))) direction = val; elseif (any (strcmpi (val, {"circular", "replicate", "reflect", "symmetric"}))) pattern = val; elseif (strcmpi (val, "zeros")) padval = 0; else error ("padarray: unrecognized string option `%s'", val); endif elseif (isscalar (val)) padval = val; else error ("padarray: PADVAL and DIRECTION must be a string or a scalar"); endif endfor fancy_pad = false; if (! isempty (pattern)) fancy_pad = true; endif ## Check direction pre = any (strcmpi (direction, {"pre", "both"})); post = any (strcmpi (direction, {"post", "both"})); ## Create output matrix B_ndims = max ([numel(padsize) ndims(A)]); A_size = size (A); P_size = padsize; A_size(end+1:B_ndims) = 1; # add singleton dimensions P_size(end+1:B_ndims) = 0; # assume zero for missing dimensions pre_pad_size = P_size * pre; B_size = A_size + pre_pad_size + (P_size * post); ## insert input matrix into output matrix A_idx = cell (B_ndims, 1); for dim = 1:B_ndims A_idx{dim} = (pre_pad_size(dim) +1):(pre_pad_size(dim) + A_size(dim)); endfor if (post && ! pre && (padval == 0 || fancy_pad)) ## optimization for post padding only with zeros B = resize (A, B_size); else B = repmat (cast (padval, class (A)), B_size); B(A_idx{:}) = A; endif if (fancy_pad) ## Init a template "index all" cell array template_idx = repmat ({":"}, [B_ndims 1]); circular = replicate = symmetric = reflect = false; switch (tolower (pattern)) case "circular", circular = true; case "replicate", replicate = true; case "symmetric", symmetric = true; case "reflect", reflect = true; otherwise error ("padarray: unknown PADVAL `%s'.", pattern); endswitch ## For a dimension of the input matrix of size 1, since reflect does ## not includes the borders, it is not possible to pad singleton dimensions. if (reflect && any ((! (A_size -1)) & P_size)) error ("padarray: can't add %s padding to singleton dimensions", pattern); endif ## For symmetric and reflect: ## ## The idea is to split the padding into 3 different cases: ## bits ## Parts of the input matrix that are used for the padding. ## In most user cases, there will be only this padding, ## complete will be zero, and so bits will be equal to padsize. ## complete ## Number of full copies of the input matrix are used for ## the padding (for reflect, "full" size is actually minus 1). ## This is divided into pair and unpaired complete. In most ## cases, this will be zero. ## pair complete ## Number of pairs of complete copies. ## unpaired complete ## This is either 1 or 0. If 1, then the complete copy closer ## to the output borders has already been flipped so that if ## there's bits used to pad as well, they don't need to be flipped. ## ## Reasoning pair and unpaired complete: when the pad is much larger ## than the input matrix, we must pay we must pay special attention to ## symmetric and reflect. In a normal case (the padding is smaller than ## the input), we just use the flipped matrix to pad and we're done. ## In other cases, if the input matrix is used multiple times on the ## pad, every other copy of it must NOT be flipped (the padding must be ## symmetric itself) or the padding will be circular. if (reflect) A_cut_size = A_size -1; complete = floor (P_size ./ A_cut_size); bits = rem (P_size, A_cut_size); pair_size = A_cut_size * 2; pair_complete = floor (complete / 2); unpaired_complete = mod (complete, 2); else complete = floor (P_size ./ A_size); bits = rem (P_size, A_size); if (circular) complete_size = complete .* A_size; elseif (symmetric) pair_complete = floor (complete / 2); pair_size = A_size * 2; unpaired_complete = mod (complete, 2); endif endif dim = 0; for s = padsize dim++; if (s == 0) ## skip this dimension if no padding requested continue endif if (circular) dim_idx = template_idx; source_idx = template_idx; A_idx_end = A_idx{dim}(end); A_idx_ini = A_idx{dim}(1); if (complete(dim)) dim_pad_size(1:B_ndims) = 1; dim_pad_size(dim) = complete(dim)*pre + complete(dim)*post; dim_idx{dim} = []; if (pre) dim_idx{dim} = [(bits(dim) +1):(complete_size(dim) + bits(dim))]; endif if (post) dim_idx{dim} = [dim_idx{dim} (A_idx_end +1):(A_idx_end + complete_size(dim))]; endif source_idx{dim} = A_idx{dim}; B(dim_idx{:}) = repmat (B(source_idx{:}), dim_pad_size); endif if (pre) if (bits(dim)) dim_idx{dim} = 1:bits(dim); source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end; B(dim_idx{:}) = B(source_idx{:}); endif endif if (post) if (bits(dim)) dim_idx{dim} = (B_size(dim) -bits(dim) +1):B_size(dim); source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1); B(dim_idx{:}) = B(source_idx{:}); endif endif elseif (replicate) dim_pad_size(1:B_ndims) = 1; dim_pad_size(dim) = P_size(dim); dim_idx = template_idx; source_idx = template_idx; if (pre) dim_idx{dim} = 1:P_size(dim); source_idx{dim} = P_size(dim) +1; B(dim_idx{:}) = repmat (B(source_idx{:}), dim_pad_size); endif if (post) dim_idx{dim} = (A_idx{dim}(end) +1):B_size(dim); source_idx{dim} = A_idx{dim}(end); B(dim_idx{:}) = repmat (B(source_idx{:}), dim_pad_size); endif ## The idea behind symmetric and reflect passing is the same so the ## following cases have similar looking code. However, there's small ## adjustements everywhere that makes it really hard to merge as a ## common case. elseif (symmetric) dim_idx = template_idx; source_idx = template_idx; A_idx_ini = A_idx{dim}(1); A_idx_end = A_idx{dim}(end); if (pre) if (bits(dim)) dim_idx{dim} = 1:bits(dim); if (unpaired_complete(dim)) source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end; B(dim_idx{:}) = B(source_idx{:}); else source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1); B(dim_idx{:}) = flipdim (B(source_idx{:}), dim); endif endif endif if (post) if (bits(dim)) dim_idx{dim} = (B_size(dim) - bits(dim) +1):B_size(dim); if (unpaired_complete(dim)) source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1); B(dim_idx{:}) = B(source_idx{:}); else source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end; B(dim_idx{:}) = flipdim (B(source_idx{:}), dim); endif endif endif if (complete(dim)) dim_pad_size(1:B_ndims) = 1; source_idx{dim} = A_idx{dim}; flipped_source = flipdim (B(source_idx{:}), dim); endif if (pair_complete(dim)) dim_pad_size(dim) = pair_complete(dim); dim_idx{dim} = []; if (pre) dim_idx{dim} = [(1 + bits(dim) + (A_size(dim)*unpaired_complete(dim))):(A_idx_ini -1)]; B(dim_idx{:}) = repmat (cat (dim, B(source_idx{:}), flipped_source), dim_pad_size); endif if (post) dim_idx{dim} = [(A_idx_end +1):(A_idx_end + (pair_size(dim) * pair_complete(dim)))]; B(dim_idx{:}) = repmat (cat (dim, flipped_source, B(source_idx{:})), dim_pad_size); endif endif if (unpaired_complete(dim)) source_idx = template_idx; if (pre) dim_idx{dim} = (1 + bits(dim)):(bits(dim) + A_size(dim)); B(dim_idx{:}) = flipped_source(source_idx{:}); endif if (post) dim_idx{dim} = (B_size(dim) - bits(dim) - A_size(dim) +1):(B_size(dim) - bits(dim)); B(dim_idx{:}) = flipped_source(source_idx{:}); endif endif elseif (reflect) dim_idx = template_idx; source_idx = template_idx; A_idx_ini = A_idx{dim}(1); A_idx_end = A_idx{dim}(end); if (pre) if (bits(dim)) dim_idx{dim} = 1:bits(dim); if (unpaired_complete(dim)) source_idx{dim} = (A_idx_end - bits(dim)):(A_idx_end -1); B(dim_idx{:}) = B(source_idx{:}); else source_idx{dim} = (A_idx_ini +1):(A_idx_ini + bits(dim)); B(dim_idx{:}) = flipdim (B(source_idx{:}), dim); endif endif endif if (post) if (bits(dim)) dim_idx{dim} = (B_size(dim) - bits(dim) +1):B_size(dim); if (unpaired_complete(dim)) source_idx{dim} = (A_idx_ini +1):(A_idx_ini + bits(dim)); B(dim_idx{:}) = B(source_idx{:}); else source_idx{dim} = (A_idx_end - bits(dim)):(A_idx_end -1); B(dim_idx{:}) = flipdim (B(source_idx{:}), dim); endif endif endif if (complete(dim)) dim_pad_size(1:B_ndims) = 1; source_idx{dim} = A_idx{dim}; flipped_source = flipdim (B(source_idx{:}), dim); endif if (pair_complete(dim)) dim_pad_size(dim) = pair_complete(dim); dim_idx{dim} = []; if (pre) flipped_source_idx = source_idx; flipped_source_idx{dim} = 1:A_cut_size(dim); source_idx{dim} = A_idx_ini:(A_idx_end -1); dim_idx{dim} = [(1 + bits(dim) + (A_cut_size(dim)*unpaired_complete(dim))):(A_idx_ini -1)]; B(dim_idx{:}) = repmat (cat (dim, B(source_idx{:}), flipped_source(flipped_source_idx{:})), dim_pad_size); endif if (post) flipped_source_idx = source_idx; flipped_source_idx{dim} = 2:A_size(dim); source_idx{dim} = (A_idx_ini +1):A_idx_end; dim_idx{dim} = [(A_idx_end +1):(A_idx_end + (pair_size(dim) * pair_complete(dim)))]; B(dim_idx{:}) = repmat (cat (dim, flipped_source(flipped_source_idx{:}), B(source_idx{:})), dim_pad_size); endif endif if (unpaired_complete(dim)) source_idx = template_idx; if (pre) source_idx{dim} = 1:(A_size(dim)-1); dim_idx{dim} = (1 + bits(dim)):(bits(dim) + A_size(dim) -1); B(dim_idx{:}) = flipped_source(source_idx{:}); endif if (post) source_idx{dim} = 2:A_size(dim); dim_idx{dim} = (B_size(dim) - bits(dim) - A_size(dim) +2):(B_size(dim) - bits(dim)); B(dim_idx{:}) = flipped_source(source_idx{:}); endif endif endif endfor endif 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 %! 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], "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 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 %!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); %! ## same with uint class %! assert (padarray (uint8 (A), [9 4], "replicate", "pre"), uint8 (B(1:11,1:6))); %! assert (padarray (uint8 (A), [9 4], "replicate", "post"), uint8 (B(10:20,5:10))); %! assert (padarray (uint8 (A), [9 4], "replicate", "both"), uint8 (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)); %! ## same with int class %! assert (padarray (int16 (A), [1 2], "symmetric", "pre"), int16 (B(2:4,2:6))); %! assert (padarray (int16 (A), [1 2], "symmetric", "post"), int16 (B(3:5,4:8))); %! assert (padarray (int16 (A), [1 2], "symmetric", "both"), int16 (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 (uint32 ([1; 2]), [1], 6, "post"), uint32 ([1; 2; 6])); %!assert (padarray (int32 ([1; 2]), [1], int32 (4), "pre"), int32 ([4; 1; 2])); ## Test symmetric and reflect for multiple lengths of padding (since the way ## it's done changes based on this). By iterating from 10 on a matrix of size ## 10, we catch the cases where there's only part of the matrix on the pad, a ## single copy of the matrix, a single copy with bits of non-flipped matrix, two ##copies of the matrix (flipped and non-flipped), the two copies with bits. %!test %! in = [ 7 5 1 3 %! 5 3 3 4 %! 7 5 2 3 %! 6 1 3 8]; %! padded = [ %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 5 7 7 5 1 3 3 1 %! 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 3 5 5 3 3 4 4 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 1 6 6 1 3 8 8 3 %! 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2 5 7 7 5 2 3 3 2]; %! for ite = 1:10 %! assert (padarray (in, [ite ite], "symmetric"), padded((11-ite):(14+ite),(11-ite):(14+ite))); %! assert (padarray (in, [ite ite], "symmetric", "pre"), padded((11-ite):14,(11-ite):14)); %! assert (padarray (in, [ite ite], "symmetric", "post"), padded(11:(14+ite),11:(14+ite))); %! endfor %!test %! in = [ 7 5 4 9 %! 6 4 5 1 %! 5 3 3 3 %! 2 6 7 3]; %! padded = [ %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 7 3 7 6 2 6 %! 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 3 3 3 3 5 3 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 %! 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 4 9 4 5 7 5 %! 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4 5 1 5 4 6 4]; %! for ite = 1:10 %! assert (padarray (in, [ite ite], "reflect"), padded((11-ite):(14+ite),(11-ite):(14+ite))); %! assert (padarray (in, [ite ite], "reflect", "pre"), padded((11-ite):14,(11-ite):14)); %! assert (padarray (in, [ite ite], "reflect", "post"), padded(11:(14+ite),11:(14+ite))); %! endfor image-2.4.1/inst/PaxHeaders.6632/imremap.m0000644000000000000000000000013212561122761015045 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imremap.m0000644000175000017500000001653212561122761017677 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2006 Søren Hauberg ## ## 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 3 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{warped} = imremap(@var{im}, @var{XI}, @var{YI}) ## @deftypefnx{Function File} @var{warped} = imremap(@var{im}, @var{XI}, @var{YI}, @var{interp}, @var{extrapval}) ## @deftypefnx{Function File} [@var{warped}, @var{valid} ] = imremap(@dots{}) ## Applies any geometric transformation to the image @var{im}. ## ## The arguments @var{XI} and @var{YI} are lookup tables that define the resulting ## image ## @example ## @var{warped}(y,x) = @var{im}(@var{YI}(y,x), @var{XI}(y,x)) ## @end example ## where @var{im} is assumed to be a continuous function, which is achieved ## by interpolation. Note that the image @var{im} is expressed in a (X, Y)-coordinate ## system and not a (row, column) system. ## ## The optional argument @var{method} defines the interpolation method to be ## used. All methods supported by @code{interp2} can be used. By default, the ## @code{linear} method is used. ## ## For @sc{matlab} compatibility, the methods @code{bicubic} (same as ## @code{cubic}), @code{bilinear} and @code{triangle} (both the same as ## @code{linear}) are also supported. ## ## All values of the result that fall outside the original image will ## be set to @var{extrapval}. The default value of @var{extrapval} is 0. ## ## The optional output @var{valid} is a matrix of the same size as @var{warped} ## that contains the value 1 in pixels where @var{warped} contains an interpolated ## value, and 0 in pixels where @var{warped} contains an extrapolated value. ## @seealso{imperspectivewarp, imrotate, imresize, imshear, interp2} ## @end deftypefn function [warped, valid] = imremap(im, XI, YI, interp = "linear", extrapval = 0) if (nargin < 3 || nargin > 5) print_usage (); elseif (! isimage (im) || ndims (im) > 3) error ("imremap: IM must be a grayscale or RGB image.") elseif (! size_equal (XI, YI) || ! ismatrix (XI) || ! isnumeric (XI)) error ("imremap: XI and YI must be matrices of the same size"); elseif (! ischar (interp)) error ("imremap: INTERP must be a string with interpolation method") elseif (! isscalar (extrapval)) error ("imremap: EXTRAPVAL must be a scalar"); endif interp = interp_method (interp); ## Interpolate if (size (im, 3) == 1) # Gray warped = grayinterp(im, XI, YI, interp, 0); else # rgb image for i = 3:-1:1 warped(:,:,i) = grayinterp(im(:,:,i), XI, YI, interp, 0); endfor endif valid = !isna(warped); warped(!valid) = extrapval; ## we return image on same class as input warped = cast (warped, class (im)); endfunction function [warped, valid] = grayinterp(im, XI, YI, interp, extrapval) if (strcmp(interp, "cubic")) warped = graybicubic(double(im), XI, YI, 0); else warped = interp2(double(im), XI, YI, interp, 0); endif valid = !isna(warped); warped(!valid) = extrapval; endfunction ## -*- texinfo -*- ## @deftypefn {Function File} {@var{zi}=} bicubic (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi}) ## Reference: ## Image Processing, Analysis, and Machine Vision, 2nd Ed. ## Sonka et.al. ## Brooks/Cole Publishing Company ## ISBN: 0-534-95393-X ## @seealso{interp2} ## @end deftypefn function ZI = graybicubic (Z, XI, YI, extrapval = 0) ## Allocate output [X, Y] = meshgrid(1:columns(Z), 1:rows(Z)); [Zr, Zc] = size(XI); ZI = zeros(Zr, Zc); ## Find inliers inside = !( XI < X(1) | XI > X(end) | YI < Y(1) | YI > Y(end) ); ## Scale XI and YI to match indices of Z (not needed when interpolating images) #XI = (columns(Z)-1) * ( XI - X(1) ) / (X(end)-X(1)) + 1; #YI = (rows(Z)-1) * ( YI - Y(1) ) / (Y(end)-Y(1)) + 1; ## Start the real work K = floor(XI); L = floor(YI); ## Coefficients AY1 = bc((YI-L+1)); AX1 = bc((XI-K+1)); AY0 = bc((YI-L+0)); AX0 = bc((XI-K+0)); AY_1 = bc((YI-L-1)); AX_1 = bc((XI-K-1)); AY_2 = bc((YI-L-2)); AX_2 = bc((XI-K-2)); ## Perform interpolation sz = size(Z); %ZI(inside) = AY_2 .* AX_2 .* Z(sym_sub2ind(sz, L+2, K+2)) ... ZI = AY_2 .* AX_2 .* Z(sym_sub2ind(sz, L+2, K+2)) ... + AY_2 .* AX_1 .* Z(sym_sub2ind(sz, L+2, K+1)) ... + AY_2 .* AX0 .* Z(sym_sub2ind(sz, L+2, K)) ... + AY_2 .* AX1 .* Z(sym_sub2ind(sz, L+2, K-1)) ... + AY_1 .* AX_2 .* Z(sym_sub2ind(sz, L+1, K+2)) ... + AY_1 .* AX_1 .* Z(sym_sub2ind(sz, L+1, K+1)) ... + AY_1 .* AX0 .* Z(sym_sub2ind(sz, L+1, K)) ... + AY_1 .* AX1 .* Z(sym_sub2ind(sz, L+1, K-1)) ... + AY0 .* AX_2 .* Z(sym_sub2ind(sz, L, K+2)) ... + AY0 .* AX_1 .* Z(sym_sub2ind(sz, L, K+1)) ... + AY0 .* AX0 .* Z(sym_sub2ind(sz, L, K)) ... + AY0 .* AX1 .* Z(sym_sub2ind(sz, L, K-1)) ... + AY1 .* AX_2 .* Z(sym_sub2ind(sz, L-1, K+2)) ... + AY1 .* AX_1 .* Z(sym_sub2ind(sz, L-1, K+1)) ... + AY1 .* AX0 .* Z(sym_sub2ind(sz, L-1, K)) ... + AY1 .* AX1 .* Z(sym_sub2ind(sz, L-1, K-1)); ZI(!inside) = extrapval; endfunction ## Checks if data is meshgrided function b = isgriddata(X) D = X - repmat(X(1,:), rows(X), 1); b = all(D(:) == 0); endfunction ## Checks if data is equally spaced (assumes data is meshgrided) function b = isequallyspaced(X) Dx = gradient(X(1,:)); b = all(Dx == Dx(1)); endfunction ## Computes the interpolation coefficients function o = bc(x) x = abs(x); o = zeros(size(x)); idx1 = (x < 1); idx2 = !idx1 & (x < 2); o(idx1) = 1 - 2.*x(idx1).^2 + x(idx1).^3; o(idx2) = 4 - 8.*x(idx2) + 5.*x(idx2).^2 - x(idx2).^3; endfunction ## This version of sub2ind behaves as if the data was symmetrically padded function ind = sym_sub2ind(sz, Y, X) Y(Y<1) = 1 - Y(Y<1); while (any(Y(:)>2*sz(1))) Y(Y>2*sz(1)) = round( Y(Y>2*sz(1))/2 ); endwhile Y(Y>sz(1)) = 1 + 2*sz(1) - Y(Y>sz(1)); X(X<1) = 1 - X(X<1); while (any(X(:)>2*sz(2))) X(X>2*sz(2)) = round( X(X>2*sz(2))/2 ); endwhile X(X>sz(2)) = 1 + 2*sz(2) - X(X>sz(2)); ind = sub2ind(sz, Y, X); endfunction %!demo %! ## Generate a synthetic image and show it %! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1; %! I(20:30, 20:30) = !I(20:30, 20:30); %! I(70:80, 70:80) = !I(70:80, 70:80); %! figure, imshow(I); %! ## Resize the image to the double size and show it %! [XI, YI] = meshgrid(linspace(1, 100, 200)); %! warped = imremap(I, XI, YI); %! figure, imshow(warped); %!demo %! ## Generate a synthetic image and show it %! I = tril(ones(100)) + abs(rand(100)); I(I>1) = 1; %! I(20:30, 20:30) = !I(20:30, 20:30); %! I(70:80, 70:80) = !I(70:80, 70:80); %! figure, imshow(I); %! ## Rotate the image around (0, 0) by -0.4 radians and show it %! [XI, YI] = meshgrid(1:100); %! R = [cos(-0.4) sin(-0.4); -sin(-0.4) cos(-0.4)]; %! RXY = [XI(:), YI(:)] * R; %! XI = reshape(RXY(:,1), [100, 100]); YI = reshape(RXY(:,2), [100, 100]); %! warped = imremap(I, XI, YI); %! figure, imshow(warped); image-2.4.1/inst/PaxHeaders.6632/imsubtract.m0000644000000000000000000000013212561122761015570 xustar0030 mtime=1438950897.754252238 30 atime=1438950897.754252238 30 ctime=1438950899.342252237 image-2.4.1/inst/imsubtract.m0000644000175000017500000001020312561122761020407 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2011 Carnë Draug ## ## 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 3 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{out} =} imsubtract (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{out} =} imsubtract (@var{a}, @var{b}, @var{class}) ## Subtract image or constant to an image. ## ## If @var{a} and @var{b} are two images of same size and class, @var{b} is subtracted ## to @var{a}. Alternatively, if @var{b} is a floating-point scalar, its value is subtracted ## to the image @var{a}. ## ## The class of @var{out} will be the same as @var{a} unless @var{a} is logical ## in which case @var{out} will be double. Alternatively, it can be ## specified with @var{class}. ## ## @emph{Note 1}: you can force output class to be logical by specifying ## @var{class}. This is incompatible with @sc{matlab} which will @emph{not} honour ## request to return a logical matrix. ## ## @emph{Note 2}: the values are truncated to the mininum value of the output ## class. ## ## @emph{Note 3}: values are truncated before the operation so if input images are ## unsigned integers and the request output class is a signed integer, it may lead ## to unexpected results: ## ## @example ## @group ## imsubtract (uint8 ([23 190]), uint8 ([24 200]), "int8") ## @result{} -1 0 ## @end group ## @end example ## ## Because both 190 and 200 were truncated to 127 before subtraction, their difference ## is zero. ## @seealso{imabsdiff, imadd, imcomplement, imdivide, imlincomb, immultiply} ## @end deftypefn function img = imsubtract (img, val, out_class = class (img)) if (nargin < 2 || nargin > 3) print_usage; elseif (any (isa (img, {"uint8", "uint16", "uint32", "uint64"})) && any (strcmpi (out_class, {"int8", "int16", "int32", "int64"}))) ## because we convert the images before the subtraction, if input is: ## imsubtract (uint8(150), uint8 (200), "int8"); ## rsult will be 0 because both values are truncated to 127 before subtraction. ## There is no matlab compatibility issue because matlab does not have the option ## to specify output class in imsubtract warning ("input images are unsigned integers but requested output is signed integer. This may lead to unexpected results."); endif [img, val] = imarithmetics ("imsubtract", img, val, out_class); ## The following makes the code imcompatible with matlab on certain cases. ## This is on purpose. Read comments in imadd source for the reasons if (nargin > 2 && strcmpi (out_class, "logical")) img = img > val; else img = img - val; endif endfunction %!assert (imsubtract (uint8 ([23 250]), uint8 ([24 50])), uint8 ([ 0 200])); # default to first class and truncate %!assert (imsubtract (uint8 ([23 250]), 10), uint8 ([13 240])); # works subtracting a scalar %!assert (imsubtract (uint8 ([23 250]), uint8 ([24 50]), "uint16"), uint16 ([ 0 200])); # defining output class works (not in matlab) %!assert (imsubtract (logical ([ 1 0]), logical ([ 1 1])), double ([ 0 -1])); # return double for two logical images %!assert (imsubtract (logical ([ 1 0]), logical ([ 1 1]), "logical"), logical ([ 0 0])); # this is matlab incompatible on purpose %!fail ("imsubtract (uint8 ([23 250]), uint16 ([23 250]))"); # input need to have same class %!assert (imsubtract (uint8 ([23 250]), uint8 ([24 255]), "int8"), int8 ([-1 0])); # signed integers kinda work (not in matlab) %!warning imsubtract (uint8 ([23 250]), uint8 ([24 255]), "int8"); image-2.4.1/inst/PaxHeaders.6632/bwareafilt.m0000644000000000000000000000013212561122761015533 xustar0030 mtime=1438950897.718252238 30 atime=1438950897.718252238 30 ctime=1438950899.342252237 image-2.4.1/inst/bwareafilt.m0000644000175000017500000002451212561122761020362 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014 Carnë Draug ## ## 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 3 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} {} bwareafilt (@var{bw}, @var{range}) ## @deftypefnx {Function File} {} bwareafilt (@var{bw}, @var{n}) ## @deftypefnx {Function File} {} bwareafilt (@var{bw}, @var{n}, @var{keep}) ## @deftypefnx {Function File} {} bwareafilt (@dots{}, @var{conn}) ## Filter objects from image based on their sizes. ## ## Returns a logical matrix with the objects of @var{bw} filtered based ## on their area (defined by thei number of pixels). This function is ## equivalent to @code{bwpropfilt (@var{bw}, "Area", @dots{})}. ## ## To filter objects with a value on a specific interval, @var{range} must be ## a two-element vector with the interval @code{[@var{low} @var{high}]} ## (values are inclusive). ## ## Alternatively, a scalar @var{n} will select the objects with the N highest ## values. The @var{keep} option defaults to @qcode{"largest"} but can also ## be set to @qcode{"smallest"} to select the N objects with lower values. ## ## The last optional argument, @var{conn}, can be a connectivity matrix, or ## the number of elements connected to the center (see @command{conndef}). ## ## @seealso{bwareaopen, bwlabel, bwlabeln, bwconncomp, bwpropfilt, regionprops} ## @end deftypefn function bwfiltered = bwareafilt (bw, varargin) if (nargin < 2 || nargin > 4) print_usage (); endif bwfiltered = bwpropfilt (bw, "Area", varargin{:}); endfunction %!shared a2d, a3d %! a2d = [1 0 0 0 0 0 1 0 0 1 %! 1 0 0 1 0 1 0 1 0 1 %! 1 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 1 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 1 0 0 %! 1 1 0 0 0 0 1 0 1 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 1 1 0 0 1]; %! %! a3d = a2d; %! a3d(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 0 0 0 %! 1 0 0 0 0 0 1 0 0 0 %! 0 1 0 0 0 0 0 0 0 1 %! 1 1 0 0 0 0 1 0 0 0]; %! %! a3d(:,:,3) = [ %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 1 %! 1 1 0 0 0 0 0 0 0 0]; %!test %! f2d = [0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 1 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a2d, 2), logical (f2d)); %! assert (bwareafilt (a2d, 2, 8), logical (f2d)); %! assert (bwareafilt (a2d, 2, 4), logical (f2d)); %!test %! f2d = [1 0 0 0 0 0 1 0 0 0 %! 1 0 0 0 0 1 0 1 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 1 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 1 0 0 %! 1 1 0 0 0 0 1 0 1 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a2d, 5), logical (f2d)); %! assert (bwareafilt (a2d, 5, 8), logical (f2d)); %!test %! f2d = [0 0 0 0 0 0 1 0 0 1 %! 0 0 0 1 0 1 0 1 0 1 %! 0 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 0 1 0 1 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 1 1 0 0 1]; %! assert (bwareafilt (a2d, 11, "smallest", 4), logical (f2d)); %!test %! f2d = [1 0 0 0 0 0 1 0 0 0 %! 1 0 0 0 0 1 0 1 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 1 0 0 0 1 0 0 %! 0 0 0 0 0 0 1 0 1 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a2d, [3 5]), logical (f2d)); %! assert (bwareafilt (a2d, [3 5], 8), logical (f2d)); %!test %! f2d = [1 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a2d, [3 4], 4), logical (f2d)); %! assert (bwareafilt (a2d, [3 4], [0 1 0; 1 1 1; 0 1 0]), logical (f2d)); %!test %! f2d = [1 0 0 0 0 0 1 0 0 1 %! 1 0 0 1 0 1 0 1 0 1 %! 1 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 1 0 0 0 1 0 0 %! 0 0 0 0 0 0 1 0 1 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 1 1 0 0 0]; %! assert (bwareafilt (a2d, [2 4]), logical (f2d)); %! assert (bwareafilt (a2d, [2 4], 8), logical (f2d)); %! assert (bwareafilt (a2d, [2 4], ones (3)), logical (f2d)); %!test %! f3d = [0 0 0 0 0 0 1 0 0 0 %! 0 0 0 1 0 1 0 1 0 0 %! 0 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! %! f3d(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! %! f3d(:,:,3) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a3d, 2), logical (f3d)); %! assert (bwareafilt (a3d, 2, 26), logical (f3d)); %! assert (bwareafilt (a3d, 2, ones (3, 3, 3)), logical (f3d)); %!test %! f3d = [0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 1 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! %! f3d(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! %! f3d(:,:,3) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 0]; %! assert (bwareafilt (a3d, 2, 6), logical (f3d)); %! assert (bwareafilt (a3d, 2, conndef (3, "minimal")), logical (f3d)); image-2.4.1/inst/PaxHeaders.6632/std2.m0000644000000000000000000000013212561122761014267 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/std2.m0000644000175000017500000000206312561122761017113 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## ## 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 3 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{s}= std2 (@var{I}) ## Returns the standard deviation for a 2d real type matrix. ## Uses @code{std (I(:))} ## @seealso{mean2,std} ## @end deftypefn function s = std2 (I) if !(nargin == 1) print_usage (); endif if (! isreal (I)) error("std2: I be a real type array"); endif s = std (I(:)); endfunction image-2.4.1/inst/PaxHeaders.6632/rho_filter.m0000644000000000000000000000013212561122761015550 xustar0030 mtime=1438950897.778252238 30 atime=1438950897.778252238 30 ctime=1438950899.342252237 image-2.4.1/inst/rho_filter.m0000644000175000017500000001312512561122761020375 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Alex Opie ## ## 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 3 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{filtered} =} rho_filter (@var{proj}, @var{type}, @var{scaling}) ## ## Filters the parallel ray projections in the columns of @var{proj}, ## according to the filter type chosen by @var{type}. @var{type} ## can be chosen from ## @itemize ## @item 'none' ## @item 'Ram-Lak' (default) ## @item 'Shepp-Logan' ## @item 'Cosine' ## @item 'Hann' ## @item 'Hamming' ## @end itemize ## ## If given, @var{scaling} determines the proportion of frequencies ## below the nyquist frequency that should be passed by the filter. ## The window function is compressed accordingly, to avoid an abrupt ## truncation of the frequency response. ## ## @end deftypefn ## @deftypefn {Function File} {[@var{filtered}, @var{filter}] =} rho_filter (@dots{}) ## ## This form also returns the frequency response of the filter in ## the vector @var{filter}. ## ## Performs rho filtering on the parallel ray projections provided. ## ## Rho filtering is performed as part of the filtered back-projection ## method of CT image reconstruction. It is the filtered part of ## the name. ## The simplest rho filter is the Ramachadran-Lakshminarayanan (Ram-Lak), ## which is simply |rho|, where rho is the radial component of spatial ## frequency. However, this can cause unwanted amplification of noise, ## which is what the other types attempt to minimise, by introducing ## roll-off into the response. The Hann and Hamming filters multiply ## the standard response by a Hann or Hamming window, respectively. ## The cosine filter is the standard response multiplied by a cosine ## shape, and the Shepp-Logan filter multiplies the response with ## a sinc shape. The 'none' filter performs no filtering, and is ## included for completeness and to enable incorporating this function ## easily into scripts or functions that may offer the ability to choose ## to apply no filtering. ## ## This function is designed to be used by the function @command{iradon}, ## but has been exposed to facilitate custom inverse radon transforms ## and to more clearly break down the process for educational purposes. ## The operations ## @example ## filtered = rho_filter (proj); ## reconstruction = iradon (filtered, 1, 'linear', 'none'); ## @end example ## are exactly equivalent to ## @example ## reconstruction = iradon (proj, 1, 'linear', 'Ram-Lak'); ## @end example ## ## Usage example: ## @example ## P = phantom (); ## projections = radon (P); ## filtered_projections = rho_filter (projections, 'Hamming'); ## reconstruction = iradon (filtered_projections, 1, 'linear', 'none'); ## figure, imshow (reconstruction, []) ## @end example ## ## @end deftypefn function [filtered_proj, filt] = rho_filter (proj, type, scaling) filtered_proj = proj; if (nargin < 3) scaling = 1; endif if (nargin < 2) || (size (type) == 0) type = 'ram-lak'; endif if (strcmpi (type, 'none')) filt = 1; return; endif if (scaling > 1) || (scaling < 0) error ('Scaling factor must be in [0,1]'); endif ## Extend the projections to a power of 2 new_len = 2 * 2^nextpow2 (size (filtered_proj, 1)); filtered_proj (new_len, 1) = 0; ## Scale the frequency response int_len = (new_len * scaling); if (mod (floor (int_len), 2)) int_len = ceil (int_len); else int_len = floor (int_len); endif ## Create the basic filter response rho = scaling * (0:1 / (int_len / 2):1); rho = [rho'; rho(end - 1:-1:2)']; ## Create the window to apply to the filter response if (strcmpi (type, 'ram-lak')) filt = 1; elseif (strcmpi (type, 'hamming')) filt = fftshift (hamming (length (rho))); elseif (strcmpi (type, 'hann')) filt = fftshift (hanning (length (rho))); elseif (strcmpi (type, 'cosine')) f = 0.5 * (0:length (rho) - 1)' / length (rho); filt = fftshift (sin (2 * pi * f)); elseif (strcmpi (type, 'shepp-logan')) f = (0:length (rho) / 2)' / length (rho); filt = sin (pi * f) ./ (pi * f); filt (1) = 1; filt = [filt; filt(end - 1:-1:2)]; else error ('rho_filter: Unknown window type'); endif ## Apply the window filt = filt .* rho; ## Pad the response to the correct length len_diff = new_len - int_len; if (len_diff != 0) pad = len_diff / 2; filt = padarray (fftshift (filt), pad); filt = fftshift (filt); endif filtered_proj = fft (filtered_proj); ## Perform the filtering for i = 1:size (filtered_proj, 2) filtered_proj (:, i) = filtered_proj (:, i) .* filt; endfor ## Finally bring the projections back to the spatial domain filtered_proj = real (ifft (filtered_proj)); ## Chop the projections back to their original size filtered_proj (size (proj, 1) + 1:end, :) = []; endfunction %!demo %! P = phantom (); %! projections = radon (P); %! filtered_projections = rho_filter (projections, 'Hamming'); %! reconstruction = iradon (filtered_projections, 1, 'linear', 'none'); %! figure, imshow (reconstruction, []) image-2.4.1/inst/PaxHeaders.6632/isbw.m0000644000000000000000000000013212561122761014357 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/isbw.m0000644000175000017500000000552112561122761017205 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} isbw (@var{img}) ## @deftypefnx {Function File} {} isbw (@var{img}, @var{logic}) ## Return true if @var{img} is a black and white image. ## ## A variable can be considered a black and white image if it is a ## non-sparse matrix of size @nospell{MxNx1xK}, and depending on the ## string @var{logic}, defined as: ## ## @table @asis ## @item @qcode{"logical"} (default) ## @var{img} must be of class logical. ## ## @item @qcode{"non-logical"} ## all values in @var{img} are either 1 or 0. ## @end table ## ## @strong{Note:} despite their suggestive names, the functions isbw, ## isgray, isind, and isrgb, are ambiguous since it is not always possible ## to distinguish between those image types. For example, an uint8 matrix ## can be both a grayscale and indexed image. They are good to dismiss ## input as an invalid image type, but not for identification. ## ## @seealso{im2bw, isgray, isind, islogical, isrgb} ## @end deftypefn function bool = isbw (BW, logic = "logical") if (nargin < 1 || nargin > 2) print_usage; endif bool = false; if (isimage (BW) && ndims (BW) < 5 && size (BW, 3) == 1) if (strcmpi (logic, "logical")) ## this is the matlab compatible way (before they removed the function) bool = islogical (BW); elseif (strcmpi (logic, "non-logical")) bool = islogical (BW) || ispart (@is_bw_nonlogical, BW); else error ("isbw: LOGIC must be the string 'logical' or 'non-logical'") endif endif endfunction function bool = is_bw_nonlogical (BW) bool = ! any ((BW(:) != 1) & (BW(:) != 0)); endfunction %!test %! a = round (rand (100)); %! assert (isbw (a, "non-logical"), true); %! assert (isbw (a, "logical"), false); %! assert (isbw (logical (a), "logical"), true); %! assert (isbw (logical (a), "non-logical"), true); %! %! ## change when the different value is near the start and then in middle, %! ## because of the way we test part of the image before the rest %! a(1, 1) = 2; %! assert (isbw (a, "non-logical"), false); %! %! a( 1, 1) = 1; %! a(50, 50) = 2; %! assert (isbw (a, "non-logical"), false); image-2.4.1/inst/PaxHeaders.6632/im2col.m0000644000000000000000000000013212561122761014600 xustar0030 mtime=1438950897.738252238 30 atime=1438950897.738252238 30 ctime=1438950899.342252237 image-2.4.1/inst/im2col.m0000644000175000017500000002134512561122761017430 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013 Carnë Draug ## ## 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 3 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} {} im2col (@var{A}, @var{block_size}) ## @deftypefnx {Function File} {} im2col (@var{A}, @var{block_size}, @var{block_type}) ## @deftypefnx {Function File} {} im2col (@var{A}, "indexed", @dots{}) ## Rearrange blocks from matrix into columns. ## ## Rearranges blocks of size @var{block_size}, sampled from the matrix @var{A}, ## into a serie of columns. This effectively transforms any image into a ## 2 dimensional matrix, a block per column, which can then be passed to ## other functions that perform calculations along columns. ## ## Both blocks and matrix @var{A} can have any number of dimensions (though ## for sliding blocks, a block can't be larger than @var{A} in any dimension). ## Blocks are always accessed in column-major order (like Octave arrays are ## stored) so that a matrix can be easily reconstructed with @code{reshape} ## and @code{col2im}. For a 2 dimensional matrix, blocks are taken first from ## the top to the bottom, and then from the left to the right of the matrix. ## ## The sampling can be performed in two different ways as defined by ## @var{block_type} (defaults to @qcode{"sliding"}): ## ## @table @asis ## @item @qcode{"distinct"} ## Each block is completely distinct from the other, with no overlapping ## elements. The matrix @var{A} is padded as required with a value of 0 ## (or 1 for non-integer indexed images). ## ## @item @qcode{"sliding"} ## A single block slides across @var{A} without any padding. ## ## While this can be used to perform sliding window operations such as maximum ## and median filters, specialized functions such as @code{imdilate} and ## @code{medfilt2} will be more efficient. ## ## Note that large images being arranged in large blocks can easily exceed the ## maximum matrix size (see @code{sizemax}). For example, a matrix @var{A} of ## size 500x500, with sliding block of size [100 100], would require a matrix ## with 2.4108e+09 elements, i.e., the number of elements in a block, ## @code{100*100}, times the number of blocks, @code{(500-10+1) * (500-10+1)}. ## ## @end table ## ## If @var{A} is an indexed image, the second argument should be the ## string @qcode{"indexed"} so that any required padding is done correctly. ## The padding value will be 0 except for indexed images of class uint8 ## and uint16. ## ## @seealso{blockproc, bestblk, col2im, colfilt, nlfilter, reshape} ## @end deftypefn ## Matlab behaves weird with N-dimensional images. It ignores block_size ## elements after the first 2, and treat N-dimensional as if the extra ## dimensions were concatenated horizontally. We are performing real ## N-dimensional conversion of image blocks into colums. function B = im2col (A, varargin) ## Input check if (nargin > 4) print_usage (); endif [p, block_size, padval] = im2col_check ("im2col", nargin, A, varargin{:}); if (nargin > p) ## we have block_type param if (! ischar (varargin{p})) error("im2col: BLOCK_TYPE must be a string"); endif block_type = varargin{p++}; else block_type = "sliding"; endif if (nargin > p) print_usage (); endif ## After all the input check, start the actual im2col. The idea is to ## calculate the linear indices for each of the blocks (using broadcasting ## for each dimension), and then reshape it with one block per column. switch (tolower (block_type)) case "distinct" ## We may need to expand the size vector to include singletons size_singletons = @(x, ndim) postpad (size (x), ndim, 1); ## Calculate needed padding A_size = size_singletons (A, numel (block_size)); sp = mod (-A_size, block_size); if (any (sp)) A = padarray (A, sp, padval, "post"); endif A_size = size_singletons (A, numel (block_size)); ## Get linear indixes for the first block [ind, stride] = get_1st_ind (A_size, block_size); ## Get linear indices for all of the blocks blocks = A_size ./ block_size; step = stride .* block_size; limit = step .* (blocks -1); for dim = 1:numel (A_size) ind = ind(:) .+ (0:step(dim):limit(dim)); endfor n_blocks = prod (blocks); case "sliding" if (numel (block_size) > ndims (A)) error ("im2col: BLOCK_SIZE can't have more elements than the dimensions of A"); elseif (any (size (A) < block_size)) error("im2col: no dimension of A can be greater than BLOCK_SIZE in sliding"); endif ## Get linear indixes for the first block [ind, stride] = get_1st_ind (size (A), block_size); ## Get linear indices for all of the blocks slides = size (A) - block_size; limit = stride .* slides; for dim = 1:ndims (A) ind = ind(:) .+ (0:stride(dim):limit(dim)); endfor n_blocks = prod (slides +1); otherwise error ("im2col: invalid BLOCK_TYPE `%s'.", block_type); endswitch B = reshape (A(ind(:)), prod (block_size), n_blocks); endfunction ## Get linear indices and for the first block, and stride size per dimension function [ind, stride] = get_1st_ind (A_size, block_size) stride = [1 cumprod(A_size(1:end-1))]; limit = (block_size -1) .* stride; ind = 1; for dim = 1:numel (A_size) ind = ind(:) .+ (0:stride(dim):limit(dim)); endfor endfunction %!demo %! ## Divide A using distinct blocks and then reverse the operation %! A = [ 1:10 %! 11:20 %! 21:30 %! 31:40]; %! B = im2col (A, [2 5], "distinct") %! C = col2im (B, [2 5], [4 10], "distinct") ## test default block type %!test %! a = rand (10); %! assert (im2col (a, [5 5]), im2col (a, [5 5], "sliding")) ## indexed makes no difference when sliding %!test %! a = rand (10); %! assert (im2col (a, [5 5]), im2col (a, "indexed", [5 5])) %!error im2col (rand (20), [2 5], 10) %!error im2col (rand (20), [2 5], "wrong_block_type") %!error im2col (rand (10), [11 5], "sliding") %!error im2col (rand (10), [5 5], "sliding", 5) %!error im2col (rand (10), "indexed", [5 5], "sliding", 5) %!shared B, A, Bs, As, Ap, Bp0, Bp1, Bp0_3s %! v = [1:10]'; %! r = reshape (v, 2, 5); %! B = [v v+20 v+40 v+10 v+30 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, 4:6) = 0; %! Bp1(9:10, 4:6) = 1; %! Bp0_3s = Bp0; %! Bp0_3s(11:30, :) = 0; ## test distinct block type %!assert (im2col (A, [2 5], "distinct"), B); ## padding for distinct %!assert (im2col (Ap, [2 5], "distinct"), Bp0); %!assert (im2col (Ap, [2 5 3], "distinct"), Bp0_3s); %!assert (im2col (Ap, "indexed", [2 5], "distinct"), Bp1); %!assert (im2col (uint8 (Ap), "indexed", [2 5], "distinct"), uint8 (Bp0)); %!assert (im2col (uint16 (Ap), "indexed", [2 5], "distinct"), uint16 (Bp0)); %!assert (im2col (int16 (Ap), "indexed", [2 5], "distinct"), int16 (Bp1)); %!assert (im2col (uint32 (Ap), "indexed", [2 5], "distinct"), uint32 (Bp1)); ## Always return correct class %!assert (im2col (uint8 (A), [2 5], "distinct"), uint8 (B)); %!assert (im2col (single (A), [2 5], "distinct"), single (B)); %!assert (im2col (logical (A), [2 5], "distinct"), logical (B)); %!assert (im2col (uint8 (As), [2 4], "sliding"), uint8 (Bs)); %!assert (im2col (single (As), [2 4], "sliding"), single (Bs)); %!assert (im2col (logical (As), [2 4], "sliding"), logical (Bs)); ## test sliding block type %!assert (im2col (As, [2 4], "sliding"), Bs); %!assert (im2col (As, [3 5], "sliding"), As(:)); ## Test N-dimensional %!test %! A = randi (9, 10, 9, 5); %!assert (convn (A, ones (3, 3, 3), "valid"), %! reshape (sum (im2col (A, [3 3 3])), [8 7 3])); %! %! A = randi (9, 10, 9, 5, 7); %!assert (convn (A, ones (3, 3, 3), "valid"), %! reshape (sum (im2col (A, [3 3 3])), [8 7 3 7])); %!assert (convn (A, ones (3, 4, 3), "valid"), %! reshape (sum (im2col (A, [3 4 3])), [8 6 3 7])); %!assert (convn (A, ones (3, 5, 3, 2), "valid"), %! reshape (sum (im2col (A, [3 5 3 2])), [8 5 3 6])); image-2.4.1/inst/PaxHeaders.6632/isgray.m0000644000000000000000000000013212561122761014711 xustar0030 mtime=1438950897.758252238 30 atime=1438950897.758252238 30 ctime=1438950899.342252237 image-2.4.1/inst/isgray.m0000644000175000017500000000454512561122761017544 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011 Carnë Draug ## ## 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 3 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} {} isgray (@var{img}) ## Return true if @var{img} is an indexed image. ## ## A variable can be considered a grayscale image if it is a non-sparse ## matrix of size @nospell{MxNx1xK} and: ## ## @itemize @bullet ## @item is of class double and all values are in the range [0, 1] or NaN; ## @item is of class uint8, uint16 or int16. ## @end itemize ## ## @strong{Note:} despite their suggestive names, the functions isbw, ## isgray, isind, and isrgb, are ambiguous since it is not always possible ## to distinguish between those image types. For example, an uint8 matrix ## can be both a grayscale and indexed image. They are good to dismiss ## input as an invalid image type, but not for identification. ## ## @seealso{gray2ind, isbw, isind, isrgb} ## @end deftypefn function bool = isgray (img) if (nargin != 1) print_usage (); endif bool = false; if (isimage (img) && ndims (img) < 5 && size (img, 3) == 1) switch (class (img)) case "double" bool = ispart (@is_double_image, img); case {"uint8", "uint16", "int16"} bool = true; endswitch endif endfunction %!test %! a = rand (100); %! assert (isgray (a), true); %! a(50, 50) = 2; %! assert (isgray (a), false); %!test %! a = uint8 (randi (255, 100)); %! assert (isgray (a), true); %! a = int8 (a); %! assert (isgray (a), false); %!test %! a = rand (100); %! a(500) = NaN; %! assert (isgray (a), true); %!assert (isgray (rand (5, 5, 1, 4)), true); %!assert (isgray (rand (5, 5, 3, 4)), false); %!assert (isgray (rand (5, 5, 3)), false); %!assert (isgray (rand (5, 5, 1, 3, 4)), false); image-2.4.1/inst/PaxHeaders.6632/fftconvn.m0000644000000000000000000000013212561122761015236 xustar0030 mtime=1438950897.734252238 30 atime=1438950897.734252238 30 ctime=1438950899.342252237 image-2.4.1/inst/fftconvn.m0000644000175000017500000001374312561122761020071 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2015 Carnë Draug ## ## 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 3 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} {} fftconvn (@var{A}, @var{B}) ## @deftypefnx {Function File} {} fftconvn (@var{A}, @var{B}, @var{shape}) ## Convolve N dimensional signals using the FFT for computation. ## ## This function is equivalent to @code{convn} but using the FFT. It ## convolves the two N dimensional @var{A} and @var{B}. The size of ## output is controlled by the option @var{shape} which removes the ## borders where boundary effects may be seen: ## ## @table @asis ## @item @qcode{"full"} (default) ## Return the full convolution. ## ## @item @qcode{"same"} ## Return central part of the convolution with the same size as @var{A}. ## ## @item @qcode{"valid"} ## Return only the parts which do not include zero-padded edges. ## ## @end table ## ## Using the FFT may be faster but this is not always the case and can ## be a lot worse, specially for smalls @var{A} and @var{B}. This performance ## increase also comes at the cost of increased memory usage, as well as a loss ## of precision. ## ## @example ## @group ## a = randi (255, 1024, 1024); ## b = randi (255, 10, 10); ## t = cputime (); convn (a, b); cputime () -t ## @result{} 0.096000 ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 1.2560 ## ## b = randi (255, 50, 50); ## t = cputime (); convn (a, b); cputime () -t ## @result{} 2.3400 ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 1.2560 ## @end group ## @end example ## ## Note how computation time for @code{convn} increased with the size of ## @var{B} but remained constant when using @code{fftconvn}. When ## performing the convolution, @code{fftconvn} zero pads both @var{A} and ## @var{B} so their lengths are a power of two on all dimensions. ## This may further increase memory usage but will also increase ## performance. In this example, the computation time will remain constant ## until @code{size (@var{A}) + size (@var{B}) -1} is greater than 2048 ## after which it will remain constant again until it reaches 4096. ## ## @example ## @group ## a = randi (255, 1024, 1024); ## b = randi (255, 50, 50); ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 1.2760 ## a = randi (255, 2048-50+1, 2048-50+1); ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 1.2120 ## a = randi (255, 2049-50+1, 2049-50+1); ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 6.1520 ## a = randi (255, 4096-50+1, 4096-50+1); ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 6.2360 ## a = randi (255, 4097-50+1, 4097-50+1); ## t = cputime (); fftconvn (a, b); cputime () -t ## @result{} 38.120 ## @end group ## @end example ## ## @seealso{convn, fftconv2, fftconv, padarray} ## @end deftypefn function C = fftconvn (A, B, shape = "full") if (nargin < 2 || nargin > 3) print_usage (); elseif (! isnumeric (A) || ! isnumeric (B)) error ("fftconvn: A and B must be numeric") endif nd = max (ndims (A), ndims (B)); A_size = get_sizes (A, nd); B_size = get_sizes (B, nd); fft_size = 2 .^ nextpow2 (A_size + B_size - 1); C = ifftn (fftn (A, fft_size(1:ndims(A))) .* fftn (B, fft_size(1:ndims(B)))); if (iscomplex (C) && isreal (A) && isreal (B)) C = real (C); endif switch (tolower (shape)) case "full" starts = repmat (1, [1 nd]); ends = A_size + B_size - 1; case "same" prepad = floor (B_size / 2); starts = prepad + 1; ends = A_size + prepad; case "valid" starts = B_size; ends = A_size; otherwise error ("fftconvn: unknown SHAPE `%s'", shape); endswitch if (any (starts > 1) || any (ends != fft_size)) idx = get_ndim_idx (starts, ends); C = C(idx{:}); endif endfunction ## returns the size of x but padded with 1 (singleton dimensions), to ## allow operations to be performed when the ndims do not match function sizes = get_sizes (x, n) sizes = postpad (size (x), n, 1, 2); endfunction ## starts and ends must have same length function idx = get_ndim_idx (starts, ends) idx = arrayfun (@colon, starts, ends, "UniformOutput", false); endfunction %!function test_shapes (a, b, precision) %! shapes = {"valid", "same", "full"}; %! for i = 1:3 %! shape = shapes{i}; %! assert (fftconvn (a, b, shape), convn (a, b, shape), precision); %! endfor %! assert (fftconvn (a, b), fftconvn (a, b, "full")); %!endfunction ## simplest case %!test test_shapes (randi (255, 100), randi (255, 10), 0.1) %!test test_shapes (randi (255, 100, 100), randi (255, 10, 10), 0.1) %!test test_shapes (randi (255, 100, 100, 100), randi (255, 10, 10, 10), 0.1) ## mix of number of dimensions %!test test_shapes (randi (255, 100, 50, 20), randi (255, 10, 7), 0.1) %!test test_shapes (randi (255, 100, 50, 20), randi (255, 10), 0.1) ## test near powers of 2 sizes %!test %! for s = [55 56 57 58] %! test_shapes (randi (255, 200, 200), randi (255, s, s), 0.1) %! endfor %!test %! for s = [203 204 205 206] %! test_shapes (randi (255, s, s), randi (255, 52, 52), 0.1) %! endfor ## test with other classes %!test test_shapes (randi (255, 100, 100, "uint8"), randi (255, 10, 10, "uint8"), 0.1) %!test test_shapes (randi (255, 100, 100, "uint8"), randi (255, 10, 10), 0.1) %!test test_shapes (randi (255, 100, 100, "single"), randi (255, 10, 10, "single"), 0.9) %!test test_shapes (randi (255, 100, 100, "single"), randi (255, 10, 10), 0.9) image-2.4.1/PaxHeaders.6632/DESCRIPTION0000644000000000000000000000013212561122761013766 xustar0030 mtime=1438950897.666252238 30 atime=1438950897.666252238 30 ctime=1438950899.342252237 image-2.4.1/DESCRIPTION0000644000175000017500000000075212561122761016615 0ustar00carandraugcarandraug00000000000000Name: image Version: 2.4.1 Date: 2015-08-07 Author: various authors Maintainer: Carnë Draug Title: Image Processing Description: The Octave-forge Image package provides functions for processing images. The package also provides functions for feature extraction, image statistics, spatial and geometric transformations, morphological operations, linear filtering, and much more. Depends: octave (>= 4.0.0) License: GPLv3+, MIT, FreeBSD Url: http://octave.sf.net image-2.4.1/PaxHeaders.6632/INDEX0000644000000000000000000000013212561122761013052 xustar0030 mtime=1438950897.666252238 30 atime=1438950897.666252238 30 ctime=1438950899.342252237 image-2.4.1/INDEX0000644000175000017500000000362212561122761015700 0ustar00carandraugcarandraug00000000000000image >> Image processing Analysis and Statistics corr2 edge fftconv2 fftconvn mean2 std2 entropy entropyfilt qtdecomp qtgetblk qtsetblk graycomatrix houghtf hough_line hough_circle imgradient imgradientxy imhist immaximas immse normxcorr2 psnr rangefilt regionprops stdfilt Arithmetics imabsdiff imadd imcomplement imdivide imlincomb immultiply imsubtract Black and white image functions applylut bwarea bwareafilt bwboundaries bwconncomp bwdist bweuler bwfill bwhitmiss bwlabel bwlabeln bwmorph bwperim bwpropfilt bwselect fchcode labelmatrix makelut Colour maps and Colour controls colorgradient rgb2ycbcr wavelength2rgb ycbcr2rgb Display montage subimage Enhancement and Restoration histeq imadjust imnoise imsmooth medfilt2 ordfilt2 ordfiltn stretchlim Filtering and Transforms findbounds fspecial imfilter imtransform intlut iradon nonmax_supress radon rho_filter Morhophological Operations bwareaopen conndef imbothat imclearborder imclose imdilate imerode imopen imreconstruct imregionalmax imregionalmin imtophat mmgradm @strel/getheight @strel/getneighbors @strel/getnhood @strel/getsequence @strel/isflat @strel/reflect @strel/strel @strel/translate Read/write analyze75info analyze75read analyze75write tiff_tag_read Region-based and block processing bestblk blockproc col2im colfilt im2col impixel nlfilter poly2mask roicolor Spatial transformations cp2tform imcrop imperspectivewarp imremap imresize imrotate imshear imtranslate maketform rotate_scale tformfwd tforminv Types and Type conversions grayslice graythresh im2bw im2double im2int16 im2single im2uint8 im2uint16 imcast imdither isbw isgray isind isrgb label2rgb mat2gray rgb2gray Utilities checkerboard edgetaper getrangefromclass imattributes iptcheckconn iptcheckmap iptnum2ordinal otf2psf padarray phantom psf2otf image-2.4.1/PaxHeaders.6632/COPYING0000644000000000000000000000013212561122761013313 xustar0030 mtime=1438950897.662252238 30 atime=1438950897.662252238 30 ctime=1438950899.342252237 image-2.4.1/COPYING0000644000175000017500000001741612561122761016147 0ustar00carandraugcarandraug00000000000000inst/private/analyze75filename.m GPLv3+ inst/private/handle_colorspec.m GPLv3+ inst/private/im2col_check.m GPLv3+ inst/private/imarithmetics.m GPLv3+ inst/private/interp_method.m GPLv3+ inst/private/is_double_image.m GPLv3+ inst/private/isimage.m GPLv3+ inst/private/ispart.m GPLv3+ inst/private/istform.m GPLv3+ inst/private/pad_for_sliding_filter.m GPLv3+ inst/private/prepare_strel.m GPLv3+ inst/private/ycbcrfunc.m GPLv3+ inst/@strel/display.m GPLv3+ inst/@strel/getheight.m GPLv3+ inst/@strel/getneighbors.m GPLv3+ inst/@strel/getnhood.m GPLv3+ inst/@strel/getsequence.m GPLv3+ inst/@strel/isflat.m GPLv3+ inst/@strel/isscalar.m GPLv3+ inst/@strel/numel.m GPLv3+ inst/@strel/reflect.m GPLv3+ inst/@strel/size.m GPLv3+ inst/@strel/strel.m GPLv3+ inst/@strel/subsref.m GPLv3+ inst/@strel/translate.m GPLv3+ inst/analyze75info.m GPLv3+ inst/analyze75read.m GPLv3+ inst/analyze75write.m GPLv3+ inst/applylut.m GPLv3+ inst/bestblk.m GPLv3+ inst/blockproc.m GPLv3+ inst/bwarea.m GPLv3+ inst/bwareafilt.m GPLv3+ inst/bwboundaries.m GPLv3+ inst/bwdist.m GPLv3+ inst/bweuler.m GPLv3+ inst/bwhitmiss.m GPLv3+ inst/bwmorph.m GPLv3+ inst/bwperim.m GPLv3+ inst/bwpropfilt.m GPLv3+ inst/bwselect.m GPLv3+ inst/col2im.m GPLv3+ inst/colfilt.m GPLv3+ inst/colorgradient.m public domain inst/corr2.m GPLv3+ inst/cp2tform.m GPLv3+ inst/edge.m GPLv3+ inst/edgetaper.m GPLv3+ inst/entropyfilt.m GPLv3+ inst/entropy.m GPLv3+ inst/fchcode.m GPLv3+ inst/findbounds.m GPLv3+ inst/fftconv2.m FreeBSD inst/fftconvn.m GPLv3+ inst/fspecial.m GPLv3+ inst/getrangefromclass.m GPLv3+ inst/grayslice.m GPLv3+ inst/graythresh.m GPLv3+ inst/histeq.m GPLv3+ inst/hough_circle.m GPLv3+ inst/houghtf.m GPLv3+ inst/im2bw.m GPLv3+ inst/im2col.m GPLv3+ inst/im2double.m GPLv3+ inst/im2int16.m GPLv3+ inst/im2single.m GPLv3+ inst/im2uint16.m GPLv3+ inst/im2uint8.m GPLv3+ inst/imabsdiff.m GPLv3+ inst/imadd.m GPLv3+ inst/imadjust.m GPLv3+ inst/imattributes GPLv3+ inst/imbothat.m GPLv3+ inst/imcast.m GPLv3+ inst/imclearborder.m GPLv3+ inst/imclose.m GPLv3+ inst/imcomplement.m GPLv3+ inst/imcrop.m GPLv3+ inst/imdither.m GPLv3+ inst/imdivide.m GPLv3+ inst/imfilter.m GPLv3+ inst/imgradient.m GPLv3+ inst/imgradientxy.m GPLv3+ inst/imhist.m GPLv3+ inst/imlincomb.m GPLv3+ inst/immaximas.m MIT inst/immse.m GPLv3+ inst/immultiply.m GPLv3+ inst/imnoise.m GPLv3+ inst/imopen.m GPLv3+ inst/imperspectivewarp.m GPLv3+ inst/impixel.m GPLv3+ inst/imregionalmax.m GPLv3+ inst/imregionalmin.m GPLv3+ inst/imremap.m GPLv3+ inst/imresize.m GPLv3+ inst/imrotate.m GPLv3+ inst/imshear.m GPLv3+ inst/imsmooth.m GPLv3+ inst/imsubtract.m GPLv3+ inst/imtophat.m GPLv3+ inst/imtransform.m GPLv3+ inst/imtranslate.m GPLv3+ inst/intlut.m GPLv3+ inst/iptcheckmap.m GPLv3+ inst/iptnum2ordinal.m GPLv3+ inst/iradon.m GPLv3+ inst/isbw.m GPLv3+ inst/isgray.m GPLv3+ inst/isind.m GPLv3+ inst/isrgb.m GPLv3+ inst/label2rgb.m GPLv3+ inst/labelmatrix.m GPLv3+ inst/makelut.m GPLv3+ inst/maketform.m GPLv3+ inst/mat2gray.m GPLv3+ inst/mean2.m GPLv3+ inst/medfilt2.m GPLv3+ inst/mmgradm.m GPLv3+ inst/montage.m GPLv3+ inst/nlfilter.m GPLv3+ inst/normxcorr2.m GPLv3+ inst/ordfilt2.m GPLv3+ inst/ordfiltn.m GPLv3+ inst/otf2psf.m GPLv3+ inst/padarray.m GPLv3+ inst/phantom.m GPLv3+ inst/psf2otf.m GPLv3+ inst/psnr.m GPLv3+ inst/poly2mask.m GPLv3+ inst/qtdecomp.m GPLv3+ inst/qtgetblk.m GPLv3+ inst/qtsetblk.m GPLv3+ inst/radon.m GPLv3+ inst/rangefilt.m GPLv3+ inst/regionprops.m GPLv3+ inst/rgb2gray.m GPLv3+ inst/rgb2ycbcr.m GPLv3+ inst/rho_filter.m GPLv3+ inst/roicolor.m GPLv3+ inst/std2.m GPLv3+ inst/stdfilt.m GPLv3+ inst/stretchlim.m GPLv3+ inst/subimage.m GPLv3+ inst/tiff_tag_read.m GPLv3+ inst/tformfwd.m GPLv3+ inst/tforminv.m GPLv3+ inst/wavelength2rgb.m GPLv3+ inst/ycbcr2rgb.m GPLv3+ src/__bilateral__.cc GPLv3+ src/__boundary__.cc GPLv3+ src/bwconncomp.cc GPLv3+ src/bwdist.cc GPLv3+ src/bwfill.cc GPLv3+ src/bwlabeln.cc GPLv3+ src/conndef.cc GPLv3+ src/connectivity.cc GPLv3+ src/connectivity.h GPLv3+ src/__custom_gaussian_smoothing__.cc GPLv3+ src/graycomatrix.cc FreeBSD src/hough_line.cc FreeBSD src/imerode.cc GPLv3+ src/imreconstruct.cc GPLv3+ src/nonmax_supress.cc GPLv3+ src/rotate_scale.cc GPLv3+ src/__spatial_filtering__.cc GPLv3+ src/strel.cc GPLv3+ src/strel.h GPLv3+ src/union-find.h++ GPLv3+ image-2.4.1/PaxHeaders.6632/bootstrap0000644000000000000000000000013212561122761014220 xustar0030 mtime=1438950897.666252238 30 atime=1438950897.802252238 30 ctime=1438950899.342252237 image-2.4.1/bootstrap0000755000175000017500000000036012561122761017045 0ustar00carandraugcarandraug00000000000000#!/bin/bash ## Octave-Forge: image package bootstrap script ## Run this to generate the configure script set -e # halt if unhandled error cd src/ aclocal -Im4 # get macros into aclocal.m4 autoconf # generate configure script image-2.4.1/PaxHeaders.6632/src0000644000000000000000000000013212561122763012774 xustar0030 mtime=1438950899.342252237 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/src/0000755000175000017500000000000012561122763015674 5ustar00carandraugcarandraug00000000000000image-2.4.1/src/PaxHeaders.6632/bwlabeln.cc0000644000000000000000000000013212561122761015144 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/bwlabeln.cc0000644000175000017500000006703012561122761017775 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2002 Jeffrey E. Boyd // Copyright (C) 2011-2012 Jordi Gutiérrez Hermoso // Copyright (C) 2013 Carnë Draug // // 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 3 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 // . // Copyright // Jeffrey E. Boyd and Carnë Draug for bwlabel_2d // Jordi Gutiérrez Hermoso for bwlabel_nd #include #include #include #include #include "union-find.h" #include "connectivity.h" using namespace octave::image; static union_find pre_label (NDArray& L, const connectivity& conn) { double* L_vec = L.fortran_vec (); const octave_idx_type numel = L.numel (); const Array neighbours = conn.negative_neighbourhood (L.dims ()); const octave_idx_type* nbr = neighbours.fortran_vec (); const octave_idx_type nbr_numel = neighbours.numel (); union_find u_f (numel); for (octave_idx_type Lidx = 0; Lidx < numel; Lidx++) { // The boundary is always zero, so we'll always skip it, so // we're never considering the neighbours of the boundary. Thus, // there is no possibility of out-of-bounds error below. if (L_vec[Lidx]) { //Insert this one into its group u_f.add (Lidx); for (octave_idx_type i = 0; i < nbr_numel; i++) { octave_idx_type n = *nbr++ + Lidx; if (L_vec[n]) u_f.unite (n, Lidx); } nbr -= nbr_numel; } } return u_f; } static octave_idx_type paint_labels (NDArray& L, union_find& u_f) { double* L_vec = L.fortran_vec (); std::unordered_map ids_to_label; octave_idx_type next_label = 1; std::vector idxs = u_f.get_ids (L); for (auto idx = idxs.begin (); idx != idxs.end (); idx++) { octave_idx_type label; octave_idx_type id = u_f.find (*idx); auto try_label = ids_to_label.find (id); if (try_label == ids_to_label.end ()) { label = next_label++; ids_to_label[id] = label; } else label = try_label->second; L_vec[*idx] = label; } return ids_to_label.size (); } static octave_value_list bwlabel_nd (const boolNDArray& BW, const connectivity& conn) { boolNDArray conn_mask = conn.mask; const dim_vector size_vec = BW.dims (); // Use temporary array with borders padded with zeros. Labels will // also go in here eventually. NDArray L = conn.create_padded (BW, 0); union_find u_f = pre_label (L, conn); octave_idx_type n_labels = paint_labels (L, u_f); // Remove the zero padding... conn.unpad (L); octave_value_list rval; rval(0) = L; rval(1) = n_labels; return rval; } static octave_idx_type find (std::vector& lset, octave_idx_type x) { // Follow lset until we find a value that points to itself while (lset[x] != x) x = lset[x]; return x; } static octave_value_list bwlabel_2d (const boolMatrix& BW, const octave_idx_type& n) { // This algorithm was derived from BKP Horn, Robot Vision, MIT Press, // 1986, p 65 - 89 by Jeffrey E. Boyd in 2002. Some smaller changes // were then introduced by Carnë Draug in 2013 to speed up by iterating // down a column, and what values to use when connecting two labels // to increase chance of getting them in the right order in the end. const octave_idx_type nr = BW.rows (); const octave_idx_type nc = BW.columns (); // The labelled image Matrix L (nr, nc); std::vector lset (nc*nr); // label table/tree octave_idx_type ntable = 0; // number of elements in the component table/tree octave_idx_type ind = 0; // linear index bool n4, n6, n8; n4 = n6 = n8 = false; if (n == 4) n4 = true; else if (n == 6) n6 = true; else if (n == 8) n8 = true; const bool* BW_vec = BW.data (); double* L_vec = L.fortran_vec (); for (octave_idx_type c = 0; c < nc; c++) { for (octave_idx_type r = 0; r < nr; r++, ind++) { if (BW_vec[ind]) // if A is an object { octave_idx_type stride = ind - nr; // Get the neighboring pixels B, C, D, and E // // D B // C A <-- ind is linear index to A // E // // C and B will always be needed so we get them here, but // D is only needed when n is 6 or 8, and E when n is 8. octave_idx_type B, C; if (c == 0) C = 0; else C = find (lset, L_vec[stride]); if (r == 0) B = 0; else B = find (lset, L_vec[ind -1]); if (n4) { // apply 4 connectedness if (B && C) // B and C are labeled { if (B != C) lset[B] = C; L_vec[ind] = C; } else if (B) // B is object but C is not L_vec[ind] = B; else if (C) // C is object but B is not L_vec[ind] = C; else // B, C not object - new object { // label and put into table ntable++; L_vec[ind] = lset[ntable] = ntable; } } else if (n6) { // Apply 6 connectedness. Seem there's more than one // possible way to do this for 2D images but for some // reason, the most common seems to be the top left pixel // and the bottom right // See http://en.wikipedia.org/wiki/Pixel_connectivity octave_idx_type D; // D is only required for n6 and n8 if (r == 0 || c == 0) D = 0; else D = find (lset, L_vec[stride -1]); if (D) // D object, copy label and move on L_vec[ind] = D; else if (B && C) // B and C are labeled { if (B == C) L_vec[ind] = B; else { octave_idx_type tlabel = std::min (B, C); lset[B] = tlabel; lset[C] = tlabel; L_vec[ind] = tlabel; } } else if (B) // B is object but C is not L_vec[ind] = B; else if (C) // C is object but B is not L_vec[ind] = C; else // B, C, D not object - new object { // label and put into table ntable++; L_vec[ind] = lset[ntable] = ntable; } } else if (n8) { octave_idx_type D, E; // D is only required for n6 and n8 if (r == 0 || c == 0) D = 0; else D = find (lset, L_vec[stride -1]); // E is only required for n8 if (c == 0 || r == nr -1) E = 0; else E = find (lset, L_vec[stride +1]); // apply 8 connectedness if (B || C || D || E) { octave_idx_type tlabel = D; if (D) ; // do nothing (tlabel is already D) else if (C) tlabel = C; else if (E) tlabel = E; else if (B) tlabel = B; L_vec[ind] = tlabel; if (B && B != tlabel) lset[B] = tlabel; if (C && C != tlabel) lset[C] = tlabel; if (D) // we don't check if B != tlabel since if B // is true, tlabel == B lset[D] = tlabel; if (E && E != tlabel) lset[E] = tlabel; } else { // label and put into table ntable++; // run image through the look-up table L_vec[ind] = lset[ntable] = ntable; } } } else L_vec[ind] = 0; // A is not an object so leave it } } const octave_idx_type numel = BW.numel (); // consolidate component table for (octave_idx_type i = 0; i <= ntable; i++) lset[i] = find (lset, i); // run image through the look-up table for (octave_idx_type ind = 0; ind < numel; ind++) L_vec[ind] = lset[L_vec[ind]]; // count up the objects in the image for (octave_idx_type i = 0; i <= ntable; i++) lset[i] = 0; for (octave_idx_type ind = 0; ind < numel; ind++) lset[L_vec[ind]]++; // number the objects from 1 through n objects octave_idx_type nobj = 0; lset[0] = 0; for (octave_idx_type i = 1; i <= ntable; i++) if (lset[i] > 0) lset[i] = ++nobj; // Run through the look-up table again, so that their numbers // match the number of labels for (octave_idx_type ind = 0; ind < numel; ind++) L_vec[ind] = lset[L_vec[ind]]; octave_value_list rval; rval(0) = L; rval(1) = double (nobj); return rval; } DEFUN_DLD(bwlabeln, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln (@var{bw})\n\ @deftypefnx {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln (@var{bw}, @var{n})\n\ Label foreground objects in the n-dimensional binary image @var{bw}.\n\ \n\ The optional argument @var{n} sets the connectivity and defaults 26,\n\ for 26-connectivity in 3-D images. Other possible values are 18 and 6\n\ for 3-D images, 4 and 8 for 2-D images, or an arbitrary N-dimensional\n\ binary connectivity mask where each dimension is of size 3.\n\ \n\ The output @var{l} is an Nd-array where 0 indicates a background\n\ pixel, 1 indicates that the pixel belong to object number 1, 2 that\n\ the pixel belong to object number 2, etc. The total number of objects\n\ is @var{num}.\n\ \n\ The algorithm used is a disjoint-set data structure, a.k.a. union-find.\n\ See, for example, http://en.wikipedia.org/wiki/Union-find\n\ \n\ @seealso{bwconncomp, bwlabel, regionprops}\n\ @end deftypefn\n\ ") { octave_value_list rval; const octave_idx_type nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return rval; } if (!args(0).is_numeric_type () && !args(0).is_bool_type ()) { error ("bwlabeln: BW must be a numeric or logical matrix"); return rval; } boolNDArray BW = args(0).bool_array_value (); dim_vector size_vec = BW.dims (); connectivity conn; try { conn = (nargin == 2) ? connectivity (args(1)) : connectivity (BW.ndims (), "maximal"); } catch (invalid_connectivity& e) { error ("bwlabeln: MASK %s", e.what ()); return octave_value (); } // The implementation in bwlabel_2d is faster so use it if we can const octave_idx_type ndims = BW.ndims (); if (ndims == 2 && boolMatrix (conn.mask) == connectivity (4).mask) rval = bwlabel_2d (BW, 4); else if (ndims == 2 && boolMatrix (conn.mask) == connectivity (8).mask) rval = bwlabel_2d (BW, 8); else rval = bwlabel_nd (BW, conn); return rval; } /* %!shared a2d, a3d %! a2d = [1 0 0 0 0 0 1 0 0 1 %! 1 0 0 1 0 1 0 1 0 1 %! 1 0 1 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 1 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 1 0 0 %! 1 1 0 0 0 0 1 0 1 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 1 1 0 0 1]; %! %! a3d = a2d; %! a3d(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 1 1 0 0 0 0 %! 1 1 0 1 0 0 0 0 0 0 %! 1 0 0 0 0 0 1 0 0 0 %! 0 1 0 0 0 0 0 0 0 1 %! 1 1 0 0 0 0 1 0 0 0]; %! %! a3d(:,:,3) = [ %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 1 1 0 0 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 0 1 %! 1 1 0 0 0 0 0 0 0 0]; %!test %! label2dc4 = [ %! 1 0 0 0 0 0 8 0 0 13 %! 1 0 0 4 0 6 0 10 0 13 %! 1 0 3 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 5 5 5 0 0 0 0 %! 2 2 0 5 0 0 0 11 0 0 %! 2 2 0 0 0 0 9 0 12 0 %! 2 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 7 7 0 0 14]; %! assert (bwlabeln (a2d, 4), label2dc4) %! assert (bwlabeln (a2d, [0 1 0; 1 1 1; 0 1 0]), label2dc4) %! assert (bwlabeln (a2d, conndef (2, "minimal")), label2dc4) %! assert (bwlabeln (a2d, conndef (3, "minimal")), label2dc4) %!test %! label2dc8 = [ %! 1 0 0 0 0 0 5 0 0 8 %! 1 0 0 3 0 5 0 5 0 8 %! 1 0 3 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 4 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 7 0 0 %! 2 2 0 0 0 0 7 0 7 0 %! 2 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 6 6 0 0 9]; %! assert (bwlabeln (a2d, 8), label2dc8) %! assert (bwlabeln (a2d, ones (3)), label2dc8) %! assert (bwlabeln (a2d, conndef (2, "maximal")), label2dc8) %! assert (bwlabeln (a2d, conndef (3, "maximal")), label2dc8) %!test %! label3dc8 = [ %! 1 0 0 0 0 0 5 0 0 8 %! 1 0 0 3 0 5 0 5 0 8 %! 1 0 3 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 4 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 7 0 0 %! 2 2 0 0 0 0 7 0 7 0 %! 2 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 6 6 0 0 9]; %! label3dc8(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 10 0 0 12 12 0 0 16 0 0 %! 0 0 0 12 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 11 0 0 0 0 0 0 0 0 %! 11 11 0 0 13 13 0 0 0 0 %! 11 11 0 13 0 0 0 0 0 0 %! 11 0 0 0 0 0 14 0 0 0 %! 0 11 0 0 0 0 0 0 0 17 %! 11 11 0 0 0 0 15 0 0 0]; %! label3dc8(:,:,3) = [ %! 18 0 0 0 0 0 0 0 0 0 %! 0 18 0 20 20 0 0 22 0 0 %! 0 0 0 20 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 21 21 21 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 19 0 0 0 0 0 0 0 0 0 %! 19 19 0 0 0 0 0 0 0 23 %! 19 19 0 0 0 0 0 0 0 0]; %! assert (bwlabeln (a3d, 8), label3dc8) %! assert (bwlabeln (a3d, ones (3, 3)), label3dc8) %! assert (bwlabeln (a3d, conndef (2, "maximal")), label3dc8) %!test %! label3dc26 = [ %! 1 0 0 0 0 0 3 0 0 7 %! 1 0 0 3 0 3 0 3 0 7 %! 1 0 3 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 4 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 6 0 0 %! 2 2 0 0 0 0 6 0 6 0 %! 2 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 5 5 0 0 6]; %! label3dc26(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 3 3 0 0 3 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 0 0 0 %! 2 0 0 0 0 0 6 0 0 0 %! 0 2 0 0 0 0 0 0 0 6 %! 2 2 0 0 0 0 5 0 0 0]; %! label3dc26(:,:,3) = [ %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 3 3 0 0 3 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 4 4 4 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 2 0 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 0 0 0 0 6 %! 2 2 0 0 0 0 0 0 0 0]; %! assert (bwlabeln (a3d, 26), label3dc26) %! assert (bwlabeln (a3d, ones (3, 3, 3)), label3dc26) %! assert (bwlabeln (a3d, conndef (3, "maximal")), label3dc26) %!test %! label3dc18 = [ %! 1 0 0 0 0 0 3 0 0 7 %! 1 0 0 3 0 3 0 3 0 7 %! 1 0 3 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 4 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 6 0 0 %! 2 2 0 0 0 0 6 0 6 0 %! 2 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 5 5 0 0 8]; %! label3dc18(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 3 3 0 0 3 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 2 0 0 0 0 0 0 0 0 %! 2 2 0 0 4 4 0 0 0 0 %! 2 2 0 4 0 0 0 0 0 0 %! 2 0 0 0 0 0 6 0 0 0 %! 0 2 0 0 0 0 0 0 0 8 %! 2 2 0 0 0 0 5 0 0 0]; %! label3dc18(:,:,3) = [ %! 1 0 0 0 0 0 0 0 0 0 %! 0 1 0 3 3 0 0 3 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 4 4 4 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 2 0 0 0 0 0 0 0 0 0 %! 2 2 0 0 0 0 0 0 0 8 %! 2 2 0 0 0 0 0 0 0 0]; %! assert (bwlabeln (a3d, 18), label3dc18) %!test %! label2dc3 = [ %! 1 0 0 0 0 0 11 0 0 17 %! 1 0 0 5 0 8 0 14 0 17 %! 1 0 4 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 3 0 0 0 0 0 0 0 0 %! 2 3 0 6 7 9 0 0 0 0 %! 2 3 0 6 0 0 0 15 0 0 %! 2 3 0 0 0 0 12 0 16 0 %! 2 3 0 0 0 0 0 0 0 0 %! 2 3 0 0 0 10 13 0 0 18]; %! assert (bwlabeln (a2d, [1 1 1]'), label2dc3) %! %! label3dc3 = label2dc3; %! label3dc3(:,:,2) = [ %! 0 0 0 0 0 0 0 0 0 0 %! 19 0 0 24 26 0 0 31 0 0 %! 0 0 0 24 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 22 0 0 0 0 0 0 0 0 %! 20 22 0 0 27 28 0 0 0 0 %! 20 22 0 25 0 0 0 0 0 0 %! 20 0 0 0 0 0 29 0 0 0 %! 0 23 0 0 0 0 0 0 0 32 %! 21 23 0 0 0 0 30 0 0 0]; %! label3dc3(:,:,3) = [ %! 33 0 0 0 0 0 0 0 0 0 %! 0 35 0 37 39 0 0 42 0 0 %! 0 0 0 37 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 38 40 41 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 34 0 0 0 0 0 0 0 0 0 %! 34 36 0 0 0 0 0 0 0 43 %! 34 36 0 0 0 0 0 0 0 0]; %! assert (bwlabeln (a3d, [1 1 1]'), label3dc3) %!test %! label2dc1 = zeros (size (a2d)); %! label2dc1(a2d != 0) = 1:nnz (a2d); %! assert (bwlabeln (a2d, [1]), label2dc1); %! assert (bwlabeln (a2d, [0 1 0]'), label2dc1); %! %! label3dc1 = zeros (size (a3d)); %! label3dc1(a3d != 0) = 1:nnz (a3d); %! assert (bwlabeln (a3d, [1]), label3dc1); %! assert (bwlabeln (a3d, [0 1 0]'), label3dc1); */ // PKG_ADD: autoload ("bwlabel", which ("bwlabeln")); // PKG_DEL: autoload ("bwlabel", which ("bwlabeln"), "remove"); DEFUN_DLD(bwlabel, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{l}, @var{num}] =} bwlabel(@var{BW})\n\ @deftypefnx {Loadable Function} {[@var{l}, @var{num}] =} bwlabel(@var{BW}, @var{n})\n\ Label binary 2 dimensional image.\n\ \n\ Labels foreground objects in the binary image @var{bw}.\n\ The output @var{l} is a matrix where 0 indicates a background pixel,\n\ 1 indicates that the pixel belong to object number 1, 2 that the pixel\n\ belong to object number 2, etc.\n\ The total number of objects is @var{num}.\n\ \n\ To pixels belong to the same object if the are neighbors. By default\n\ the algorithm uses 8-connectivity to define a neighborhood, but this\n\ can be changed through the argument @var{n} that can be either 4, 6, or 8.\n\ \n\ @seealso{bwconncomp, bwlabeln, regionprops}\n\ @end deftypefn\n\ ") { octave_value_list rval; const octave_idx_type nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return rval; } // We do not check error state after conversion to boolMatrix // because what we want is to actually get a boolean matrix // with all non-zero elements as true (Matlab compatibility). if ((! args(0).is_numeric_type () && ! args(0).is_bool_type ()) || args(0).ndims () != 2) { error ("bwlabel: BW must be a 2D matrix"); return rval; } // For some reason, we can't use bool_matrix_value() to get a // a boolMatrix since it will error if there's values other // than 0 and 1 (whatever bool_array_value() does, bool_matrix_value() // does not). const boolMatrix BW = args(0).bool_array_value (); // N-hood connectivity const octave_idx_type n = nargin < 2 ? 8 : args(1).idx_type_value (); if (error_state || (n != 4 && n!= 6 && n != 8)) { error ("bwlabel: BW must be a 2 dimensional matrix"); return rval; } return bwlabel_2d (BW, n); } /* %!shared in %! in = rand (10) > 0.8; %!assert (bwlabel (in, 4), bwlabeln (in, 4)); %!assert (bwlabel (in, 4), bwlabeln (in, [0 1 0; 1 1 1; 0 1 0])); %!assert (bwlabel (in, 8), bwlabeln (in, 8)); %!assert (bwlabel (in, 8), bwlabeln (in, [1 1 1; 1 1 1; 1 1 1])); %!assert (bwlabel (logical ([0 1 0; 0 0 0; 1 0 1])), [0 2 0; 0 0 0; 1 0 3]); %!assert (bwlabel ([0 1 0; 0 0 0; 1 0 1]), [0 2 0; 0 0 0; 1 0 3]); ## Support any type of real non-zero value %!assert (bwlabel ([0 -1 0; 0 0 0; 5 0 0.2]), [0 2 0; 0 0 0; 1 0 3]); %!shared in, out %! %! in = [ 0 1 1 0 0 1 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 1 %! 0 1 1 0 0 0 0 0 1 1 %! 1 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 0 1 0 0 %! 0 0 0 1 0 1 0 1 0 1 %! 1 1 0 0 0 0 0 1 1 0]; %! %! out = [ 0 3 3 0 0 9 0 0 0 0 %! 0 0 0 5 0 0 0 0 0 13 %! 0 4 4 0 0 0 0 0 13 13 %! 1 0 0 0 0 0 0 11 0 0 %! 0 0 0 0 0 10 10 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 6 0 0 0 0 0 0 %! 0 0 0 0 8 8 0 12 0 0 %! 0 0 0 7 0 8 0 12 0 14 %! 2 2 0 0 0 0 0 12 12 0]; %!assert (nthargout ([1 2], @bwlabel, in, 4), {out, 14}); %!assert (nthargout ([1 2], @bwlabel, logical (in), 4), {out, 14}); %! %! out = [ 0 3 3 0 0 7 0 0 0 0 %! 0 0 0 3 0 0 0 0 0 11 %! 0 4 4 0 0 0 0 0 11 11 %! 1 0 0 0 0 0 0 9 0 0 %! 0 0 0 0 0 8 8 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 5 0 0 0 0 0 0 %! 0 0 0 0 5 5 0 10 0 0 %! 0 0 0 6 0 5 0 10 0 12 %! 2 2 0 0 0 0 0 10 10 0]; %!assert (nthargout ([1 2], @bwlabel, in, 6), {out, 12}); %!assert (nthargout ([1 2], @bwlabel, logical (in), 6), {out, 12}); %! %! ## The labeled image is not the same as Matlab, but they are %! ## labeled correctly. Do we really need to get them properly %! ## ordered? (the algorithm in bwlabeln does it) %! mout = [0 1 1 0 0 4 0 0 0 0 %! 0 0 0 1 0 0 0 0 0 5 %! 0 1 1 0 0 0 0 0 5 5 %! 1 0 0 0 0 0 0 5 0 0 %! 0 0 0 0 0 5 5 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 3 3 0 6 0 0 %! 0 0 0 3 0 3 0 6 0 6 %! 2 2 0 0 0 0 0 6 6 0]; %! %! out = [ 0 2 2 0 0 4 0 0 0 0 %! 0 0 0 2 0 0 0 0 0 5 %! 0 2 2 0 0 0 0 0 5 5 %! 2 0 0 0 0 0 0 5 0 0 %! 0 0 0 0 0 5 5 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 3 0 0 0 0 0 0 %! 0 0 0 0 3 3 0 6 0 0 %! 0 0 0 3 0 3 0 6 0 6 %! 1 1 0 0 0 0 0 6 6 0]; %!assert (nthargout ([1 2], @bwlabel, in, 8), {out, 6}); %!assert (nthargout ([1 2], @bwlabel, logical (in), 8), {out, 6}); %! %!error bwlabel (rand (10, 10, 10) > 0.8, 4) %!error bwlabel (rand (10) > 0.8, "text") %!error bwlabel ("text", 6) */ image-2.4.1/src/PaxHeaders.6632/graycomatrix.cc0000644000000000000000000000013212561122761016067 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/graycomatrix.cc0000644000175000017500000001207512561122761020717 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2004 Stefan van der Walt // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1 Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2 Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include DEFUN_DLD(graycomatrix, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{P} =} graycomatrix(@var{im}, @var{levels}, @var{distances}, @var{angles})\n\ Calculates the gray-level co-occurrence matrix @var{P} of a gray-level image @var{im}.\n\ \n\ @var{P} is a 4-dimensional matrix (histogram). The value @var{P}(@var{i},@var{j},@var{d},@var{theta})\n\ is the number of times that gray-level @var{j} occurs at a distance @var{d} and\n\ at an angle @var{theta} from gray-level @var{i}.\n\ \n\ @var{im} is the input image which should contain integers in [0, @var{levels}-1],\n\ where @var{levels} indicate the number of gray-levels counted (typically\n\ 256 for an 8-bit image). @var{distances} and @var{angles} are vectors of\n\ the different distances and angles to use.\n\ @end deftypefn\n\ " ) { // 4-dimensional histogram // P = f(i, j, d, theta) where i and j are gray levels // See Pattern Recognition Engineering (Morton Nadler & Eric P. Smith) octave_value_list retval; if (args.length() != 4) { print_usage (); // 'I' must be integer values [0, nr_of_levels-1] return retval; } // Input arguments Matrix I = args(0).matrix_value(); int L = args(1).int_value(); ColumnVector d = ColumnVector(args(2).vector_value()); ColumnVector th = ColumnVector(args(3).vector_value()); if (error_state) { print_usage (); return retval; } // Create output NDArray, P dim_vector dim = dim_vector(); dim.resize(4); dim(0) = L; dim(1) = L; dim(2) = d.length(); dim(3) = th.length(); NDArray P = NDArray(dim, 0); // Run through image //int d_max = (int)ceil(d.max()); //unused //int cnt = 0; //unused for (int r = 0; r < I.rows(); r++) { for (int c = 0; c < I.columns(); c++) { OCTAVE_QUIT; int i = (int)I(r,c); for (int d_idx = 0; d_idx < d.length(); d_idx++) { int d_val = (int)d(d_idx); for (int th_idx = 0; th_idx < th.length(); th_idx++) { double angle = th(th_idx); int row = r + (int)floor(cos(angle) * d_val + 0.5); int col = c - (int)floor(sin(angle) * d_val + 0.5); if ( ( row >= 0 ) && ( row < I.rows() ) && ( col >= 0 ) && ( col < I.cols() ) ) { int j = (int)I(row, col); if (i >= 0 && i < L && j >= 0 && j < L) { Array coord (dim_vector (4, 1), 0); coord (0, 0) = i; coord (1, 0) = j; coord (2, 0) = d_idx; coord (3, 0) = th_idx; P(coord)++; } else { warning("Image contains invalid gray-level! (%d, %d)", i, j); } } } } } } return octave_value(P); } /* %!shared a %!test %! a = [0 0 0 1 2; %! 1 1 0 1 1; %! 2 2 1 0 0; %! 1 1 0 2 0; %! 0 0 1 0 1]; %! squeeze(graycomatrix(a, 3, 1, -pi/4)) == [4 2 0; %! 2 3 2; %! 1 2 0]; %! %!assert(size(graycomatrix(a, 3, 1:5, [0:3]*-pi/4)), [3, 3, 5, 4]) %!demo %! %! # Pattern Recognition Engineering (Nadler & Smith) %! # Digital Image Processing (Gonzales & Woods), p. 668 %! %! a = [0 0 0 1 2; %! 1 1 0 1 1; %! 2 2 1 0 0; %! 1 1 0 2 0; %! 0 0 1 0 1]; %! %! graycomatrix(a, 3, 1, [0 1]*-pi/4) %! */ image-2.4.1/src/PaxHeaders.6632/configure.ac0000644000000000000000000000013212561122761015335 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.990252238 30 ctime=1438950899.342252237 image-2.4.1/src/configure.ac0000644000175000017500000000206612561122761020164 0ustar00carandraugcarandraug00000000000000AC_PREREQ([2.67]) AC_INIT([Octave-Forge image package], [2.4.1]) AC_PROG_CXX AC_LANG(C++) AX_CXX_COMPILE_STDCXX_11() ## Test for gcc bug #65843 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65843 ## which shows up as Octave bug #45096 https://savannah.gnu.org/bugs/?45096 AC_CACHE_CHECK([whether templated lambda functions accept '&const int'], [_cv_template_lambda_accepts_ref_const_inst], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ template void test (T b) { const int a = b; [&] () { return a, a; }(); } ]], [[ test (1); ]])], [_cv_template_lambda_accepts_ref_const_inst=yes], [_cv_template_lambda_accepts_ref_const_inst=no]) ]) if test $_cv_template_lambda_accepts_ref_const_inst = no; then AC_MSG_ERROR([ Your C++ compiler (are you using GCC 5.0 or 5.1?) has a bug that prevents it from building the Octave Forge image package. But you can fix it very easily. See https://savannah.gnu.org/bugs/?45096 for details on working around it. ]) fi AC_CONFIG_FILES([Makefile]) AC_OUTPUT image-2.4.1/src/PaxHeaders.6632/bwconncomp.cc0000644000000000000000000000013212561122761015523 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/bwconncomp.cc0000644000175000017500000003362712561122761020361 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2014 Carnë Draug // // 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 3 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 // . // Implements connected components but using flood-fill algorithm instead // of union find (like bwlabeln) so it uses a lot less memory. // TODO: functions that could be here // * bwareafilt // * imfill / bwfill // * bwselect // * labelmatrix #include #include #include #include #include "connectivity.h" using namespace octave::image; static std::vector> connected_components (const boolNDArray& BW, const connectivity& conn) { boolNDArray BW_pad = conn.create_padded (BW, false); bool* BW_vec = BW_pad.fortran_vec (); const Array offsets = conn.deleted_neighbourhood (BW_pad.dims ()); const octave_idx_type n_offsets = offsets.numel (); const octave_idx_type* off_v = offsets.fortran_vec (); std::vector> all_components; const octave_idx_type numel = BW_pad.numel (); for (octave_idx_type i = 0; i < numel; BW_vec++, i++) { if (! *BW_vec) continue; // We want a queue but we will mimic one with a vector because in the // end all elements that go in the queue go in the vector anyway. std::vector conn_comp {0}; *BW_vec = false; std::vector::size_type front = 0; while (front < conn_comp.size ()) { octave_idx_type base_offset = conn_comp[front++]; for (octave_idx_type j = 0; j < n_offsets; j++) { const octave_idx_type this_offset = base_offset + off_v[j]; if (BW_vec[this_offset]) { BW_vec[this_offset] = false; conn_comp.push_back (this_offset); } } } for (octave_idx_type& offset : conn_comp) offset += i; all_components.push_back (conn_comp); } // The collected indices are for the padded image so they need fixing const dim_vector original_size = BW.dims (); const dim_vector padded_size = BW_pad.dims (); const octave_idx_type* o = original_size.to_jit (); const octave_idx_type* p = padded_size.to_jit (); const octave_idx_type ndims_m1 = BW_pad.ndims () -1; std::vector dim_padded (BW_pad.ndims (), true); for (octave_idx_type i = 0; i < BW_pad.ndims (); i++) if (p[i] == o[i]) dim_padded[i] = false; for (std::vector& conn_comp : all_components) { for (octave_idx_type& offset : conn_comp) { octave_idx_type mult = 1; octave_idx_type ind = 0; for (octave_idx_type d = 0; d < ndims_m1; d++) { if (dim_padded[d]) { ind += mult * (offset % p[d] - 1); mult *= p[d] - 2; offset /= p[d]; } else { ind += mult * (offset % p[d]); mult *= p[d]; offset /= p[d]; } } if (dim_padded[ndims_m1]) ind += mult * (offset % p[ndims_m1] - 1); else ind += mult * (offset % p[ndims_m1]); offset = ind; } } return all_components; } static Array dim_vector_2_array (const dim_vector& dims) { RowVector size (dim_vector (1, dims.length ())); for (octave_idx_type i = 0; i < dims.length (); i++) size(i) = dims(i); return size; } // We should just return the connectivity used as input, args(1), but for // Matlab compatibility, we must return 4, 8, etc if it matches static octave_value conn_to_octave_value (const connectivity& conn) { const octave_idx_type n = conn.mask.numel (); const octave_idx_type nnz = conn.mask.nnz (); const bool* b_v = conn.mask.fortran_vec (); octave_idx_type nr; if ((n == 9 || n == 27) && n == nnz) nr = nnz -1; else if (nnz == 5 && b_v[1] && b_v[3] && b_v[4] && b_v[5] && b_v[7]) nr = 4; else if (nnz == 7 && b_v[4] && b_v[10] && b_v[12] && b_v[13] && b_v[14] && b_v[16] && b_v[22]) nr = 6; else if (nnz == 19 && ! b_v[0] && ! b_v[2] && ! b_v[6] && ! b_v[8] && ! b_v[18] && ! b_v[20] && ! b_v[24] && ! b_v[26]) nr = 18; else return octave_value (conn.mask); return octave_value (nr); } DEFUN_DLD(bwconncomp, args, , "\ -*- texinfo -*-\n\ @deftypefn {Function File} {@var{cc} =} bwconncomp (@var{bw})\n\ @deftypefnx {Function File} {@var{cc} =} bwconncomp (@var{bw}, @var{conn})\n\ Find connected objects.\n\ \n\ Elements from the matrix @var{bw}, belong to an object if they have a\n\ non-zero value. The output @var{cc} is a structure with information about\n\ each object;\n\ \n\ @table @asis\n\ @item @qcode{\"Connectivity\"}\n\ The connectivity used in the boundary tracing. This may be different from\n\ the input argument, e.g., if @var{conn} is defined as a matrix of 1s and\n\ size 3x3, the @qcode{\"Connectivity\"} value will still be 8.\n\ \n\ @item @qcode{\"ImageSize\"}\n\ The size of the matrix @var{bw}.\n\ \n\ @item @qcode{\"NumObjects\"}\n\ The number of objects in the image @var{bw}.\n\ \n\ @item @qcode{\"PixelIdxList\"}\n\ A cell array with linear indices for each element of each object in @var{bw}\n\ A cell array containing where each element corresponds to an object in @var{BW}.\n\ Each element is represented as a vector of linear indices of the boundary of\n\ the given object.\n\ \n\ @end table\n\ \n\ Element connectivity @var{conn}, to define the size of objects, can be\n\ specified with a numeric scalar (number of elements in the neighborhood):\n\ \n\ @table @samp\n\ @item 4 or 8\n\ for 2 dimensional matrices;\n\ @item 6, 18 or 26\n\ for 3 dimensional matrices;\n\ @end table\n\ \n\ or with a binary matrix representing a connectivity array. Defaults to\n\ @code{conndef (ndims (@var{bw}), \"maximal\")} which is equivalent to\n\ @var{conn} of 8 and 26 for 2 and 3 dimensional matrices respectively.\n\ \n\ @seealso{bwlabel, bwlabeln, bwboundaries, ind2sub, regionprops}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return octave_value_list (); } const boolNDArray BW = args(0).bool_array_value (); if (error_state) { error ("bwconncomp: BW must be a numeric or logical matrix"); return octave_value_list (); } connectivity conn; try { conn = (nargin > 1) ? connectivity (args(1)) : connectivity (BW.ndims (), "maximal"); } catch (invalid_connectivity& e) { error ("bwconncomp: MASK %s", e.what ()); return octave_value_list (); } const std::vector> all_cc = connected_components (BW, conn); static const char *fields[] = { "Connectivity", "ImageSize", "NumObjects", "PixelIdxList", 0 }; octave_scalar_map cc = octave_scalar_map (string_vector (fields)); cc.assign ("Connectivity", conn_to_octave_value (conn)); cc.assign ("NumObjects", octave_value (all_cc.size ())); cc.assign ("ImageSize", octave_value (dim_vector_2_array (BW.dims ()))); Cell idx_cell (dim_vector (1, all_cc.size ()), ColumnVector ()); octave_idx_type i_out = 0; for (auto it = all_cc.begin (); it != all_cc.end (); it++, i_out++) { ColumnVector idx (dim_vector (it->size (), 1)); double* idx_v = idx.fortran_vec (); octave_idx_type i_in = 0; for (auto it_it = it->begin (); it_it != it->end (); it_it++, i_in++) idx_v[i_in] = *it_it +1; // +1 (we fix it for Octave indexing) idx_cell(i_out) = idx; } cc.setfield ("PixelIdxList", idx_cell); return octave_value (cc); } /* %!test %! a = rand (10) > 0.5; %! cc = bwconncomp (a, 4); %! assert (cc.Connectivity, 4) %! assert (cc.ImageSize, [10 10]) %! %! b = false (10); %! for i = 1:numel (cc.PixelIdxList) %! b(cc.PixelIdxList{i}) = true; %! endfor %! assert (a, b) %!test %! a = rand (10, 13) > 0.5; %! cc = bwconncomp (a, 4); %! assert (cc.ImageSize, [10 13]) %! %! b = false (10, 13); %! for i = 1:numel (cc.PixelIdxList) %! b(cc.PixelIdxList{i}) = true; %! endfor %! assert (a, b) %!test %! a = rand (15) > 0.5; %! conn_8 = bwconncomp (a, 8); %! assert (conn_8, bwconncomp (a)) %! assert (conn_8, bwconncomp (a, ones (3))) %! assert (conn_8.Connectivity, 8) %! assert (bwconncomp (a, ones (3)).Connectivity, 8) %! assert (bwconncomp (a, [0 1 0; 1 1 1; 0 1 0]).Connectivity, 4) ## test that PixelIdxList is a row vector %!test %! a = rand (40, 40) > 0.2; %! cc = bwconncomp (a, 4); %! assert (rows (cc.PixelIdxList), 1) %! assert (columns (cc.PixelIdxList) > 1) */ // PKG_ADD: autoload ("bwareaopen", which ("bwconncomp")); // PKG_DEL: autoload ("bwareaopen", which ("bwconncomp"), "remove"); DEFUN_DLD(bwareaopen, args, , "\ -*- texinfo -*-\n\ @deftypefn {Function File} {} bwareaopen (@var{bw}, @var{lim})\n\ @deftypefnx {Function File} {} bwareaopen (@var{bw}, @var{lim}, @var{conn})\n\ Perform area opening.\n\ \n\ Remove objects with less than @var{lim} elements from a binary image\n\ @var{bw}.\n\ \n\ Element connectivity @var{conn}, to define the size of objects, can be\n\ specified with a numeric scalar (number of elements in the neighborhood):\n\ \n\ @table @samp\n\ @item 4 or 8\n\ for 2 dimensional matrices;\n\ @item 6, 18 or 26\n\ for 3 dimensional matrices;\n\ @end table\n\ \n\ or with a binary matrix representing a connectivity array. Defaults to\n\ @code{conndef (ndims (@var{bw}), \"maximal\")} which is equivalent to\n\ @var{conn} of 8 and 26 for 2 and 3 dimensional matrices respectively.\n\ \n\ @seealso{bwconncomp, conndef, bwboundaries}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 2 || nargin > 3) { print_usage (); return octave_value_list (); } boolNDArray BW = args(0).bool_array_value (); if (error_state) { error ("bwareaopen: BW must be a numeric or logical matrix"); return octave_value_list (); } const std::vector::size_type lim = args(1).idx_type_value (); if (error_state || lim < 0) { error ("bwareaopen: LIM must be a non-negative scalar integer"); return octave_value_list (); } connectivity conn; try { conn = (nargin > 2) ? connectivity (args(2)) : connectivity (BW.ndims (), "maximal"); } catch (invalid_connectivity& e) { error ("bwareaopen: MASK %s", e.what ()); return octave_value_list (); } const std::vector> all_cc = connected_components (BW, conn); bool* BW_v = BW.fortran_vec (); for (std::vector cc : all_cc) { if (cc.size () < lim) for (octave_idx_type ind : cc) BW_v[ind] = false; } return octave_value (BW); } /* %!test %! in = [ 0 0 1 0 0 1 0 1 0 0 %! 0 0 1 0 0 0 0 0 1 1 %! 1 0 0 0 0 1 1 0 0 0 %! 1 0 0 0 1 0 0 0 0 0 %! 1 1 1 1 0 0 0 0 0 1 %! 0 1 0 1 1 0 0 1 0 0 %! 1 0 0 0 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 1 0 0 %! 0 1 0 1 1 0 0 1 1 0 %! 0 1 0 1 1 1 0 0 1 0]; %! assert (bwareaopen (in, 1, 4), logical (in)) %! %! out = [0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 1 1 0 0 0 0 0 0 %! 0 1 0 1 1 0 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! assert (bwareaopen (logical (in), 10, 4), logical (out)) %! assert (bwareaopen (in, 10, 4), logical (out)) %! assert (bwareaopen (in, 10, [0 1 0; 1 1 1; 0 1 0]), logical (out)) %! %! out = [0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 1 1 0 0 0 %! 1 0 0 0 1 0 0 0 0 0 %! 1 1 1 1 0 0 0 0 0 0 %! 0 1 0 1 1 0 0 0 0 0 %! 1 0 0 0 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 1 1 1 0 0 0 0]; %! assert (bwareaopen (in, 10, 8), logical (out)) %! assert (bwareaopen (in, 10, ones (3)), logical (out)) %! assert (bwareaopen (in, 10), logical (out)) %! %! out = [0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 1 1 1 1 0 0 0 0 0 0 %! 0 1 0 1 1 0 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 0 %! 0 0 0 1 1 0 0 1 0 0 %! 0 0 0 1 1 0 0 1 1 0 %! 0 0 0 1 1 1 0 0 1 0]; %! assert (bwareaopen (in, 4, [1 1 0; 1 1 1; 0 1 1]), logical (out)) %!error bwareaopen ("not an image", 78, 8) %!error bwareaopen (rand (10) > 0.5, 10, 100) %!error bwareaopen (rand (10) > 0.5, 10, "maximal") %!error bwareaopen (rand (10) > 0.5, 10, [1 1 1; 0 1 1; 0 1 0]) */ image-2.4.1/src/PaxHeaders.6632/bwdist.cc0000644000000000000000000000013212561122761014652 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/bwdist.cc0000644000175000017500000005472412561122761017511 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2009 Stefan Gustavson // Copyright (C) 2013 Carnë Draug // // 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 3 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 . #include /* edtfunc - Euclidean distance transform of a binary image This is a sweep-and-update Euclidean distance transform of a binary image. All positive pixels are considered object pixels, zero or negative pixels are treated as background. By Stefan Gustavson (stefan.gustavson@gmail.com). Originally written in 1994, based on paper-only descriptions of the SSED8 algorithm, invented by Per-Erik Danielsson and improved by Ingemar Ragnemalm. This is a classic algorithm with roots in the 1980s, still very good for the 2D case. Updated in 2004 to treat pixels at image edges correctly, and to improve code readability. Edited in 2009 to form the foundation for Octave BWDIST: added #define-configurable distance measure and function name Edited in 2013 for C++, removed the #define stuff, and other fixes for matlab compatibility. */ void edtfunc (float (*func)(short int, short int), const boolNDArray &img, short *distx, short *disty) { const int w = img.cols (); const int h = img.rows (); const int numel = img.numel (); // Initialize the distance images to be all large values const bool* elem = img.fortran_vec (); for (octave_idx_type i = 0; i < numel; i++) { if(elem[i]) { distx[i] = 0; disty[i] = 0; } else { distx[i] = 32000; // Large but still representable in a short, and disty[i] = 32000; // 32000^2 + 32000^2 does not overflow an int } } double olddist2, newdist2, newdistx, newdisty; bool changed; // Initialize index offsets for the current image width const int offset_u = -h; const int offset_ur = -h+1; const int offset_r = 1; const int offset_rd = h+1; const int offset_d = h; const int offset_dl = h-1; const int offset_l = -1; const int offset_lu = -h-1; // Perform the transformation int x, y, i; do { changed = false; // Scan rows, except first row for (y = 1; y < w; y++) { OCTAVE_QUIT; // move index to leftmost pixel of current row octave_idx_type i = y*h; /* scan right, propagate distances from above & left */ /* Leftmost pixel is special, has no left neighbors */ olddist2 = (*func)(distx[i], disty[i]); if(olddist2 > 0) // If not already zero distance { newdistx = distx[i+offset_u]; newdisty = disty[i+offset_u]+1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_ur]-1; newdisty = disty[i+offset_ur]+1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; changed = true; } } i++; /* Middle pixels have all neighbors */ for(x=1; x 0) // If not already zero distance { newdistx = distx[i+offset_l]+1; newdisty = disty[i+offset_l]; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_lu]+1; newdisty = disty[i+offset_lu]+1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_u]; newdisty = disty[i+offset_u]+1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } } /* Move index to second rightmost pixel of current row. */ /* Rightmost pixel is skipped, it has no right neighbor. */ i = y*h + h-2; /* scan left, propagate distance from right */ for(x=h-2; x>=0; x--, i--) { olddist2 = (*func)(distx[i], disty[i]); if(olddist2 == 0) continue; // Already zero distance newdistx = distx[i+offset_r]-1; newdisty = disty[i+offset_r]; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; changed = true; } } } /* Scan rows in reverse order, except last row */ for(y=w-2; y>=0; y--) { OCTAVE_QUIT; /* move index to rightmost pixel of current row */ i = y*h + h-1; /* Scan left, propagate distances from below & right */ /* Rightmost pixel is special, has no right neighbors */ olddist2 = (*func)(distx[i], disty[i]); if(olddist2 > 0) // If not already zero distance { newdistx = distx[i+offset_d]; newdisty = disty[i+offset_d]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_dl]+1; newdisty = disty[i+offset_dl]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; changed = true; } } i--; /* Middle pixels have all neighbors */ for(x=h-2; x>0; x--, i--) { olddist2 = (*func)(distx[i], disty[i]); if(olddist2 == 0) continue; // Already zero distance newdistx = distx[i+offset_r]-1; newdisty = disty[i+offset_r]; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_rd]-1; newdisty = disty[i+offset_rd]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_d]; newdisty = disty[i+offset_d]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_dl]+1; newdisty = disty[i+offset_dl]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; changed = true; } } /* Leftmost pixel is special, has no left neighbors */ olddist2 = (*func)(distx[i], disty[i]); if(olddist2 > 0) // If not already zero distance { newdistx = distx[i+offset_r]-1; newdisty = disty[i+offset_r]; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_rd]-1; newdisty = disty[i+offset_rd]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } newdistx = distx[i+offset_d]; newdisty = disty[i+offset_d]-1; newdist2 = (*func)(newdistx, newdisty); if(newdist2 < olddist2) { distx[i]=newdistx; disty[i]=newdisty; olddist2=newdist2; changed = true; } } /* Move index to second leftmost pixel of current row. */ /* Leftmost pixel is skipped, it has no left neighbor. */ i = y*h + 1; for(x=1; xabs(y) ? (abs(x) + sqrt2_1 * abs(y)) : (sqrt2_1 * abs(x) + abs(y)) ; } static FloatMatrix calc_distances (float (*func)(short, short), const boolNDArray& bw, short *xdist, short *ydist) { FloatMatrix dist (bw.dims ()); edtfunc (func, bw, xdist, ydist); const int numel = dist.numel (); float* dist_vec = dist.fortran_vec (); for (int i = 0; i < numel; i++) dist_vec[i] = (*func)(xdist[i], ydist[i]); return dist; } template T calc_index (const boolNDArray& bw, const short *xdist, const short *ydist) { typedef typename T::element_type P; T idx (bw.dims ()); const int numel = bw.numel (); const int rows = bw.rows (); P* idx_vec = idx.fortran_vec (); for(int i = 0; i < numel; i++) idx_vec[i] = i+1 - xdist[i] - ydist[i]*rows; return idx; } DEFUN_DLD (bwdist, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{dist} =} bwdist (@var{bw})\n\ @deftypefnx {Loadable Function} {@var{dist} =} bwdist (@var{bw}, @var{method})\n\ @deftypefnx {Loadable Function} {[@var{dist}, @var{idx}] =} bwdist (@dots{})\n\ Compute distance transform in binary image.\n\ \n\ The image @var{bw} must be a binary matrix For @sc{matlab} compatibility, no\n\ check is performed, all non-zero values are considered object pixels.\n\ The return value @var{dist}, is the distance of each background pixel to the\n\ closest object pixel in a matrix of class @code{single}.\n\ \n\ @var{idx} is the linear index for the closest object, used to calculate the\n\ distance for each of the pixels. Its class is dependent on the number of\n\ elements in @var{bw}, @code{uint64} if less than 2^32 elements, @code{uint32}\n\ otherwise.\n\ \n\ The distance can be measured through different @var{method}s:\n\ \n\ @table @asis\n\ @item euclidean (default)\n\ \n\ @item chessboard\n\ \n\ @item cityblock\n\ \n\ @item quasi-euclidean\n\ \n\ @end table\n\ \n\ Currently, only 2D images are supported.\n\ \n\ @end deftypefn") { octave_value_list retval; const int nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return retval; } // for matlab compatibility, we do not actually check if the values are all // 0 and 1, any non-zero value is considered true const boolNDArray bw = args (0).bool_array_value (); if (error_state) { error ("bwdist: BW must be a logical matrix"); return retval; } std::string method = (nargin > 1) ? args (1).string_value () : "euclidean"; if (error_state) { error ("bwdist: METHOD must be a string"); return retval; } for (octave_idx_type q = 0; q < octave_idx_type (method.length ()); q++) method[q] = tolower (method[q]); if (method.length () <= 2) { static bool warned = false; if (! warned ) { warning ("bwdist: specifying METHOD with abbreviation is deprecated"); warned = true; } if (method == "e" ) { method = "euclidean"; } else if (method == "ch") { method = "chessboard"; } else if (method == "ci") { method = "cityblock"; } else if (method == "q" ) { method = "quasi-euclidean"; } } // Allocate two arrays for temporary output values const int numel = bw.numel (); OCTAVE_LOCAL_BUFFER (short, xdist, numel); OCTAVE_LOCAL_BUFFER (short, ydist, numel); FloatMatrix dist; if (method == "euclidean") { dist = calc_distances (euclidean, bw, xdist, ydist); const Array positions = (!bw).find (); const int zpos = positions.numel(); const octave_idx_type* pos_vec = positions.fortran_vec (); float* dist_vec = dist.fortran_vec (); for (int i = 0; i < zpos; i++) dist_vec[pos_vec[i]] = sqrt (dist_vec[pos_vec[i]]); } else if (method == "chessboard") dist = calc_distances (chessboard, bw, xdist, ydist); else if (method == "cityblock") dist = calc_distances (cityblock, bw, xdist, ydist); else if (method == "quasi-euclidean") dist = calc_distances (quasi_euclidean, bw, xdist, ydist); else error ("bwdist: unknown METHOD '%s'", method.c_str ()); retval(0) = dist; // Compute optional 'index to closest object pixel', only if requested if (nargout > 1) { if (numel >= pow (2, 32)) retval(1) = calc_index (bw, xdist, ydist); else retval(1) = calc_index (bw, xdist, ydist); } return retval; } /* %!shared bw %! %! bw = [0 1 0 1 0 1 1 0 %! 0 0 0 1 1 0 0 0 %! 0 0 0 1 1 0 0 0 %! 0 0 0 1 1 0 0 0 %! 0 0 1 1 1 1 1 1 %! 1 1 1 1 0 0 0 1 %! 1 1 1 0 0 0 1 0 %! 0 0 1 0 0 0 1 1]; %!test %! out = [ 1.00000 0.00000 1.00000 0.00000 1.00000 0.00000 0.00000 1.00000 %! 1.41421 1.00000 1.00000 0.00000 0.00000 1.00000 1.00000 1.41421 %! 2.23607 2.00000 1.00000 0.00000 0.00000 1.00000 2.00000 2.00000 %! 2.00000 1.41421 1.00000 0.00000 0.00000 1.00000 1.00000 1.00000 %! 1.00000 1.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 %! 0.00000 0.00000 0.00000 0.00000 1.00000 1.00000 1.00000 0.00000 %! 0.00000 0.00000 0.00000 1.00000 1.41421 1.00000 0.00000 1.00000 %! 1.00000 1.00000 0.00000 1.00000 2.00000 1.00000 0.00000 0.00000]; %! out = single (out); %! %! assert (bwdist (bw), out, 0.0001); # default is euclidean %! assert (bwdist (bw, "euclidean"), out, 0.0001); %! assert (bwdist (logical (bw), "euclidean"), out, 0.0001); %!test %! out = [ 1 0 1 0 1 0 0 1 %! 1 1 1 0 0 1 1 1 %! 2 2 1 0 0 1 2 2 %! 2 1 1 0 0 1 1 1 %! 1 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 1 0 %! 0 0 0 1 1 1 0 1 %! 1 1 0 1 2 1 0 0]; %! out = single (out); %! %! assert (bwdist (bw, "chessboard"), out); %!test %! out = [ 1 0 1 0 1 0 0 1 %! 2 1 1 0 0 1 1 2 %! 3 2 1 0 0 1 2 2 %! 2 2 1 0 0 1 1 1 %! 1 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 1 0 %! 0 0 0 1 2 1 0 1 %! 1 1 0 1 2 1 0 0]; %! out = single (out); %! %! assert (bwdist (bw, "cityblock"), out); %!test %! out = [ 1.00000 0.00000 1.00000 0.00000 1.00000 0.00000 0.00000 1.00000 %! 1.41421 1.00000 1.00000 0.00000 0.00000 1.00000 1.00000 1.41421 %! 2.41421 2.00000 1.00000 0.00000 0.00000 1.00000 2.00000 2.00000 %! 2.00000 1.41421 1.00000 0.00000 0.00000 1.00000 1.00000 1.00000 %! 1.00000 1.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 %! 0.00000 0.00000 0.00000 0.00000 1.00000 1.00000 1.00000 0.00000 %! 0.00000 0.00000 0.00000 1.00000 1.41421 1.00000 0.00000 1.00000 %! 1.00000 1.00000 0.00000 1.00000 2.00000 1.00000 0.00000 0.00000]; %! out = single (out); %! %! assert (bwdist (bw, "quasi-euclidean"), out, 0.0001); %! %! bw(logical (bw)) = 3; # there is no actual check if matrix is binary or 0 and 1 %! assert (bwdist (bw, "quasi-euclidean"), out, 0.0001); %! %! bw(logical (bw)) = -2; # anything non-zero is considered object %! assert (bwdist (bw, "quasi-euclidean"), out, 0.0001); %!test %! bw = [ 1 1 1 1 0 1 1 1 1 %! 1 1 1 1 0 1 1 1 1 %! 1 1 0 1 1 1 1 1 1 %! 0 1 1 1 1 1 1 1 1]; %! %! dist = [ 0 0 0 0 1 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 %! 0 0 1 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 0]; %! dist = single (dist); %! %! c = [ 1 5 9 13 13 21 25 29 33 %! 2 6 10 14 14 22 26 30 34 %! 3 7 10 15 19 23 27 31 35 %! 8 8 12 16 20 24 28 32 36]; %! c = uint32 (c); %! %! [dout, cout] = bwdist (bw, "euclidean"); %! assert (dout, dist) %! assert (cout, c) ## The quasi-euclidean method is apparently sensitive to a machine precision ## error that happens in x86 systems only. This test will cause an endless ## loop in case of a regression. %!test %! bw = [ 0 1 1 0 0 0 1 0 %! 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 0 0 0 %! 0 0 0 0 0 0 1 0 %! 0 0 0 0 1 0 0 1 %! 0 0 0 0 0 0 0 0 %! 1 0 0 0 0 0 0 0 %! 0 0 1 0 0 1 1 0]; %! out = single ([ %! 1.00000 0.00000 0.00000 1.00000 2.00000 1.00000 0.00000 1.00000 %! 1.00000 1.00000 1.00000 sqrt(2) sqrt(2)+1 sqrt(2) 1.00000 sqrt(2) %! 0.00000 0.00000 1.00000 2.00000 2.00000 sqrt(2) 1.00000 sqrt(2) %! 1.00000 1.00000 sqrt(2) sqrt(2) 1.00000 1.00000 0.00000 1.00000 %! 2.00000 2.00000 2.00000 1.00000 0.00000 1.00000 1.00000 0.00000 %! 1.00000 sqrt(2) 2.00000 sqrt(2) 1.00000 sqrt(2) sqrt(2) 1.00000 %! 0.00000 1.00000 1.00000 sqrt(2) sqrt(2) 1.00000 1.00000 sqrt(2) %! 1.00000 1.00000 0.00000 1.00000 1.00000 0.00000 0.00000 1.00000 %! ]); %! assert (bwdist (bw, "quasi-euclidean"), out); %!error bwdist (bw, "not a valid method"); */ image-2.4.1/src/PaxHeaders.6632/__spatial_filtering__.cc0000644000000000000000000000013212561122761017652 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/src/__spatial_filtering__.cc0000644000175000017500000007327712561122761022515 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2008 Søren Hauberg // Copyright (C) 2013 Carnë Draug // // 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 3 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 . // The 'compare' and 'selnth' functions are copied from the 'cordflt2' function // developed by Teemu Ikonen. This work was released under GPLv2 or later. // -- Søren Hauberg, March 21st, 2008 #include /** * Filter functions for ordered filtering. */ template inline bool compare (const ET a, const ET b) { if (a > b) return 1; else return 0; } template <> inline bool compare (const Complex a, const Complex b) { const double anorm2 = a.real () * a.real () + a.imag () * a.imag (); const double bnorm2 = b.real () * b.real () + b.imag () * b.imag (); if (anorm2 > bnorm2) return 1; else return 0; } // select nth largest member from the array values // Partitioning algorithm, see Numerical recipes chap. 8.5 template ET_OUT selnth (MT &vals, octave_idx_type len, int nth) { ET hinge; int l, r, mid, i, j; l = 0; r = len - 1; for (;;) { // if partition size is 1 or two, then sort and return if (r <= l+1) { if (r == l+1 && compare (vals (l), vals (r))) std::swap (vals (l), vals (r)); return vals (nth); } else { mid = (l+r) >> 1; std::swap (vals (mid), vals (l+1)); // choose median of l, mid, r to be the hinge element // and set up sentinels in the borders (order l, l+1 and r) if (compare (vals (l), vals (r))) std::swap (vals (l), vals (r)); if (compare (vals (l+1), vals (r))) std::swap (vals (l+1), vals (r)); if (compare (vals (l), vals (l+1))) std::swap (vals (l), vals (l+1)); i = l + 1; j = r; hinge = vals (l+1); for (;;) { do i++; while (compare (hinge, vals (i))); do j--; while (compare (vals (j), hinge)); if (i > j) break; std::swap (vals (i), vals (j)); } vals (l+1) = vals (j); vals (j) = hinge; if (j >= nth) r = j - 1; if (j <= nth) l = i; } } } template ET_OUT min_filt (MT &vals, octave_idx_type len, int not_used) { ET_OUT min_val = vals (0); for (octave_idx_type i = 1; i < len; i++) min_val = compare (min_val, vals (i)) ? vals (i) : min_val; return min_val; } template ET_OUT max_filt (MT &vals, octave_idx_type len, int not_used) { ET_OUT max_val = vals (0); for (octave_idx_type i = 1; i < len; i++) max_val = compare (max_val, vals (i)) ? max_val : vals (i); return max_val; } /** * Filter functions for standard deviation filters */ template inline ET square (const ET a) { return a * a; } template ET_OUT std_filt (MT &vals, octave_idx_type len, int norm) { // Compute mean ET_OUT mean = 0; for (octave_idx_type i = 0; i < len; i++) mean += (ET_OUT)vals (i); mean /= (ET_OUT)len; // Compute sum of square differences from the mean ET_OUT var = 0; for (octave_idx_type i = 0; i < len; i++) var += square ((ET_OUT)vals (i) - mean); // Normalise to produce variance var /= (ET_OUT)norm; // Compute std. deviation return sqrt (var); } /** * Functions for the entropy filter. */ /* We only need the explicit typed versions */ template void get_entropy_info (ET &add, int &nbins) { } #define ENTROPY_INFO(TYPE, ADD, NBINS) \ template <> \ void get_entropy_info (TYPE &add, int &nbins) \ { \ add = ADD; \ if (nbins <= 0) \ nbins = NBINS; \ } ENTROPY_INFO (bool, 0, 2) ENTROPY_INFO (octave_int8, 128, 256) //ENTROPY_INFO (octave_int16, 32768, 65536) ENTROPY_INFO (octave_uint8, 0, 256) //ENTROPY_INFO (octave_uint16, 0, 65536) #undef ENTROPY_INFO template ET_OUT entropy_filt (MT &vals, octave_idx_type len, int nbins) { ET add; get_entropy_info (add, nbins); // Compute histogram from values ColumnVector hist (nbins, 0); for (octave_idx_type i = 0; i < len; i++) hist (vals (i) + add) ++; for (octave_idx_type i = 0; i < len; i++) hist (vals (i) + add) /= (double)len; // Compute entropy double entropy = 0; for (octave_idx_type i = 0; i < nbins; i++) { const double p = hist (i); if (p > 0) entropy -= p * xlog2 (p); } return entropy; } /** * The function for the range filter */ template ET_OUT range_filt (MT &vals, octave_idx_type len, int not_used) { const ET_OUT min_val = min_filt (vals, len, not_used); const ET_OUT max_val = max_filt (vals, len, not_used); return max_val - min_val; } // The general function for doing the filtering // // We differentiate between MT and MTout for cases such as std and // entropy, where the output will have a different class than the input. template octave_value do_filtering (const MT &in, const boolNDArray &se, ETout (*filter_function) (MT&, octave_idx_type, int), const MT &S, int arg4) { typedef typename MT::element_type Pin; const octave_idx_type ndims = in.ndims (); const octave_idx_type se_nnz = se.nnz (); const dim_vector se_size = se.dims ().redim (ndims); const dim_vector in_size = in.dims (); // Create output matrix dim_vector out_size (in_size); for (octave_idx_type i = 0; i < ndims; i++) { out_size (i) = in_size (i) - se_size (i) + 1; } MTout out (out_size); // We will loop for all elements of the output matrix. On each iteration // we collect the values from the input matrix as marked by the // structuring element (SE), and pass them to the filtering function. // The value returned is then assigned assigned to the output matrix. // Using dim_vector's and increment_index() allows us to support matrices // with any number of dimensions. // Create a 2D array with the subscript indices for each of the // true elements on the SE. Each column has the subscripts for // each true elements, and the rows are the dimensions. // We also don't need the heights in a matrix. We can extract the // ones that matter for us and place them in a vector to access // them easily during the loop. Array se_sub (dim_vector (ndims, 1), 0); Array nnz_sub (dim_vector (ndims, se_nnz)); Array heights (dim_vector (se_nnz, 1)); for (octave_idx_type i = 0, found = 0; found < se_nnz; i++) { if (se(se_sub)) { // insert the coordinate vectors on the next column nnz_sub.insert (se_sub, 0, found); // store new height value heights(found) = S(se_sub); found++; } boolNDArray::increment_index (se_sub, se_size); } // Create array with subscript indexes for the elements being // evaluated at any given time. We will be using linear indexes // later but need the subscripts to add them. Array in_sub (dim_vector (ndims, 1)); Array out_sub (dim_vector (ndims, 1), 0); // For each iteration of the output matrix, will store the values from // the input matrix that will be passed to the filtering function. MT values (dim_vector (1, se_nnz)); // Get pointers to the fortran vector for good performance. ETout* out_fvec = out.fortran_vec (); Pin* values_fvec = values.fortran_vec (); Pin* heights_fvec = heights.fortran_vec (); octave_idx_type* in_sub_fvec = in_sub.fortran_vec (); octave_idx_type* out_sub_fvec = out_sub.fortran_vec (); octave_idx_type* nnz_sub_fvec = nnz_sub.fortran_vec (); // We iterate for all elements of the output matrix const octave_idx_type out_numel = out.numel (); for (octave_idx_type out_ind = 0; out_ind < out_numel; out_ind++) { // On each iteration we get the subscript indexes for the output // matrix (obtained with increment_index), and add to it the // subscript indexes of each of the nnz elements in the SE. These // are the subscript indexes for the elements in input matrix that // need to be evaluated for that element in the output matrix octave_idx_type nnz_sub_ind = 0; for (octave_idx_type se_ind = 0; se_ind < se_nnz; se_ind++) { nnz_sub_ind = se_ind * ndims; // move to the next column for (octave_idx_type n = 0; n < ndims; n++, nnz_sub_ind++) { // get subcript indexes for the input matrix in_sub_fvec[n] = out_sub_fvec[n] + nnz_sub_fvec[nnz_sub_ind]; } values_fvec[se_ind] = in(in_sub) + heights_fvec[se_ind]; } // Compute filter result out_fvec[out_ind] = filter_function (values, se_nnz, arg4); // Prepare for next iteration boolNDArray::increment_index (out_sub, out_size); OCTAVE_QUIT; } return octave_value (out); } DEFUN_DLD(__spatial_filtering__, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} __spatial_filtering__(@var{A}, @var{domain},\ @var{method}, @var{S}, @var{arg})\n\ Implementation of two-dimensional spatial filtering. In general this function\n\ should NOT be used -- user interfaces are available in other functions.\n\ The function computes local characteristics of the image @var{A} in the domain\n\ @var{domain}. The following values of @var{method} are supported.\n\ \n\ @table @asis\n\ @item @qcode{\"ordered\"}\n\ Perform ordered filtering. The output in a pixel is the @math{n}th value of a\n\ sorted list containing the elements of the neighbourhood. The value of @math{n}\n\ is given in the @var{arg} argument. The corresponding user interface is available\n\ in @code{ordfilt2} and @code{ordfiltn}.\n\ \n\ @item @qcode{\"std\"}\n\ Compute the local standard deviation. The corresponding user interface is available\n\ in @code{stdfilt}.\n\ \n\ @item @qcode{\"entropy\"}\n\ Compute the local entropy. The corresponding user interface is available\n\ in @code{entropyfilt}.\n\ \n\ @item @qcode{\"range\"}\n\ Compute the local range of the data. The corresponding user interface is\n\ available in @code{rangefilt}.\n\ \n\ @item @qcode{\"min\"}\n\ Computes the smallest value in a local neighbourheed.\n\ \n\ @item @qcode{\"max\"}\n\ Computes the largest value in a local neighbourheed.\n\ \n\ @item @qcode{\"encoded sign of difference\"}\n\ NOT IMPLEMENTED (local binary patterns style)\n\ \n\ @end table\n\ @seealso{ordfilt2}\n\ @end deftypefn\n\ ") { octave_value_list retval; const octave_idx_type nargin = args.length (); if (nargin < 4) { print_usage (); return retval; } const boolNDArray dom = args (1).bool_array_value (); if (error_state) { error ("__spatial_filtering__: A must be a logical matrix"); return retval; } octave_idx_type len = 0; for (octave_idx_type i = 0; i < dom.numel (); i++) len += dom (i); const int ndims = dom.ndims (); const int args0_ndims = args (0).ndims (); if (args0_ndims != ndims || args (3).ndims () != ndims) { error ("__spatial_filtering__: A and S must have the same dimensions"); return retval; } int arg4 = (nargin == 4) ? 0 : args (4).int_value (); const std::string method = args (2).string_value (); if (error_state) { error ("__spatial_filtering__: method must be a string"); return retval; } #define GENERAL_ACTION(MT, FUN, ET, MT_OUT, ET_OUT, FILTER_FUN) \ { \ const MT A = args (0).FUN (); \ const MT S = args (3).FUN (); \ if (error_state) \ error ("__spatial_filtering__: invalid input"); \ else \ retval = do_filtering (A, dom, FILTER_FUN, S, arg4); \ } if (method == "ordered") { // Handle input arg4 -= 1; // convert arg to zero-based index if (arg4 > len - 1) { warning ("__spatial_filtering__: nth should be less than number of non-zero " "values in domain setting nth to largest possible value"); arg4 = len - 1; } if (arg4 < 0) { warning ("__spatial_filtering__: nth should be non-negative, setting to 1"); arg4 = 0; } // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, MT, ET, selnth) if (args (0).is_real_matrix ()) ACTION (NDArray, array_value, double) else if (args (0).is_complex_matrix ()) ACTION (ComplexNDArray, complex_array_value, Complex) else if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_int8_type ()) ACTION (int8NDArray, int8_array_value, octave_int8) else if (args (0).is_int16_type ()) ACTION (int16NDArray, int16_array_value, octave_int16) else if (args (0).is_int32_type ()) ACTION (int32NDArray, int32_array_value, octave_int32) else if (args (0).is_int64_type ()) ACTION (int64NDArray, int64_array_value, octave_int64) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else if (args (0).is_uint16_type ()) ACTION (uint16NDArray, uint16_array_value, octave_uint16) else if (args (0).is_uint32_type ()) ACTION (uint32NDArray, uint32_array_value, octave_uint32) else if (args (0).is_uint64_type ()) ACTION (uint64NDArray, uint64_array_value, octave_uint64) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else if (method == "min") { // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, MT, ET, min_filt) if (args (0).is_real_matrix ()) ACTION (NDArray, array_value, double) else if (args (0).is_complex_matrix ()) ACTION (ComplexNDArray, complex_array_value, Complex) else if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_int8_type ()) ACTION (int8NDArray, int8_array_value, octave_int8) else if (args (0).is_int16_type ()) ACTION (int16NDArray, int16_array_value, octave_int16) else if (args (0).is_int32_type ()) ACTION (int32NDArray, int32_array_value, octave_int32) else if (args (0).is_int64_type ()) ACTION (int64NDArray, int64_array_value, octave_int64) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else if (args (0).is_uint16_type ()) ACTION (uint16NDArray, uint16_array_value, octave_uint16) else if (args (0).is_uint32_type ()) ACTION (uint32NDArray, uint32_array_value, octave_uint32) else if (args (0).is_uint64_type ()) ACTION (uint64NDArray, uint64_array_value, octave_uint64) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else if (method == "max") { // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, MT, ET, max_filt) if (args (0).is_real_matrix ()) ACTION (NDArray, array_value, double) else if (args (0).is_complex_matrix ()) ACTION (ComplexNDArray, complex_array_value, Complex) else if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_int8_type ()) ACTION (int8NDArray, int8_array_value, octave_int8) else if (args (0).is_int16_type ()) ACTION (int16NDArray, int16_array_value, octave_int16) else if (args (0).is_int32_type ()) ACTION (int32NDArray, int32_array_value, octave_int32) else if (args (0).is_int64_type ()) ACTION (int64NDArray, int64_array_value, octave_int64) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else if (args (0).is_uint16_type ()) ACTION (uint16NDArray, uint16_array_value, octave_uint16) else if (args (0).is_uint32_type ()) ACTION (uint32NDArray, uint32_array_value, octave_uint32) else if (args (0).is_uint64_type ()) ACTION (uint64NDArray, uint64_array_value, octave_uint64) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else if (method == "range") { // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, MT, ET, range_filt) if (args (0).is_real_matrix ()) ACTION (NDArray, array_value, double) else if (args (0).is_complex_matrix ()) ACTION (ComplexNDArray, complex_array_value, Complex) else if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_int8_type ()) ACTION (int8NDArray, int8_array_value, octave_int8) else if (args (0).is_int16_type ()) ACTION (int16NDArray, int16_array_value, octave_int16) else if (args (0).is_int32_type ()) ACTION (int32NDArray, int32_array_value, octave_int32) else if (args (0).is_int64_type ()) ACTION (int64NDArray, int64_array_value, octave_int64) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else if (args (0).is_uint16_type ()) ACTION (uint16NDArray, uint16_array_value, octave_uint16) else if (args (0).is_uint32_type ()) ACTION (uint32NDArray, uint32_array_value, octave_uint32) else if (args (0).is_uint64_type ()) ACTION (uint64NDArray, uint64_array_value, octave_uint64) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else if (method == "std") { // Compute normalisation factor if (arg4 == 0) arg4 = len - 1; // unbiased else arg4 = len; // max. likelihood // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, NDArray, double, std_filt) if (args (0).is_real_matrix ()) ACTION (NDArray, array_value, double) else if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_int8_type ()) ACTION (int8NDArray, int8_array_value, octave_int8) else if (args (0).is_int16_type ()) ACTION (int16NDArray, int16_array_value, octave_int16) else if (args (0).is_int32_type ()) ACTION (int32NDArray, int32_array_value, octave_int32) else if (args (0).is_int64_type ()) ACTION (int64NDArray, int64_array_value, octave_int64) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else if (args (0).is_uint16_type ()) ACTION (uint16NDArray, uint16_array_value, octave_uint16) else if (args (0).is_uint32_type ()) ACTION (uint32NDArray, uint32_array_value, octave_uint32) else if (args (0).is_uint64_type ()) ACTION (uint64NDArray, uint64_array_value, octave_uint64) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else if (method == "entropy") { // Do the real work #define ACTION(MT, FUN, ET) \ GENERAL_ACTION(MT, FUN, ET, NDArray, double, entropy_filt) if (args (0).is_bool_matrix ()) ACTION (boolNDArray, bool_array_value, bool) else if (args (0).is_uint8_type ()) ACTION (uint8NDArray, uint8_array_value, octave_uint8) else error ("__spatial_filtering__: first input should be a real, complex, or integer array"); #undef ACTION } else { error ("__spatial_filtering__: unknown method '%s'.", method.c_str ()); } return retval; } /* %!shared a, domain, s, out %! a = [ 82 2 97 43 79 43 41 65 51 11 %! 60 65 21 56 94 77 36 38 75 39 %! 32 68 78 1 16 75 76 90 81 56 %! 43 90 82 41 36 1 87 19 18 63 %! 63 64 2 48 18 43 38 25 22 99 %! 12 46 90 79 3 92 39 79 10 22 %! 38 98 11 10 40 90 88 38 4 76 %! 54 37 9 4 33 98 36 47 53 57 %! 38 76 82 50 14 74 64 99 7 33 %! 88 96 41 62 84 89 97 23 41 3]; %! %! domain = ones (3); %! s = zeros (3); %! %! out = [ 2 1 1 1 16 36 36 11 %! 21 1 1 1 1 1 18 18 %! 2 1 1 1 1 1 18 18 %! 2 2 2 1 1 1 10 10 %! 2 2 2 3 3 25 4 4 %! 9 4 3 3 3 36 4 4 %! 9 4 4 4 14 36 4 4 %! 9 4 4 4 14 23 7 3]; %!assert (__spatial_filtering__ (a, domain, "min", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, 1), out); %! %! out = [ 97 97 97 94 94 90 90 90 %! 90 90 94 94 94 90 90 90 %! 90 90 82 75 87 90 90 99 %! 90 90 90 92 92 92 87 99 %! 98 98 90 92 92 92 88 99 %! 98 98 90 98 98 98 88 79 %! 98 98 82 98 98 99 99 99 %! 96 96 84 98 98 99 99 99]; %!assert (__spatial_filtering__ (a, domain, "max", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, nnz (domain)), out); %! %! out = [ 60 43 43 43 43 43 51 51 %! 60 56 36 36 36 38 38 39 %! 63 48 18 18 36 38 25 25 %! 46 48 36 36 36 38 22 22 %! 38 46 11 40 39 39 25 22 %! 37 11 10 33 39 47 38 38 %! 38 11 11 33 40 64 38 38 %! 41 41 33 50 64 64 41 33]; %!assert (__spatial_filtering__ (a, domain, "ordered", s, 4), out); %! %! out = [ 31.223 33.788 35.561 31.011 26.096 20.630 20.403 24.712 %! 23.428 29.613 32.376 34.002 33.593 32.470 29.605 26.333 %! 27.834 32.890 29.903 24.207 30.083 32.497 31.898 32.600 %! 32.027 28.995 33.530 31.002 32.241 32.004 27.501 32.070 %! 34.682 36.030 33.046 33.745 32.509 27.352 28.607 34.180 %! 32.709 37.690 32.992 40.036 34.456 26.656 27.685 26.863 %! 30.971 36.227 25.775 34.873 29.917 25.269 32.292 30.410 %! 29.135 31.626 30.056 33.594 30.814 28.853 30.917 29.120]; %!assert (__spatial_filtering__ (a, domain, "std", s), out, 0.001); %! %! out = [ 95 96 96 93 78 54 54 79 %! 69 89 93 93 93 89 72 72 %! 88 89 81 74 86 89 72 81 %! 88 88 88 91 91 91 77 89 %! 96 96 88 89 89 67 84 95 %! 89 94 87 95 95 62 84 75 %! 89 94 78 94 84 63 95 95 %! 87 92 80 94 84 76 92 96]; %!assert (__spatial_filtering__ (a, domain, "range", s), out); %! %! domain = [ 1 1 0 %! 0 1 1 %! 0 1 0]; %! %! out = [ 2 2 1 16 36 36 38 39 %! 60 1 1 16 1 36 19 18 %! 32 2 1 1 1 19 18 18 %! 2 2 18 3 1 1 19 10 %! 46 2 2 3 18 38 10 4 %! 11 9 4 3 3 36 4 4 %! 9 4 4 10 36 36 38 4 %! 37 9 4 4 33 36 7 7]; %!assert (__spatial_filtering__ (a, domain, "min", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, 1), out); %! %! out = [ 82 97 97 94 79 76 90 81 %! 90 82 56 94 94 90 90 81 %! 90 82 78 36 87 87 90 90 %! 90 90 82 43 92 87 87 99 %! 98 90 79 92 92 88 79 25 %! 98 90 90 90 98 92 79 79 %! 98 98 50 98 98 90 99 57 %! 96 82 62 84 98 99 99 53]; %!assert (__spatial_filtering__ (a, domain, "max", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, nnz (domain)), out); %! %! out = [ 68 78 94 79 77 43 75 75 %! 78 78 41 75 77 87 81 75 %! 82 78 48 18 75 76 76 81 %! 64 90 79 41 43 39 79 22 %! 90 79 48 48 90 79 38 22 %! 46 46 79 79 92 88 47 76 %! 76 82 33 40 90 88 88 53 %! 82 50 50 74 89 98 47 47]; %!assert (__spatial_filtering__ (a, domain, "ordered", s, 4), out); %! %! out = [ 34.2389 39.2772 39.6699 31.6812 20.7364 16.5439 22.2419 17.2395 %! 11.9248 36.3084 21.6217 30.8350 36.4047 21.6726 30.9144 26.1017 %! 22.2980 33.2746 27.5808 14.5017 36.8890 29.0259 34.6020 33.2521 %! 32.2490 37.9579 26.9685 17.1959 32.5346 31.3847 33.5976 36.8280 %! 21.3354 40.1833 34.0044 33.9882 32.9894 24.1102 25.6613 9.0995 %! 35.4641 35.3794 39.0871 35.4753 39.9775 28.7193 26.7451 35.6553 %! 35.2179 45.3398 19.3210 35.2987 28.4042 24.0832 26.8421 25.0539 %! 23.4307 26.2812 26.3287 35.6959 25.2646 28.1016 34.9829 17.9221]; %!assert (__spatial_filtering__ (a, domain, "std", s), out, 0.001); %! %! out = [ 80 95 96 78 43 40 52 42 %! 30 81 55 78 93 54 71 63 %! 58 80 77 35 86 68 72 72 %! 88 88 64 40 91 86 68 89 %! 52 88 77 89 74 50 69 21 %! 87 81 86 87 95 56 75 75 %! 89 94 46 88 62 54 61 53 %! 59 73 58 80 65 63 92 46]; %!assert (__spatial_filtering__ (a, domain, "range", s), out); %! %! s = [ 1 -3 4 %! 6 -7 2 %! -1 3 -5]; %! %! out = [ -1 3 4 19 38 29 31 41 %! 61 3 -6 9 4 33 22 21 %! 33 5 -2 2 -6 21 12 11 %! 4 -5 20 6 -2 2 16 13 %! 39 -1 3 -4 19 32 12 3 %! 13 4 3 0 4 36 6 -3 %! 11 2 -3 11 38 29 35 1 %! 34 6 1 5 34 33 9 0]; %!assert (__spatial_filtering__ (a, domain, "min", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, 1), out); %! %! out = [ 83 94 98 87 80 79 93 84 %! 93 85 53 91 95 92 83 74 %! 84 75 79 29 89 80 87 91 %! 87 93 83 45 95 84 88 101 %! 101 83 72 94 93 91 72 26 %! 91 87 91 92 101 93 76 80 %! 95 99 53 100 91 91 102 59 %! 99 75 65 87 95 101 92 50]; %!assert (__spatial_filtering__ (a, domain, "max", s), out); %!assert (__spatial_filtering__ (a, domain, "ordered", s, nnz (domain)), out); %! %! out = [ 71 81 96 79 78 44 77 68 %! 80 71 44 77 78 90 83 72 %! 83 75 51 21 72 76 77 78 %! 57 91 82 42 40 42 82 20 %! 92 81 45 49 85 81 41 24 %! 43 47 76 80 90 81 50 78 %! 79 85 35 37 87 85 89 46 %! 84 52 43 76 92 100 44 48]; %!assert (__spatial_filtering__ (a, domain, "ordered", s, 4), out); %! %! out = [ 34.903 40.206 39.885 28.627 20.620 19.248 25.209 17.111 %! 14.536 35.865 23.221 32.230 34.903 23.923 28.879 22.621 %! 20.635 30.113 29.351 11.610 38.863 25.936 34.608 34.482 %! 29.811 40.998 28.279 17.897 34.666 29.978 36.150 38.213 %! 25.066 39.240 30.013 37.300 31.856 27.428 22.884 10.281 %! 31.890 34.761 39.645 37.526 39.336 27.031 25.648 39.285 %! 35.017 47.776 22.764 35.912 25.460 25.636 29.861 24.566 %! 25.213 25.000 26.391 38.451 24.631 31.305 31.118 20.611]; %!assert (__spatial_filtering__ (a, domain, "std", s), out, 0.001); %! %! out = [ 84 91 94 68 42 50 62 43 %! 32 82 59 82 91 59 61 53 %! 51 70 81 27 95 59 75 80 %! 83 98 63 39 97 82 72 88 %! 62 84 69 98 74 59 60 23 %! 78 83 88 92 97 57 70 83 %! 84 97 56 89 53 62 67 58 %! 65 69 64 82 61 68 83 50]; %!assert (__spatial_filtering__ (a, domain, "range", s), out); */ image-2.4.1/src/PaxHeaders.6632/connectivity.h0000644000000000000000000000013212561122761015736 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/connectivity.h0000644000175000017500000001065012561122761020563 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2014 Carnë Draug // // 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 3 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 // . #ifndef OCTAVE_IMAGE_CONNDEF #define OCTAVE_IMAGE_CONNDEF #include #include #include #include // octave_Inf namespace octave { namespace image { class connectivity { public: connectivity () = default; //! Will throw if val is bad connectivity (const octave_value& val); connectivity (const boolNDArray& mask_arg); connectivity (const octave_idx_type& conn); connectivity (const octave_idx_type& ndims, const std::string& type); boolNDArray mask; // For a matrix of size `size', what are the offsets for all of its // connected elements (will have negative and positive values). Array neighbourhood (const dim_vector& size) const; Array deleted_neighbourhood (const dim_vector& size) const; Array positive_neighbourhood (const dim_vector& size) const; Array negative_neighbourhood (const dim_vector& size) const; template T create_padded (const T& image, const P& val) const; template void unpad (T& image) const; template static P min_value (void); static Array padding_lengths (const dim_vector& size, const dim_vector& padded_size); private: void ctor (const boolNDArray& mask_arg); void ctor (const octave_idx_type& conn); //! Like octave_value::double_value() but actually checks if scalar. static double double_value (const octave_value& val); //! Like octave_value::bool_array_value() but actually checks if //! all values are zeros and one. static boolNDArray bool_array_value (const octave_value& val); //! Like Array::ndims() but will return 1 dimension for ColumnVector static octave_idx_type ndims (const dim_vector& d); template static octave_idx_type ndims (const Array& a); }; class invalid_conversion : public std::invalid_argument { public: invalid_conversion (const std::string& what_arg) : std::invalid_argument (what_arg) { } }; class invalid_connectivity : public octave::image::invalid_conversion { public: invalid_connectivity (const std::string& what_arg) : octave::image::invalid_conversion (what_arg) { } }; } } // Templated methods template T octave::image::connectivity::create_padded (const T& image, const P& val) const { const octave_idx_type pad_ndims = std::min (mask.ndims (), image.ndims ()); Array idx (dim_vector (image.ndims (), 1), 0); dim_vector padded_size = image.dims (); for (octave_idx_type i = 0; i < pad_ndims; i++) { padded_size(i) += 2; idx(i) = 1; } T padded (padded_size, val); // padded(2:end-1, 2:end-1, ..., 2:end-1) = BW padded.insert (image, idx); return padded; } template void octave::image::connectivity::unpad (T& image) const { const octave_idx_type pad_ndims = std::min (mask.ndims (), image.ndims ()); const dim_vector padded_size = image.dims (); Array inner_slice (dim_vector (image.ndims (), 1)); for (octave_idx_type i = 0; i < pad_ndims ; i++) inner_slice(i) = idx_vector (1, padded_size(i) - 1); for (octave_idx_type i = pad_ndims; i < image.ndims (); i++) inner_slice(i) = idx_vector (0, padded_size(i)); image = image.index (inner_slice); return; } template P octave::image::connectivity::min_value (void) { if (typeid (P) == typeid (bool)) return false; else return P(-octave_Inf); } #endif image-2.4.1/src/PaxHeaders.6632/aclocal.m40000644000000000000000000000013212561122762014710 xustar0030 mtime=1438950898.986252237 30 atime=1438950899.238252237 30 ctime=1438950899.342252237 image-2.4.1/src/aclocal.m40000644000175000017500000000130712561122762017534 0ustar00carandraugcarandraug00000000000000# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_include([m4/ax_cxx_compile_stdcxx_11.m4]) image-2.4.1/src/PaxHeaders.6632/Makefile.in0000644000000000000000000000013212561122761015114 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/src/Makefile.in0000644000175000017500000000205012561122761017734 0ustar00carandraugcarandraug00000000000000MKOCTFILE ?= mkoctfile -Wall OCTAVE ?= octave FLAGGED_MKOCTFILE = CXXFLAGS="@CXXFLAGS@" $(MKOCTFILE) ## We can't link oct files, and Octave's package system does not handle ## shared libraries. Because of this, we need to create object files for ## our "shared" libraries and statically link to selected oct files. conn_dependent = conndef.oct bwlabeln.oct imreconstruct.oct bwconncomp.oct strel_dependent = imerode.oct libs = connectivity.o strel.o OCT_FILES = __spatial_filtering__.oct __bilateral__.oct \ __custom_gaussian_smoothing__.oct __boundary__.oct bwfill.oct \ rotate_scale.oct hough_line.oct graycomatrix.oct bwdist.oct \ nonmax_supress.oct $(strel_dependent) $(conn_dependent) CC_FILES = $(patsubst %.oct, %.cc, ${OCT_FILES}) all: ${OCT_FILES} %.o: %.cc %.h $(FLAGGED_MKOCTFILE) -c $< $(conn_dependent): %.oct: %.cc connectivity.o $(FLAGGED_MKOCTFILE) $^ $(strel_dependent): %.oct: %.cc strel.o $(FLAGGED_MKOCTFILE) $^ %.oct: %.cc $(FLAGGED_MKOCTFILE) $< clean: rm -f *.o octave-core core *.oct *~ image-2.4.1/src/PaxHeaders.6632/union-find.h0000644000000000000000000000013212561122761015266 xustar0030 mtime=1438950897.794252238 30 atime=1438950897.794252238 30 ctime=1438950899.342252237 image-2.4.1/src/union-find.h0000644000175000017500000000457012561122761020117 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2011 Jordi Gutiérrez Hermoso // Copyright (C) 2014 Carnë Draug // // 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 3 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 . #include struct voxel { octave_idx_type rank; octave_idx_type parent; voxel () = default; }; class union_find { // Union-find data structure, see e.g. // http://en.wikipedia.org/wiki/Union-find private: std::vector voxels; public: union_find (octave_idx_type s) : voxels (s) {}; // Use only when adding new elements for the first time void add (const octave_idx_type idx) { voxels[idx].parent = idx; voxels[idx].rank = 0; return; } // Give the root representative id for this object octave_idx_type find (const octave_idx_type idx) { voxel* elt = &voxels[idx]; if (elt->parent != idx) elt->parent = find (elt->parent); return elt->parent; } //Given two objects, unite the sets to which they belong void unite (const octave_idx_type idx1, const octave_idx_type idx2) { octave_idx_type root1 = find (idx1); octave_idx_type root2 = find (idx2); //Check if any union needs to be done, maybe they already are //in the same set. if (root1 != root2) { voxel* v1 = &voxels[root1]; voxel* v2 = &voxels[root2]; if (v1->rank > v2->rank) v1->parent = root2; else if (v1->rank < v2->rank) v2->parent = root1; else { v2->parent = root1; v1->rank++; } } } std::vector get_ids (const NDArray& L) const { std::vector ids; const double* v = L.fortran_vec (); for (size_t i = 0; i < voxels.size (); i++) if (v[i]) ids.push_back (i); return ids; }; }; image-2.4.1/src/PaxHeaders.6632/m40000644000000000000000000000013212561122761013312 xustar0030 mtime=1438950897.790252238 30 atime=1438950899.342252237 30 ctime=1438950899.342252237 image-2.4.1/src/m4/0000755000175000017500000000000012561122761016212 5ustar00carandraugcarandraug00000000000000image-2.4.1/src/m4/PaxHeaders.6632/ax_cxx_compile_stdcxx_11.m40000644000000000000000000000013212561122761020531 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.990252238 30 ctime=1438950899.342252237 image-2.4.1/src/m4/ax_cxx_compile_stdcxx_11.m40000644000175000017500000001127512561122761023362 0ustar00carandraugcarandraug00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014 Alexey Sokolov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; ]]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) image-2.4.1/src/PaxHeaders.6632/__custom_gaussian_smoothing__.cc0000644000000000000000000000013212561122761021445 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/src/__custom_gaussian_smoothing__.cc0000644000175000017500000002053712561122761024277 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2008 Søren Hauberg // // 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 3 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 . #include template MT custom_gaussian_smoothing (const MT &I, const Matrix &lambda1, const Matrix &lambda2, const Matrix &theta) { const octave_idx_type rows = I.rows (); const octave_idx_type cols = I.columns (); // Allocate output MT J (I.dims ()); // Iterate over every element of 'I' for (octave_idx_type row = 0; row < rows; row++) { for (octave_idx_type col = 0; col < cols; col++) { // Extract parameters const double v1 = lambda1 (row, col); const double v2 = lambda2 (row, col); const double t = theta (row, col); // Should we perform any filtering? if (std::min (v1, v2) > 0) { // Compute inverse covariance matrix, C^-1 = [a, b; b, c] const double iv1 = 1.0/v1; const double iv2 = 1.0/v2; const double ct = cos (t); const double st = sin (t); const double ct2 = ct*ct; const double st2 = st*st; const double ctst = ct*st; const double a = ct2*iv2 + st2*iv1; const double b = (iv2-iv1)*ctst; const double c = st2*iv2 + ct2*iv1; // Compute bounding box of the filter const double k = 3.0; // The maximally allowed Mahalanobis' distance const double sqrtv1 = sqrt (v1); const double sqrtv2 = sqrt (v2); const octave_idx_type rur = abs (k*(ct*sqrtv2 - st*sqrtv1)); // 'rur' means 'row-upper-right' const octave_idx_type cur = abs (k*(st*sqrtv2 + ct*sqrtv1)); const octave_idx_type rlr = abs (k*(ct*sqrtv2 + st*sqrtv1)); const octave_idx_type clr = abs (k*(st*sqrtv2 - ct*sqrtv1)); const octave_idx_type rul = abs (k*(-ct*sqrtv2 - st*sqrtv1)); const octave_idx_type cul = abs (k*(-st*sqrtv2 + ct*sqrtv1)); const octave_idx_type rll = abs (k*(-ct*sqrtv2 + st*sqrtv1)); const octave_idx_type cll = abs (k*(-st*sqrtv2 - ct*sqrtv1)); const octave_idx_type r_delta = std::max (std::max (rur, rlr), std::max (rul, rll)); const octave_idx_type c_delta = std::max (std::max (cur, clr), std::max (cul, cll));; // The bounding box is now (row-r_delta):(row+r_delta)x(col-c_delta):(col+c_delta). // We, however, represent the bounding box in a local coordinate system around (row, col). const octave_idx_type r1 = std::max (row-r_delta, octave_idx_type (0)) - row; const octave_idx_type r2 = std::min (row+r_delta, rows-1) - row; const octave_idx_type c1 = std::max (col-c_delta, octave_idx_type (0)) - col; const octave_idx_type c2 = std::min (col+c_delta, cols-1) - col; // Perform the actual filtering double sum = 0; double wsum = 0; // for normalisation for (octave_idx_type rl = r1; rl <= r2; rl++) { for (octave_idx_type cl = c1; cl <= c2; cl++) { // Compute Mahalanobis' distance const double dsquare = rl*(a*rl + b*cl) + cl*(b*rl + c*cl); // We only do the filtering in an elliptical window if (dsquare > k*k) continue; // Update filter values const double w = exp (-0.5*dsquare); wsum += w; sum += w*(double)I.elem (row + rl, col + cl); } // End: cl } // End: rl // Compute final result J (row, col) = sum/wsum; } else // No filtering is performed { J.elem (row, col) = I.elem (row, col); } } // End: column iteration } // End: row iteration // Return return J; } #define RETURN_IF_INVALID \ if (error_state) \ { \ error ("__custom_gaussian_smoothing__: invalid input"); \ return retval; \ } DEFUN_DLD (__custom_gaussian_smoothing__, args, ,"\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{J} =} __custom_gaussian_smooting__ (@var{I}, @var{lambda1}, @var{lambda2}, @var{theta})\n\ Performs Gaussian smoothing on the image @var{I}. In pixel @math{(r,c)} the \n\ Eigenvalues of the Gaussian is @var{lambda1}@math{(r,c)} and @var{lambda2}@math{(r,c)}.\n\ The Gaussian is rotated with the angle given in @var{theta}@math{(r,c)}.\n\ \n\ @strong{Warning:} this function should @i{never} be called directly! The user\n\ interface to this function is available in @code{imsmooth}.\n\ @seealso{imsmooth}\n\ @end deftypefn\n\ ") { // Handle Input octave_value_list retval; const int nargin = args.length (); if (nargin != 4) { print_usage (); return retval; } const Matrix lambda1 = args (1).matrix_value (); const Matrix lambda2 = args (2).matrix_value (); const Matrix theta = args (3).matrix_value (); RETURN_IF_INVALID; const octave_idx_type rows = args (0).rows(); const octave_idx_type cols = args (0).columns(); if (lambda1.rows () != rows || lambda1.columns () != cols || lambda2.rows () != rows || lambda2.columns () != cols || theta.rows () != rows || theta.columns () != cols) { error ("__custom_gaussian_smoothing__: size mismatch"); return retval; } // Take action depending on input type //octave_value J; if (args(0).is_real_matrix()) { const Matrix I = args(0).matrix_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_int8_type()) { const int8NDArray I = args(0).int8_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_int16_type()) { const int16NDArray I = args(0).int16_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_int32_type()) { const int32NDArray I = args(0).int32_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_int64_type()) { const int64NDArray I = args(0).int64_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_uint8_type()) { const uint8NDArray I = args(0).uint8_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_uint16_type()) { const uint16NDArray I = args(0).uint16_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_uint32_type()) { const uint32NDArray I = args(0).uint32_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else if (args(0).is_uint64_type()) { const uint64NDArray I = args(0).uint64_array_value(); RETURN_IF_INVALID; retval.append (custom_gaussian_smoothing(I, lambda1, lambda2, theta)); } else { error("__custom_gaussian_smoothing__: first input should be a real or integer array"); return retval; } // Return return retval; } image-2.4.1/src/PaxHeaders.6632/strel.h0000644000000000000000000000013212561122761014351 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/strel.h0000644000175000017500000001021412561122761017172 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2013 Carnë Draug // // 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 3 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 . // This is wrapper class for the @strel class so that it can be used by // the rest of the image package using SE's. It's not a perfect wrapper // on purpose. For example, the reflect method behaves kinda weird for // matlab compatibility. In here we try to make a bit more sense. // An important thing about this class is how the origin (defaults to // center coordinates which can have different interpretations when // sides are of even length) moves when it's reflected. Consider the // following (x is the origin) // // o o o o o o // o x o -- reflect --> o x o // o o o o o o // // o o o o o o o o // o o x o -- reflect --> o x o o // o o o o o o o o #ifndef OCTAVE_IMAGE_STREL #define OCTAVE_IMAGE_STREL #include #include namespace octave { namespace image { class strel { public: strel (const octave_value& arg); strel (const boolNDArray& nhood, const NDArray& height); strel (const boolNDArray& nhood, const NDArray& height, const Array& origin); boolNDArray get_nhood (void) const; octave_idx_type get_nnz (void) const; Array get_origin (void) const; strel operator () (const octave_idx_type& i) const; // Number of strel objects after decomposition, NOT numel of nhood octave_idx_type numel (void) const; // flat SE? bool flat (void) const; // set origin of the SE to specific coordinates void set_origin (const Array& sub); // reflect the SE (rotates is 180 degrees in all dimensions). // Note that when rotating it, the origin coordinates move with it // (this is by design see ratinoal on top of this file). strel reflect (void) const; // given a matrix with a specific cumulative size, what's the offset // for each true element of the nhood from the first element (true or // false) of the nhood. Array offsets (const dim_vector& cum_size) const; // array with height of each true element in the nhood (same order // as the one returned by offsets). template Array

true_heights (void) const; Array pre_pad (const octave_idx_type& mt_ndims, const std::string& shape) const; Array post_pad (const octave_idx_type& mt_ndims, const std::string& shape) const; private: boolNDArray nhood; NDArray height; octave_idx_type nnz; Array origin; dim_vector size; octave_idx_type ndims; std::vector decomposition; void ini_ctor (void); Array default_origin (void); void end_ctor (void); void validate_origin (void); }; } } // Define it on header or we we need to instantiate it for all // possible classes in strel.cc template Array

octave::image::strel::true_heights (void) const { Array

true_heights (dim_vector (nnz, 1)); for (octave_idx_type ind = 0, found = 0; found < nnz; ind++) if (nhood(ind)) true_heights(found++) = height(ind); return true_heights; } #endif image-2.4.1/src/PaxHeaders.6632/strel.cc0000644000000000000000000000013212561122761014507 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/strel.cc0000644000175000017500000002302012561122761017327 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2013 Carnë Draug // // 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 3 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 . // This is wrapper class for the @strel class so that it can be used by // the rest of the image package using SE's. It's not a perfect wrapper // on purpose. For example, the reflect method behaves kinda weird for // matlab compatibility. In here we try to make a bit more sense. #include "strel.h" #include #include // gives us feval so we can use @strel #include #include // Constructors // Expects a @strel object, or a boolean matrix (or something // that can be converted into one with bool_matrix_value() octave::image::strel::strel (const octave_value& arg) { octave_value se = arg; // We are only creating a strel object here so that we can use // getsequence which tries to guess a shape to decompose. In // the cases where we don't get a @strel object we could also: // // 1) don't do any automatic decomposition, use the matrix as // it is. // 2) implement the guessing in C++ and make a oct file for it. // If we don't have a strel object, then make one. if (se.class_name () != "strel") { octave_value_list strel_args (2); strel_args(0) = "arbitrary"; strel_args(1) = se; // We are leaving the input check up to @strel se = feval ("strel", strel_args)(0); if (error_state) return; } nhood = feval ("getnhood", se)(0).bool_array_value (); height = feval ("getheight", se)(0).array_value (); ini_ctor (); origin = default_origin (); const octave_value se_seq = feval ("getsequence", se)(0); const octave_idx_type seq_numel = feval ("numel", se_seq)(0).idx_type_value (); // This is to emulate the strel_obj(idx) syntax in function form static const char *fields[] = {"type", "subs", 0}; octave_scalar_map ref = octave_scalar_map (string_vector (fields)); ref.setfield ("type", octave_value ("()")); octave_value_list subsref_args (2); subsref_args(0) = se_seq; if (seq_numel > 1) { for (octave_idx_type subs = 0; subs < seq_numel; subs++) { // subs+1 because octave is index base 1 ref.setfield ("subs", Cell (octave_value (subs+1))); subsref_args(1) = ref; // Equivalent to "selem = strel_obj(subs)" const octave_value_list elem = feval ("subsref", subsref_args)(0); const boolNDArray elem_nhood = feval ("getnhood", elem)(0).bool_array_value (); const NDArray elem_height = feval ("getheight", elem)(0).array_value (); decomposition.push_back (strel (elem_nhood, elem_height)); } } end_ctor (); return; } octave::image::strel::strel (const boolNDArray& nhood, const NDArray& height) : nhood (nhood), height (height) { ini_ctor (); origin = default_origin (); end_ctor (); return; } octave::image::strel::strel (const boolNDArray& nhood, const NDArray& height, const Array& origin) : nhood (nhood), height (height), origin (origin) { ini_ctor (); validate_origin (); end_ctor (); return; } boolNDArray octave::image::strel::get_nhood (void) const { return nhood; } octave_idx_type octave::image::strel::get_nnz (void) const { return nnz; } Array octave::image::strel::get_origin (void) const { return origin; } octave::image::strel octave::image::strel::operator () (const octave_idx_type& i) const { assert (i >= 0 && i < octave_idx_type (decomposition.size ())); return decomposition[i]; } // Number of strel elements after decomposition octave_idx_type octave::image::strel::numel (void) const { return octave_idx_type (decomposition.size ()); } // Pretty much rotates the matrix by 180 degrees in all dimensions. The // only tricky thing that we doo it purpose is that the origin is also // rotated. For example, if the origin is set to the bottom right point, // after refleection it will be in the top left. If the origin is at the // center of the matrix, there will be no change. // The reason for this is so that we can keep the origin in matrices with // sides with an even length. octave::image::strel octave::image::strel::reflect (void) const { boolNDArray ref_nhood (size); NDArray ref_height (size); const octave_idx_type numel = nhood.numel (); for (octave_idx_type ind = 0; ind < numel; ind++) { ref_nhood(ind) = nhood(numel - ind -1); ref_height(ind) = height(numel - ind -1); } Array ref_origin (origin); for (octave_idx_type dim = 0; dim < ndims; dim++) ref_origin(dim) = size(dim) - origin(dim) -1; return octave::image::strel (ref_nhood, ref_height, ref_origin); } void octave::image::strel::set_origin (const Array& sub) { origin = sub; validate_origin (); return; } bool octave::image::strel::flat (void) const { bool flat = true; if (! height.all_elements_are_zero ()) { const octave_idx_type numel = height.numel (); for (octave_idx_type ind = 0; ind < numel; ind++) { if (height(ind)) { flat = false; break; } } } return flat; } // For any given point in the input matrix, calculates the memory offset for // all the others that will have an effect on the erosion and dilation with it. // How much we need to shift the input matrix to cover the nnz of the SE. // That is, how many elements away is each nnz of the SE, for any element // of the input matrix. Given a 10x10 input matrix (cumulative dimensions // of [10 100]), and a SE with: // [1 0 0 // 1 1 1 // 0 0 1] // linear shift is [0 1 11 21 22] // The second element is the matching height for each. Array octave::image::strel::offsets (const dim_vector& cum_size) const { Array sub (dim_vector (ndims, 1), 0); Array offsets (dim_vector (nnz, 1)); for (octave_idx_type found = 0; found < nnz; boolNDArray::increment_index (sub, size)) { if (nhood(sub)) { offsets(found) = sub(0); for (octave_idx_type dim = 1; dim < ndims; dim++) offsets(found) += cum_size(dim-1) * sub(dim); found++; } } return offsets; } // The final size of the output matrix will be the size of the input // matrix, plus the size of the SE, less its center. Consider a square SE // at the corner of the input matrix. The origin (center) of the SE will be // at coordinates (0,0) of the input matrix and we need enough padding for // it. If the shape is "full", then we add the double. Array octave::image::strel::pre_pad (const octave_idx_type& mt_ndims, const std::string& shape) const { Array pad (dim_vector (mt_ndims, 1), 0); octave_idx_type pad_times; if (shape == "valid") return pad; else if (shape == "same") pad_times = 1; else if (shape == "full") pad_times = 2; else { error ("invalid SHAPE"); error_state = 1; return Array (); } Array resized_origin (origin); dim_vector resized_size (size); if (ndims < mt_ndims) { resized_origin.resize (dim_vector (mt_ndims, 1), 0); resized_size.resize (mt_ndims, 1); } for (octave_idx_type dim = 0; dim < mt_ndims; dim++) pad(dim) = resized_origin(dim) * pad_times; return pad; } Array octave::image::strel::post_pad (const octave_idx_type& mt_ndims, const std::string& shape) const { Array pad (dim_vector (mt_ndims, 1), 0); octave_idx_type pad_times; if (shape == "valid") return pad; else if (shape == "same") pad_times = 1; else if (shape == "full") pad_times = 2; else { error ("invalid SHAPE"); error_state = 1; return Array (); } Array resized_origin (origin); dim_vector resized_size (size); if (ndims < mt_ndims) { resized_origin.resize (dim_vector (mt_ndims, 1), 0); resized_size.resize (mt_ndims, 1); } for (octave_idx_type dim = 0; dim < mt_ndims; dim++) pad(dim) = (resized_size(dim) - resized_origin(dim) -1) * pad_times; return pad; } void octave::image::strel::ini_ctor () { size = nhood.dims (); ndims = nhood.ndims (); nnz = nhood.nnz (); return; } Array octave::image::strel::default_origin () { Array origin (dim_vector (ndims, 1)); for (octave_idx_type dim = 0; dim < ndims; dim++) origin(dim) = floor ((size(dim) +1) /2) -1; // -1 for zero based indexing return origin; } void octave::image::strel::end_ctor (void) { if (decomposition.empty ()) decomposition.push_back (*this); } void octave::image::strel::validate_origin (void) { assert (ndims == origin.numel ()); for (octave_idx_type dim = 0; dim < ndims; dim++) assert (origin(dim) >= 0 && origin(dim) < size(dim)); return; } image-2.4.1/src/PaxHeaders.6632/imreconstruct.cc0000644000000000000000000000013212561122761016257 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/imreconstruct.cc0000644000175000017500000004042412561122761021106 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2014 Carnë Draug // // 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 3 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 // . // This file implements imreconstruct as described on "Vincent, L. (1993). // Morphological grayscale reconstruction in image analysis: applications // and efficient algorithms. Image Processing, IEEE Transactions on, 2(2), // 176-201." // // Our strategy to handle elements in the border is to simply pad it with // the lowest value for the type, which will be ignored on the comparisons. // This should still be more efficient than using subscript indices to find // when we are on the border. #include #include #include #include // xmin() #include "connectivity.h" using namespace octave::image; /* ## A dirty implementation of the fast hybrid reconstruction as m file ## for testing purposes. function marker = fast_hybrid_reconstruction (marker, mask) ## works for 10x10 matrices, padded to 12x12 with zeros, when ## connectivity is ones (3, 3) offsets = [-13 -12 -11 -1 1 11 12 13]; pos_offsets = [0 1 11 12 13]; # don't forget the zero neg_offsets = - [pos_offsets]; ## the raster scan for c = 2:(columns(marker) -1) for r = 2:(rows(marker) -1) i = sub2ind (size (marker), r, c); marker(r,c) = min (mask(r,c), max (marker(i + [neg_offsets]))); endfor endfor ## the antiraster scan fifo = []; for c = (columns(marker) -1):-1:2 for r = (rows(marker) -1):-1:2 i = sub2ind (size (marker), r, c); offs = marker(i + [pos_offsets]); marker(r,c) = min (mask(r,c), max (offs)); offs(1) = []; #remove itself picks = offs < marker(i) & offs < mask(i + [pos_offsets(2:end)]); if (any (picks)) fifo(end+1) = i; endif endfor endfor ## the propagation step while (numel (fifo) != 0) p = fifo(1); fifo(1) = []; for i = offsets; if (marker(p +i) < marker(p) && mask(p+i) != marker(p+i)) marker(p +i) = min (marker(p), mask(p+i)); fifo(end+1) = p+i; endif endfor endwhile endfunction */ template static void scan_raster_order (T& padded_marker, const T& padded_mask, const dim_vector& original_size, const Array& padding_lengths, const Array& raster_neighbours) { typedef typename T::element_type P; P* J = padded_marker.fortran_vec (); const P* I = padded_mask.fortran_vec (); const octave_idx_type* pads = padding_lengths.fortran_vec (); const octave_idx_type* neighbours = raster_neighbours.fortran_vec (); const octave_idx_type n_neighbours = raster_neighbours.numel (); // We probably should not be using this but converting to Array // just to have fortran_vec seems a bit too much. const octave_idx_type* s = original_size.to_jit (); std::function scan; scan = [&] (const octave_idx_type dim) -> void { J += pads[dim]; I += pads[dim]; if (dim == 0) { for (octave_idx_type k = 0; k < s[0]; k++, J++, I++) { for (octave_idx_type i = 0; i < n_neighbours; i++) if (*J < J[neighbours[i]]) *J = J[neighbours[i]]; if (*J > *I) *J = *I; } } else for (octave_idx_type i = 0; i < s[dim]; i++) scan (dim-1); J += pads[dim]; I += pads[dim]; return; }; scan (original_size.length () -1); return; } template static std::queue scan_antiraster_order (T& padded_marker, const T& padded_mask, const dim_vector& original_size, const Array& padding_lengths, const Array& antiraster_neighbours) { typedef typename T::element_type P; std::queue unfinished; P* J = padded_marker.fortran_vec (); const P* I = padded_mask.fortran_vec (); const octave_idx_type* pads = padding_lengths.fortran_vec (); const octave_idx_type* neighbours = antiraster_neighbours.fortran_vec (); const octave_idx_type n_neighbours = antiraster_neighbours.numel (); // We probably should not be using this but converting to Array // just to have fortran_vec seems a bit too much. const octave_idx_type* s = original_size.to_jit (); J += padded_marker.numel () -1; I += padded_marker.numel () -1; octave_idx_type ind = padded_marker.numel () -1; std::function scan; scan = [&] (const octave_idx_type dim) -> void { J -= pads[dim]; I -= pads[dim]; ind -= pads[dim]; if (dim == 0) { for (octave_idx_type k = 0; k < s[0]; k++, J--, I--, ind--) { for (octave_idx_type i = 0; i < n_neighbours; i++) if (*J < J[neighbours[i]]) *J = J[neighbours[i]]; if (*J > *I) *J = *I; for (octave_idx_type i = 0; i < n_neighbours; i++) if (J[neighbours[i]] < *J && J[neighbours[i]] < I[neighbours[i]]) unfinished.push (ind); } } else for (octave_idx_type i = 0; i < s[dim]; i++) scan (dim-1); J -= pads[dim]; I -= pads[dim]; ind -= pads[dim]; return; }; scan (original_size.length () -1); return unfinished; } template static void propagation_step (T& padded_marker, const T& padded_mask, std::queue& unfinished, const Array& deleted_neighbours) { typedef typename T::element_type P; P* J = padded_marker.fortran_vec (); const P* I = padded_mask.fortran_vec (); const octave_idx_type* neighbours = deleted_neighbours.fortran_vec (); const octave_idx_type n_neighbours = deleted_neighbours.numel (); while (! unfinished.empty ()) { octave_idx_type p = unfinished.front (); unfinished.pop (); for (octave_idx_type k = 0; k < n_neighbours; k++) { octave_idx_type q = p + neighbours[k]; if (J[q] < J[p] && I[q] != J[q]) { J[q] = xmin (J[p], I[q]); unfinished.push (q); } } OCTAVE_QUIT; } return; } template static T fast_hybrid_reconstruction (const T& marker, const T& mask, const connectivity& conn) { typedef typename T::element_type P; const P* Ju = marker.fortran_vec (); const P* Iu = mask.fortran_vec (); for (octave_idx_type i = 0; i < marker.numel (); i++) if (*Ju++ > *Iu++) { error ("imreconstruct: MARKER must be less or equal than MASK"); return T (); } const dim_vector original_size = marker.dims (); T padded_marker = conn.create_padded (marker, connectivity::min_value

()); const T padded_mask = conn.create_padded (mask, connectivity::min_value

()); const dim_vector padded_size = padded_marker.dims (); const Array padding_lengths = connectivity::padding_lengths (original_size, padded_size); scan_raster_order (padded_marker, padded_mask, original_size, padding_lengths, conn.negative_neighbourhood (padded_size)); OCTAVE_QUIT; std::queue unfinished = scan_antiraster_order (padded_marker, padded_mask, original_size, padding_lengths, conn.positive_neighbourhood (padded_size)); OCTAVE_QUIT; propagation_step (padded_marker, padded_mask, unfinished, conn.deleted_neighbourhood (padded_size)); conn.unpad (padded_marker); return padded_marker; } template static T reconstruct (const T& marker, const T& mask, const connectivity& conn) { return fast_hybrid_reconstruction (marker, mask, conn); } // TODO implement the following by reusing the code in bwlabeln //static boolNDArray //reconstruct (const boolNDArray& marker, const boolNDArray& mask, // const connectivity& conn) //{ // /* // 1. Label the connected components of the mask image, i.e., each of these // components is assigned a unique number. Note that this step can itself // be implemented very efficiently by using algorithms based on chain an // loops [16] or queues of pixels [23, 26]. // 2. Determine the labels of the connected components which contain at // least a pixel of the marker image. // 3. Remove all the connected components whose label is not one of the // previous ones. // */ // return boolNDArray (); //} DEFUN_DLD(imreconstruct, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} imreconstruct (@var{marker}, @var{mask})\n\ @deftypefnx {Loadable Function} {} imreconstruct (@var{marker}, @var{mask}, @var{conn})\n\ \n\ @seealso{imclearborder, imdilate, imerode}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 2 || nargin > 3) { print_usage (); return octave_value_list (); } if (args(0).class_name () != args(1).class_name ()) { error ("imreconstruct: MARKER and MASK must be of same class"); return octave_value_list (); } connectivity conn; if (nargin > 2) { try { conn = connectivity (args(2)); } catch (invalid_connectivity& e) { error ("imreconstruct: CONN %s", e.what ()); return octave_value_list (); } } else { try { conn = connectivity (args(0).ndims (), "maximal"); } catch (invalid_connectivity& e) { error ("imreconstruct: unable to create connectivity"); return octave_value_list (); } } #define IF_TYPE(TYPE) \ if (args (0).is_ ## TYPE ## _type ()) \ ret = reconstruct (args(0).TYPE ## _array_value (), \ args(1).TYPE ## _array_value (), conn); #define INT_BRANCH(TYPE) \ IF_TYPE(u ## TYPE) \ else IF_TYPE(TYPE) #define FLOAT_BRANCH(CR) \ if (args(0).is_single_type ()) \ ret = reconstruct (args(0).float_ ## CR ## array_value (), \ args(1).float_ ## CR ## array_value (), conn); \ else \ ret = reconstruct (args(0).CR ## array_value (), \ args(1).CR ## array_value (), conn); octave_value ret; IF_TYPE (bool) else INT_BRANCH (int8) else INT_BRANCH (int16) else INT_BRANCH (int32) else INT_BRANCH (int64) else if (args(0).is_real_type ()) { FLOAT_BRANCH() } else if (args(0).is_complex_type ()) { FLOAT_BRANCH(complex_) } else error ("imreconstruct: unsupported class %s for MARKER", args(0).class_name ().c_str ()); #undef IF_TYPE #undef INT_BRANCH #undef FLOAT_BRANCH return ret; } /* ## When using the fast hybrid reconstruction (and specially with random ## images), and if the images are small, it is often finished after the ## antiraster scan and before the propagation step. Using larger images ## makes sure we get in the propagation step and that we catch bugs in there. ## This function does exactly what imreconstruct is meant to but is, in ## the words of Luc Vicent 1993, and I can attest to it, "[...] not suited ## to conventional computers, where its execution time is often of several ## minutes." %!function recon = parallel_reconstruction (marker, mask, %! conn = conndef (ndims (marker), "maximal")) %! do %! previous = marker; %! marker = imdilate (marker, conn); %! ## FIXME https://savannah.gnu.org/bugs/index.php?43712 %! if (strcmp (class (marker), "logical")) %! marker = marker & mask; %! else %! marker = min (marker, mask); %! endif %! until (all ((marker == previous)(:))) %! recon = marker; %!endfunction %!test %! for cl = {"int8", "uint8", "int16", "uint16", "int32", "uint32"} %! cl = cl{1}; %! a = randi ([intmin(cl) intmax(cl)-30], 100, 100, cl); %! b = a + randi (20, 100, 100, cl); %! assert (imreconstruct (a, b), parallel_reconstruction (a, b)) %! endfor %! for cl = {"double", "single"} %! cl = cl{1}; %! a = (rand (100, 100, cl) - 0.5) .* 1000; %! b = a + rand (100, 100, cl) * 100; %! assert (imreconstruct (a, b), parallel_reconstruction (a, b)) %! endfor %!test %! for cl = {"int8", "uint8", "int16", "uint16", "int32", "uint32"} %! cl = cl{1}; %! a = randi ([intmin(cl) intmax(cl)-30], 100, 100, cl); %! b = a + randi (20, 100, 100, cl); %! c = [0 1 0; 1 1 1; 0 1 0]; %! assert (imreconstruct (a, b, c), parallel_reconstruction (a, b, c)) %! endfor %!test %! a = randi (210, 100, 100); %! b = a + randi (20, 100, 100); %! c = ones (3, 1); %! assert (imreconstruct (a, b, c), parallel_reconstruction (a, b, c)) %!test %! a = randi (210, 500, 500, 10, 4); %! b = a + randi (20, 500, 500, 10, 4); %! c = ones (3, 3, 3); %! assert (imreconstruct (a, b, c), parallel_reconstruction (a, b, c)) %!test %! a = randi (210, 500, 500, 10, 4); %! b = a + randi (20, 500, 500, 10, 4); %! c = conndef (4, "minimal"); %! assert (imreconstruct (a, b, c), parallel_reconstruction (a, b, c)) %!test %! a = [ 0 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 0 0 1 0 0 %! 1 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 1 0 0 %! 0 0 0 0 0 0 1 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 1 0 0 0 0 0 %! 0 0 0 0 0 0 0 1 0 0]; %! %! b = [ 0 1 0 0 0 0 0 1 1 0 %! 1 1 0 0 0 1 0 1 1 0 %! 1 1 0 0 1 0 0 0 0 0 %! 1 1 0 0 0 1 1 0 0 0 %! 1 0 0 0 0 0 1 1 0 0 %! 0 1 0 0 0 0 1 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 1 0 0 0 1 0 0 1 0 1]; %! %! c = [ 0 1 0 0 0 0 0 1 1 0 %! 1 1 0 0 0 1 0 1 1 0 %! 1 1 0 0 1 0 0 0 0 0 %! 1 1 0 0 0 1 1 0 0 0 %! 1 0 0 0 0 0 1 1 0 0 %! 0 1 0 0 0 0 1 1 0 0 %! 0 0 0 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 0 1 0 0 1 0 0]; %! assert (imreconstruct (logical (a), logical (b)), logical (c)); %! %! c = [ 0 1 0 0 0 0 0 1 1 0 %! 1 1 0 0 0 0 0 1 1 0 %! 1 1 0 0 0 0 0 0 0 0 %! 1 1 0 0 0 1 1 0 0 0 %! 1 0 0 0 0 0 1 1 0 0 %! 0 0 0 0 0 0 1 1 0 0 %! 0 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 1 1 0 0 0 0 %! 0 0 0 1 1 0 0 0 0 0 %! 0 0 0 0 1 0 0 1 0 0]; %! assert (imreconstruct (logical (a), logical (b), [0 1 0; 1 1 1; 0 1 0]), %! logical (c)); %!test %! do %! b = rand (100, 100, 100) > 0.98; %! until (nnz (b) > 4) %! b = imdilate (b, ones (5, 5, 5)); %! a = false (size (b)); %! f = find (b); %! a(f(randi (numel (f), 6, 1))) = true; %! assert (imreconstruct (a, b), parallel_reconstruction (a, b)) ## we try to be smart about the padding so make sure this works. There ## was a nasty bug during development which this test brings up. %!test %! a = randi (200, 100,100, 10, 10); %! b = a + randi (20, 100,100, 10, 10); %! c1 = ones (3, 3, 3); %! c2 = zeros (3, 3, 3, 3); %! c2(:,:,:,2) = c1; %! assert (imreconstruct (a, b, c1), imreconstruct (a, b, c2)) %!error imreconstruct (randi([5 10], [10 10]), randi([1 5], [10 10])) */ image-2.4.1/src/PaxHeaders.6632/hough_line.cc0000644000000000000000000000013212561122761015477 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/hough_line.cc0000644000175000017500000000755112561122761020332 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2004 Stefan van der Walt // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1 Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2 Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include DEFUN_DLD(hough_line, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{H}, @var{R}] =} hough_line(@var{I}, @var{angles})\n\ Calculate the straight line Hough transform of a binary image @var{I}.\n\ \n\ The angles are given in degrees and defaults to -90:90.\n\ \n\ @var{H} is the resulting Hough transform, and @var{R} is the radial distances.\n\ \n\ The algorithm is described in\n\ Digital Image Processing by Gonzales & Woods (2nd ed., p. 587)\n\ @end deftypefn\n\ ") { octave_value_list retval; const int nargin = args.length (); const bool DEF_THETA = (nargin == 1); if (1 > nargin || nargin > 2) { print_usage (); return retval; } const Matrix I = args (0).matrix_value (); const ColumnVector thetas = (DEF_THETA) ? ColumnVector (Range (-M_PI/2.0, M_PI/2.0, M_PI/180.0).matrix_value ()) : ColumnVector (args (1).vector_value ()); if (error_state) { print_usage (); return retval; } const int r = I.rows (); const int c = I.columns (); const int thetas_length = thetas.length (); Matrix size (1, 2); size (0) = r; size (1) = c; const double diag_length = sqrt (size.sumsq ()(0)); const int nr_bins = 2 * (int)ceil (diag_length) - 1; RowVector bins = RowVector (Range(1, nr_bins).matrix_value ()) - ceil (nr_bins/2.0); const int bins_length = bins.length (); Matrix J (bins_length, thetas_length, 0.0); for (int i = 0; i < thetas_length; i++) { const double theta = thetas (i); const double cT = cos (theta); const double sT = sin (theta); for (int x = 0; x < r; x++) { for (int y = 0; y < c; y++) { if (I(x, y) == 1) { const int rho = (int)floor (cT*x + sT*y + 0.5); const int bin = (int)(rho - bins (0)); if ((bin > 0) && (bin < bins_length)) J (bin, i)++; } } } } retval.append (J); retval.append (bins); return retval; } /* %!test %! I = zeros(100, 100); %! I(1,1) = 1; I(100,100) = 1; I(1,100) = 1; I(100, 1) = 1; I(50,50) = 1; %! [J, R] = houghtf(I); J = J / max(J(:)); %! assert(size(J) == [length(R) 181]); %! %!demo %! I = zeros(100, 150); %! I(30,:) = 1; I(:, 65) = 1; I(35:45, 35:50) = 1; %! for i = 1:90, I(i,i) = 1;endfor %! I = imnoise(I, 'salt & pepper'); %! imshow(I); %! J = houghtf(I); J = J / max(J(:)); %! imshow(J, bone(128), 'truesize'); */ image-2.4.1/src/PaxHeaders.6632/configure0000644000000000000000000000013212561122763014755 xustar0030 mtime=1438950899.338252237 30 atime=1438950899.298252237 30 ctime=1438950899.342252237 image-2.4.1/src/configure0000755000175000017500000032056312561122763017614 0ustar00carandraugcarandraug00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Octave-Forge image package 2.4.1. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Octave-Forge image package' PACKAGE_TARNAME='octave-forge-image-package' PACKAGE_VERSION='2.4.1' PACKAGE_STRING='Octave-Forge image package 2.4.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_subst_vars='LTLIBOBJS LIBOBJS HAVE_CXX11 OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Octave-Forge image package 2.4.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/octave-forge-image-package] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Octave-Forge image package 2.4.1:";; esac cat <<\_ACEOF Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Octave-Forge image package configure 2.4.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Octave-Forge image package $as_me 2.4.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ax_cxx_compile_cxx11_required=true ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 $as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } if ${ax_cv_cxx_compile_cxx11+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ax_cv_cxx_compile_cxx11=yes else ax_cv_cxx_compile_cxx11=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 $as_echo "$ax_cv_cxx_compile_cxx11" >&6; } if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 $as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } if eval \${$cachevar+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval $cachevar=yes else eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CXXFLAGS="$ac_save_CXXFLAGS" fi eval ac_res=\$$cachevar { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 $as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } if eval \${$cachevar+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = [](){}; _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval $cachevar=yes else eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CXXFLAGS="$ac_save_CXXFLAGS" fi eval ac_res=\$$cachevar { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 fi else if test x$ac_success = xno; then HAVE_CXX11=0 { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 $as_echo "$as_me: No compiler with C++11 support was found" >&6;} else HAVE_CXX11=1 $as_echo "#define HAVE_CXX11 1" >>confdefs.h fi fi ## Test for gcc bug #65843 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65843 ## which shows up as Octave bug #45096 https://savannah.gnu.org/bugs/?45096 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether templated lambda functions accept '&const int'" >&5 $as_echo_n "checking whether templated lambda functions accept '&const int'... " >&6; } if ${_cv_template_lambda_accepts_ref_const_inst+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ template void test (T b) { const int a = b; [&] () { return a, a; }(); } int main () { test (1); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : _cv_template_lambda_accepts_ref_const_inst=yes else _cv_template_lambda_accepts_ref_const_inst=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_cv_template_lambda_accepts_ref_const_inst" >&5 $as_echo "$_cv_template_lambda_accepts_ref_const_inst" >&6; } if test $_cv_template_lambda_accepts_ref_const_inst = no; then as_fn_error $? " Your C++ compiler (are you using GCC 5.0 or 5.1?) has a bug that prevents it from building the Octave Forge image package. But you can fix it very easily. See https://savannah.gnu.org/bugs/?45096 for details on working around it. " "$LINENO" 5 fi ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Octave-Forge image package $as_me 2.4.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Octave-Forge image package config.status 2.4.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi image-2.4.1/src/PaxHeaders.6632/rotate_scale.cc0000644000000000000000000000013212561122761016023 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/rotate_scale.cc0000644000175000017500000001351112561122761020647 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2003 Andy Adler // // 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 3 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 . /* * ROTATE_SCALE: rotate and scale a matrix using bilinear interpolation * imo= block(im, xregs, yregs); */ #include void calc_rotation_params( double x0l,double y0l,double x0r,double y0r, double x1l,double y1l,double x1r,double y1r, double* Tx_x, double* Ty_x, double* Tx_y, double* Ty_y, double* Tx_1, double* Ty_1 ); void do_interpolation ( double Tx_x, double Ty_x, double Tx_y, double Ty_y, double Tx_1, double Ty_1, int x0max, int y0max,// initial size int x1max, int y1max,// output size const double * img0, double * img1 ); DEFUN_DLD (rotate_scale, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{im1} =} rotate_scale(@var{im0}, @var{lm0}, @var{lm1}, @var{out_size})\n\ Arbitrary rotation and scaling of a gray-scale image using fast bilinear interpolation.\n\ \n\ The image @var{im0} will be rotated and scaled such that the landmark points in\n\ @var{lm0} in the image will be placed in the landmark points in @var{lm1} in\n\ the output image @var{im1}. The landmark points are given as a 2 by 2 matrix\n\ where the first row contains the x-coordinates of the landmarks, and the second\n\ row contains the y-coordinates.\n\ \n\ The size of the output image is given in the vector @var{out_size}.\n\ \n\ The following example shows basic usage of the function\n\ @example\n\ im0 = zeros(100); im0(25:75, 25:75)=1;\n\ im1 = rotate_scale( im0, [40,60; 50,50], [60,90; 60,90], [120,120]);\n\ @end example\n\ @seealso{imrotate, imresize}\n\ @end deftypefn\n\ ") { octave_value_list retval; if (args.length() < 4 || !args(0).is_matrix_type() || !args(1).is_matrix_type() || !args(2).is_matrix_type() || !args(3).is_matrix_type() ) { print_usage (); return retval; } Matrix im0( args(0).matrix_value() ); const double * im0p = im0.data(); Matrix lm0( args(1).matrix_value() ); Matrix lm1( args(2).matrix_value() ); ColumnVector out_size( args(3).vector_value() ); int inp_hig= im0.rows(); int inp_wid= im0.cols(); int out_hig= (int) out_size(0); int out_wid= (int) out_size(1); Matrix im1( out_hig, out_wid); double * im1p = im1.fortran_vec(); double Tx_x; double Ty_x; double Tx_y; double Ty_y; double Tx_1; double Ty_1; calc_rotation_params( lm0(0,0), lm0(1,0), lm0(0,1), lm0(1,1), lm1(0,0), lm1(1,0), lm1(0,1), lm1(1,1), & Tx_x, & Ty_x, & Tx_y, & Ty_y, & Tx_1, & Ty_1 ); do_interpolation( Tx_x, Ty_x, Tx_y, Ty_y, Tx_1, Ty_1, inp_wid, inp_hig, out_wid, out_hig, im0p, im1p ); retval(0) = im1; return retval; } inline double sqr(double a) { return (a)*(a); } void calc_rotation_params( double x1l,double y1l,double x1r,double y1r, double x0l,double y0l,double x0r,double y0r, double* Tx_x, double* Ty_x, double* Tx_y, double* Ty_y, double* Tx_1, double* Ty_1 ) { double d0= sqrt( sqr(x0l-x0r) + sqr(y0l-y0r) ); double d1= sqrt( sqr(x1l-x1r) + sqr(y1l-y1r) ); double dr= d1/d0; double a0= atan2( y0l-y0r , x0l-x0r ); double a1= atan2( y1l-y1r , x1l-x1r ); double ad= a1-a0; double dr_cos_ad= dr*cos(ad); double dr_sin_ad= dr*sin(ad); double x0m= (x0l+x0r)/2; double y0m= (y0l+y0r)/2; double x1m= (x1l+x1r)/2; double y1m= (y1l+y1r)/2; *Tx_x= dr_cos_ad; *Ty_x= dr_sin_ad; *Tx_y= -dr_sin_ad; *Ty_y= dr_cos_ad; *Tx_1= x1m - dr_cos_ad*x0m + dr_sin_ad*y0m; *Ty_1= y1m - dr_sin_ad*x0m - dr_cos_ad*y0m; } void do_interpolation ( double Tx_x, double Ty_x, double Tx_y, double Ty_y, double Tx_1, double Ty_1, int x0max, int y0max,// initial size int x1max, int y1max,// output size const double * img0, double * img1 ) { for (int i=0; i< x1max; i++) { for (int j=0; j< y1max; j++) { double x0i= Tx_x * i + Tx_y * j + Tx_1; double y0i= Ty_x * i + Ty_y * j + Ty_1; if ( x0i < 0 ) x0i= 0; else if (x0i >= x0max-1 ) x0i= x0max - 1.00001; if ( y0i < 0 ) y0i= 0; else if (y0i >= y0max-1 ) y0i= y0max - 1.00001; int x0idx= (int) x0i; int y0idx= (int) y0i; double frac_r= x0i- x0idx; double frac_l= 1 - frac_r; double frac_d= y0i- y0idx; double frac_u= 1 - frac_d; int pix_lu= (y0idx+0) + (x0idx+0) * y0max ; int pix_ru= (y0idx+0) + (x0idx+1) * y0max ; int pix_ld= (y0idx+1) + (x0idx+0) * y0max ; int pix_rd= (y0idx+1) + (x0idx+1) * y0max ; img1[ i*y1max + j ]= frac_l*frac_u* img0[ pix_lu ] + frac_r*frac_u* img0[ pix_ru ] + frac_l*frac_d* img0[ pix_ld ] + frac_r*frac_d* img0[ pix_rd ]; } } } image-2.4.1/src/PaxHeaders.6632/__bilateral__.cc0000644000000000000000000000013212561122761016111 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/src/__bilateral__.cc0000644000175000017500000001335512561122761020743 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2008 Søren Hauberg // // 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 3 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 . #include inline double gauss (const double *x, const double *mu, const double sigma, const octave_idx_type ndims) { double s = 0; for (octave_idx_type i = 0; i < ndims; i++) { const double d = x[i] - mu[i]; s += d*d; } return exp (-0.5*s/(sigma*sigma)); } template octave_value bilateral (const MatrixType &im, const double sigma_d, const double sigma_r) { // Get sizes const octave_idx_type ndims = im.ndims (); const dim_vector size = im.dims (); const octave_idx_type num_planes = (ndims == 2) ? 1 : size (2); // Build spatial kernel const int s = std::max ((int)xround (3*sigma_d), 1); Matrix kernel (2*s+1, 2*s+1); for (octave_idx_type r = 0; r < 2*s+1; r++) { for (octave_idx_type c = 0; c < 2*s+1; c++) { const int dr = r-s; const int dc = c-s; kernel (r,c) = exp (-0.5 * (dr*dr + dc*dc)/(sigma_d*sigma_d)); } } // Allocate output dim_vector out_size (size); out_size (0) = std::max (size (0) - 2*s, (octave_idx_type)0); out_size (1) = std::max (size (1) - 2*s, (octave_idx_type)0); MatrixType out = MatrixType (out_size); // Iterate over every element of 'out'. for (octave_idx_type r = 0; r < out_size (0); r++) { for (octave_idx_type c = 0; c < out_size (1); c++) { OCTAVE_QUIT; // For each neighbour OCTAVE_LOCAL_BUFFER (double, val, num_planes); OCTAVE_LOCAL_BUFFER (double, sum, num_planes); double k = 0; for (octave_idx_type i = 0; i < num_planes; i++) { val[i] = im (r+s,c+s,i); sum[i] = 0; } for (octave_idx_type kr = 0; kr < 2*s+1; kr++) { for (octave_idx_type kc = 0; kc < 2*s+1; kc++) { OCTAVE_LOCAL_BUFFER (double, lval, num_planes); for (octave_idx_type i = 0; i < num_planes; i++) lval[i] = im (r+kr, c+kc, i); const double w = kernel (kr, kc) * gauss (val, lval, sigma_r, num_planes); for (octave_idx_type i = 0; i < num_planes; i++) sum[i] += w * lval[i]; k += w; } } for (octave_idx_type i = 0; i < num_planes; i++) out (r, c, i) = sum[i]/k; } } return octave_value (out); } DEFUN_DLD (__bilateral__, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} __bilateral__(@var{im}, @var{sigma_d}, @var{sigma_r})\n\ Performs Gaussian bilateral filtering in the image @var{im}. @var{sigma_d} is the\n\ spread of the Gaussian used as closenes function, and @var{sigma_r} is the spread\n\ of Gaussian used as similarity function. This function is internal and should NOT\n\ be called directly. Instead use @code{imsmooth}.\n\ @end deftypefn\n\ ") { octave_value_list retval; if (args.length () != 3) { print_usage (); return retval; } const octave_idx_type ndims = args (0).ndims (); if (ndims != 2 && ndims != 3) { error ("__bilateral__: only 2 and 3 dimensional is supported"); return retval; } const double sigma_d = args (1).scalar_value (); const double sigma_r = args (2).scalar_value (); if (error_state) { error("__bilateral__: invalid input"); return retval; } // Take action depending on input type if (args (0).is_real_matrix ()) { const NDArray im = args(0).array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_int8_type ()) { const int8NDArray im = args (0).int8_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_int16_type ()) { const int16NDArray im = args (0).int16_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_int32_type ()) { const int32NDArray im = args (0).int32_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_int64_type ()) { const int64NDArray im = args (0).int64_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_uint8_type ()) { const uint8NDArray im = args (0).uint8_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args(0).is_uint16_type()) { const uint16NDArray im = args (0).uint16_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_uint32_type ()) { const uint32NDArray im = args (0).uint32_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else if (args (0).is_uint64_type ()) { const uint64NDArray im = args (0).uint64_array_value (); retval = bilateral (im, sigma_d, sigma_r); } else { error ("__bilateral__: first input should be a real or integer array"); return retval; } return retval; } image-2.4.1/src/PaxHeaders.6632/__boundary__.cc0000644000000000000000000000013212561122761015775 xustar0030 mtime=1438950897.782252238 30 atime=1438950897.782252238 30 ctime=1438950899.342252237 image-2.4.1/src/__boundary__.cc0000644000175000017500000001311112561122761020615 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2010 Andrew Kelly, IPS Radio & Space Services // // 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 3 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 . /** * Oct-file to trace the boundary of an object in a binary image. * * b = boundary(region, conn=8) */ #include #include using namespace std; DEFUN_DLD(__boundary__, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} boundary(@var{region})\n\ @deftypefnx {Loadable Function} {} boundary(@var{region}, @var{conn})\n\ Trace the boundary of an object in a binary image.\n\ \n\ @code{boundary} computes the exterior clockwise boundary of the single \ @var{conn}-connected object represented by the non-zero pixels \ of @var{region}. It uses an algorithm based on Moore-neighbour tracing.\n\ \n\ @var{conn} can be either 8 (the default) or 4.\n\ \n\ @var{b} is an N-by-2 matrix containing the row/column coordinates of points \ on the boundary. The first boundary point is the first non-zero \ pixel of @var{region}, as determined by @code{find}. The last boundary \ point is the same as the first.\n\ @seealso{boundaries, bwlabel, find}\n\ @end deftypefn") { octave_value_list retval; enum { ROW, COL }; // check number of arguments const int nargin = args.length (); if (nargin > 2 || nargout != 1) { error ("__boundary__: wrong number of input arguments"); return retval; } // extract arguments const boolMatrix unpadded = args (0).bool_matrix_value (); const int conn = (nargin > 1) ? (int) args (1).scalar_value () : 8; if (error_state) { error ("__boundary__: internal error"); return retval; } // pad to avoid boundary issues int rows = unpadded.rows (); int cols = unpadded.columns (); boolMatrix region (rows + 2, cols + 2, false); for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) region.elem (r+1, c+1) = unpadded (r, c); // the padded size rows += 2; cols += 2; // find the (first two) true pixels, if any std::vector pixels; for (int i = 0; pixels.size () < 2 && i < region.numel (); ++i) if (region.elem (i)) pixels.push_back (i); if (pixels.empty ()) return retval; // the starting boundary point const int start = pixels [0]; std::vector bound; bound.push_back (start); // is this the only point? if (pixels.size () == 1) bound.push_back (start); // otherwise, find the boundary by tracing the Moore neighbourhood of its pixels // // 8-connected: 7 0 1 4-connected: 0 // 6 . 2 3 . 1 // 5 4 3 2 else { // relative row/column positions static const int row8 [] = {-1, -1, 0, 1, 1, 1, 0, -1}; static const int col8 [] = { 0, 1, 1, 1, 0, -1, -1, -1}; static const int row4 [] = {-1, 0, 1, 0 }; static const int col4 [] = { 0, 1, 0, -1 }; const int* mr = (conn == 4) ? row4 : row8; const int* mc = (conn == 4) ? col4 : col8; // next after backing-up static const int back8 [] = {7, 7, 1, 1, 3, 3, 5, 5}; static const int back4 [] = {3, 0, 1, 2}; const int* mBack = (conn == 4) ? back4 : back8; // relative indexes into the region for the Moore neighbourhood pixels OCTAVE_LOCAL_BUFFER (int, mi, conn); for (int i = 0; i < conn; ++i) mi[i] = mr[i] + (rows * mc [i]); // next neighbourhood pixel static const int next8 [] = {1, 2, 3, 4, 5, 6, 7, 0}; static const int next4 [] = {1, 2, 3, 0}; const int* mNext = (conn == 4) ? next4 : next8; // the final boundary point to be visited int finish = 0; for (int i = 0; i < conn; ++i) if (region.elem(start + mi [i])) finish = start + mi [i]; // look for the next boundary point, starting at the next neighbour int bp = start; int mCurrent = mNext [0]; bool done = false; while (!done) { // next neighbour int cp = bp + mi [mCurrent]; // if this pixel is false, try the next one if (!region.elem (cp)) { mCurrent = mNext [mCurrent]; } // otherwise, we have another boundary point else { bound.push_back (cp); // either we're back at the start for the last time if (bp == finish && cp == start) { done = true; } // or we step back to where we came in from, and continue else { bp = cp; mCurrent = mBack [mCurrent]; } } } } // convert boundary points to row/column coordinates Matrix b (bound.size (), 2); for (unsigned int i = 0; i < bound.size (); i++) { const int point = bound [i]; b (i, ROW) = point % rows; b (i, COL) = point / rows; } retval.append (b); return retval; } image-2.4.1/src/PaxHeaders.6632/connectivity.cc0000644000000000000000000000013212561122761016074 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/connectivity.cc0000644000175000017500000002200712561122761020720 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2014 Carnë Draug // // 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 3 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 // . #include #include #include #include #include "connectivity.h" using namespace octave::image; connectivity::connectivity (const octave_value& val) { try {ctor (double_value (val));} catch (invalid_conversion& e) { try {ctor (bool_array_value (val));} catch (invalid_connectivity& e) {throw;} // so it does not get caught by the parent invalid_conversion catch (invalid_conversion& e) {throw invalid_connectivity ("must be logical or in the set [4 6 8 18 26]");} } return; } connectivity::connectivity (const boolNDArray& mask_arg) { ctor (mask_arg); return; } void connectivity::ctor (const boolNDArray& mask_arg) { mask = mask_arg; // Must be 1x1, 3x1, or 3x3x3x...x3 const octave_idx_type numel = mask.numel (); const dim_vector dims = mask.dims (); const octave_idx_type ndims = connectivity::ndims (dims); for (octave_idx_type i = 0; i < ndims; i++) if (dims(i) != 3) throw invalid_connectivity ("is not 1x1, 3x1, 3x3, or 3x3x...x3"); // Center must be true const octave_idx_type center = floor (numel /2); if (! mask(center)) throw invalid_connectivity ("center is not true"); // Must be symmetric relative to its center const bool* start = mask.fortran_vec (); const bool* end = mask.fortran_vec () + (numel -1); for (octave_idx_type i = 0; i < center; i++) if (start[i] != end[-i]) throw invalid_connectivity ("is not symmetric relative to its center"); return; } connectivity::connectivity (const octave_idx_type& conn) { ctor (conn); return; } void connectivity::ctor (const octave_idx_type& conn) { if (conn == 4) { mask = boolNDArray (dim_vector (3, 3), true); bool* md = mask.fortran_vec (); md[ 0] = false; md[ 2] = false; md[ 6] = false; md[ 8] = false; } else if (conn == 6) { mask = boolNDArray (dim_vector (3, 3, 3), false); bool* md = mask.fortran_vec (); md[ 4] = true; md[10] = true; md[12] = true; md[13] = true; md[14] = true; md[16] = true; md[22] = true; } else if (conn == 8) mask = boolNDArray (dim_vector (3, 3), true); else if (conn == 18) { mask = boolNDArray (dim_vector (3, 3, 3), true); bool* md = mask.fortran_vec (); md[ 0] = false; md[ 2] = false; md[ 6] = false; md[ 8] = false; md[18] = false; md[20] = false; md[24] = false; md[26] = false; } else if (conn == 26) mask = boolNDArray (dim_vector (3, 3, 3), true); else throw invalid_connectivity ("must be in the set [4 6 8 18 26]"); return; } connectivity::connectivity (const octave_idx_type& ndims, const std::string& type) { dim_vector size; if (ndims == 1) size = dim_vector (3, 1); else { size = dim_vector (3, 3); size.resize (ndims, 3); } if (type == "maximal") { mask = boolNDArray (size, true); } else if (type == "minimal") { mask = boolNDArray (size, false); bool* md = mask.fortran_vec (); md += int (floor (pow (3, ndims) /2)); // move to center md[0] = true; for (octave_idx_type dim = 0; dim < ndims; dim++) { const octave_idx_type stride = pow (3, dim); md[ stride] = true; md[-stride] = true; } } else throw invalid_connectivity ("must be \"maximal\" or \"minimal\""); return; } // A couple of things: // * it is handy that the offsets come sorted since they will be used to // access the elements and we want to jump around as little as possible. // * the number of dimensions used may be different than the mask. Array connectivity::neighbourhood (const dim_vector& size) const { const octave_idx_type ndims = connectivity::ndims (mask); const octave_idx_type numel = mask.numel (); // offset to adjacent element on correspoding dimension Array strides (dim_vector (ndims, 1)); strides(0) = 1; for (octave_idx_type dim = 1; dim < ndims; dim++) strides(dim) = strides(dim-1) * size(dim-1); Array pow3 (dim_vector (ndims, 1)); pow3(0) = 1; for (octave_idx_type dim = 1; dim < ndims; dim++) pow3(dim) = pow3(dim-1) * 3; // We calculate this for all elements. We could do it only for the "true" // elements but that's slightly more complex and in most cases we will // already want most, if not all, elements anyway. Array all_offsets (dim_vector (numel, 1), 0); for (octave_idx_type dim = 0; dim < ndims; dim++) { octave_idx_type i (0); for (int x = 0; x < pow3(ndims -1 -dim); x++) { for (octave_idx_type k = 0; k < pow3(dim); k++) all_offsets(i++) -= strides(dim); i += pow3(dim); for (octave_idx_type k = 0; k < pow3(dim); k++) all_offsets(i++) += strides(dim); } } octave_idx_type start_idx = 0; for (octave_idx_type dim = ndims; dim > connectivity::ndims (size); dim--) start_idx += pow3(dim -1); const bool* m = mask.fortran_vec (); const octave_idx_type* ao = all_offsets.fortran_vec (); octave_idx_type nnz = 0; for (octave_idx_type i = start_idx; i < (numel - start_idx); i++) if (m[i]) nnz++; Array offsets (dim_vector (nnz, 1)); octave_idx_type* o = offsets.fortran_vec (); for (octave_idx_type i = start_idx, j = 0; i < (numel - start_idx); i++) if (m[i]) o[j++] = ao[i]; return offsets; } Array connectivity::deleted_neighbourhood (const dim_vector& size) const { Array offsets = neighbourhood (size); for (octave_idx_type i = 0; i < offsets.numel (); i++) if (offsets(i) == 0) offsets.delete_elements (idx_vector (i)); return offsets; } Array connectivity::positive_neighbourhood (const dim_vector& size) const { Array offsets = neighbourhood (size); std::vector to_keep; for (octave_idx_type i = 0; i < offsets.numel (); i++) if (offsets(i) > 0) to_keep.push_back (offsets(i)); octave_idx_type numel = to_keep.size (); Array neg (dim_vector (numel, 1)); for (octave_idx_type i = 0; i < numel; i++) neg(i) = to_keep[i]; return neg; } Array connectivity::negative_neighbourhood (const dim_vector& size) const { Array offsets = neighbourhood (size); std::vector to_keep; for (octave_idx_type i = 0; i < offsets.numel (); i++) if (offsets(i) < 0) to_keep.push_back (offsets(i)); octave_idx_type numel = to_keep.size (); Array neg (dim_vector (numel, 1)); for (octave_idx_type i = 0; i < numel; i++) neg(i) = to_keep[i]; return neg; } double connectivity::double_value (const octave_value& val) { const double conn = val.double_value (); // Check is_scalar_type because the warning Octave:array-to-scalar // is off by default and we will get the first element only. if (error_state || ! val.is_scalar_type ()) throw invalid_conversion ("no conversion to double value"); return conn; } boolNDArray connectivity::bool_array_value (const octave_value& val) { const boolNDArray mask = val.bool_array_value (); // bool_array_value converts anything other than 0 to true, which will // then validate as conn array, hence any_element_not_one_or_zero() if (val.array_value ().any_element_not_one_or_zero ()) throw invalid_conversion ("no conversion to bool array value"); return mask; } octave_idx_type connectivity::ndims (const dim_vector& dims) { // We do not bother with 1x3 arrays since those are not valid // connectivity masks anyway. if (dims(1) == 1) { if (dims(0) == 1) return 0; else return 1; } else return dims.length (); } template octave_idx_type connectivity::ndims (const Array& a) { return connectivity::ndims (a.dims ()); } Array connectivity::padding_lengths (const dim_vector& size, const dim_vector& padded_size) { const octave_idx_type ndims = size.length (); Array lengths (dim_vector (ndims, 1), 0); lengths(0) = 1; for (octave_idx_type i = 1; i < ndims; i++) if (size(i) < padded_size(i)) lengths(i) = lengths(i -1) * padded_size(i-1); return lengths; } image-2.4.1/src/PaxHeaders.6632/imerode.cc0000644000000000000000000000013212561122761015002 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/imerode.cc0000644000175000017500000007622212561122761017636 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2013 Carnë Draug // // 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 3 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 . #include #include // to get ind2sub #include // for an optimization using logical matrices #include // gives us octave_Inf #include "strel.h" using namespace octave::image; // How this works: // // Erosion and dilation are simply minimum and maximum filters (in case of // dilation, the filter needs to be reflected). We have a binary matrix as // Structuring Element (SE) which slides through the image, and using the // maximum or minimum value of those elements for the output matrix. The // border of the matrix is considered to be +Inf or -Inf for the minimum // (erosion) and maximum (dilation) respectively. // // We start by padding the input matrix accordingly to the requested shape // (maybe this step could be avoided by doing the filtering in some different // method around the borders of the matrix0. // // For performance (so we can use a pointer to access the data) while // supporting ND matrices, we calculate the offset for all the points in the // input matrix that affects a single point in the output. Note that as we // slide through this offset values will always be the same. // // We could implement something more close to convn which is quite efficient // but that requires to go through every element of the SE which would be a // waste because not all elements in the SE will be true. Anyway, at least for // binary images (and convn can only be used to do erosion and dilation of // binary images), we already perform faster. // Pads the matrix MT with PADVAL, so it has the correct size to perform a // spatial filtering with SE, for the requested SHAPE. The SHAPE argument // is the same as in convn(). // FIXME: apparently it is not the same as convn(). Matlab seems to have // changed how this is done and will trim the SE, effectively changing // what its origin is. For example, requesting full erosion with the // following SE's will return the same // // 0 0 0 // 0 0 1 0 1 // 0 1 1 1 1 // // because in the first case, the first column and row are ignored. This // means that the size of output for full erosion will differ depending // on the SE. template static T pad_matrix (const T& mt, const strel& se, const double& padval, const std::string& shape) { // If the shape is valid, we can return the input matrix. if (shape == "valid") return mt; const octave_idx_type ndims = mt.ndims (); const Array pre_pad = se.pre_pad (ndims, shape); const Array post_pad = se.post_pad (ndims, shape); if (error_state) return T (); dim_vector padded_size (mt.dims ()); for (octave_idx_type dim = 0; dim < ndims; dim++) padded_size(dim) += pre_pad(dim) + post_pad(dim); T padded (padded_size, padval); // Ammount of pre_pad is also how much the original must be shifted // when inserting into the new padded matrix. padded.insert (mt, pre_pad); return padded; } // The general idea about the following is to look at each point for the // output, one at a time, and evaluate all the points from the input. This // at least allows us to skip many points in the case of binary images. For // each output point we consider the one with same index in the input as // "under" the SE element with index 0, and shift from that point to all the // others. Then we move to the next point of output. // // SE: // 0 1 1 // // Input in: // 0 1 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 1 0 // // Input out: // 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 // // Output: // 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 0 // // Note that the output is shorter in size since we have already padded the // input as appropriate for the requested shape. When we slide the SE over // the input, its center (origin) shows what value will be on the output. But // we won't actually use the center of the SE, only the first element and the // distance from it. This means that in this example, the NNZ elements of the // SE will have an offset of 1 and 2. // We match the first element of output with the first from output, and shift // their offset values to move to all other points in the input and assign // them to the output. // // To deal with N dimensional images we have the cumulative dimensions of the // input matrix, e.g. for 10x20x4x5 matrix, this would be the array // [10 200 800 4000]. This is how much we must shift the pointer in the input // matrix to get to the next value in a specific dimension. For example, to get // to the second column we would add 10*(2-1) to the input matrix. To get to // element 4 of the 3rd dimension we would add 200*(4-3). So we use this with // recursion, and adding to the pointer of the input matrix until we only // have a column to erode). // The values of erosion and isflat come as template since they are checked // at the deepest of the loop. By using a template instead of function // argument, it's all done at compile time so we get better performance. // If erosion is false, we perform dilation instead template inline static void erode_line (const P* in, P* out, const octave_idx_type* offsets, const P* height, const octave_idx_type& nnz, const octave_idx_type& line_length) { for (octave_idx_type line_idx = 0; line_idx < line_length; line_idx++) { for (octave_idx_type nnz_idx = 0; nnz_idx < nnz; nnz_idx++) { if (flat) { if (erosion) { if (in[offsets[nnz_idx]] < out[line_idx]) out[line_idx] = in[offsets[nnz_idx]]; } else { if (in[offsets[nnz_idx]] > out[line_idx]) out[line_idx] = in[offsets[nnz_idx]]; } } else { // If non-flat, there is no need to check if typeid is boolean // since non-flat makes no sense for binary images. if (erosion) { P val = in[offsets[nnz_idx]] - height[nnz_idx]; if (val < out[line_idx]) out[line_idx] = val; } else { P val = in[offsets[nnz_idx]] + height[nnz_idx]; if (val > out[line_idx]) out[line_idx] = val; } } } in++; } } // For the specific case of boolean dilation/erosion, we may be able to // break from the loop sooner. Also, there is non-flat binary erosion // and dilation. template inline static void erode_line (const bool* in, bool* out, const octave_idx_type* offsets, const bool* height, const octave_idx_type& nnz, const octave_idx_type& line_length) { for (octave_idx_type line_idx = 0; line_idx < line_length; line_idx++) { for (octave_idx_type nnz_idx = 0; nnz_idx < nnz; nnz_idx++) { if (erosion) { if (! in[offsets[nnz_idx]]) { out[line_idx] = false; break; } } else { if (in[offsets[nnz_idx]]) { out[line_idx] = true; break; } } } in++; } } template static void erode_nd (const P* in, const dim_vector& in_cd, P* out, const dim_vector& out_cd, const dim_vector& out_d, const octave_idx_type* offsets, const P* height, const octave_idx_type& nnz, const octave_idx_type& dim) { if (dim == 0) erode_line (in, out, offsets, height, nnz, out_d(0)); else for (octave_idx_type elem = 0; elem < out_d(dim); elem++) erode_nd (in + in_cd(dim-1) * elem, in_cd, out + out_cd(dim-1)* elem, out_cd, out_d, offsets, height, nnz, dim -1); OCTAVE_QUIT; } template static octave_value erode (const T& im, const strel& se, const std::string& shape, const bool& erosion) { typedef typename T::element_type P; const boolNDArray nhood = se.get_nhood (); // If image is empty, return empty of the same class. // If se is empty, return the same image as input. if (im.is_empty () || nhood.is_empty ()) return octave_value (im); // In the case of floating point, complex and integers numbers, both // octave_Inf and -octave_Inf actually become that type max and min value. // However, for boolean, both of them are converted to "true" so for // dilation, where we want false, we check the type. T padded; if (erosion) padded = pad_matrix (im, se, octave_Inf, shape); else if (typeid (P) == typeid (bool)) padded = pad_matrix (im, se, false, shape); else padded = pad_matrix (im, se, -octave_Inf, shape); if (error_state) return octave_value (); const octave_idx_type ndims = padded.ndims (); const dim_vector nhood_size = nhood.dims ().redim (ndims); const dim_vector padded_size = padded.dims (); const dim_vector cum_size = padded_size.cumulative (); const Array offsets = se.offsets (cum_size); const Array

heights = se.true_heights

(); const bool flat = se.flat (); if (typeid (P) == typeid (bool) && ! flat) { error ("only non flat structuring elements for binary images"); return octave_value (); } dim_vector out_size (padded_size); for (octave_idx_type i = 0; i < ndims; i++) out_size(i) -= nhood_size(i) - 1; T out; // When there's only a single neighbor on the SE, then we will only shift // the matrix by its distance to the origin of the SE. if (se.get_nnz () == 1) { octave_idx_type ind = nhood.find (1)(0); Array sub = ind2sub (nhood_size, idx_vector (ind)); Array ranges (dim_vector (ndims, 1)); for (octave_idx_type dim = 0; dim < ndims; dim++) { octave_idx_type start (sub(dim)(0)); octave_idx_type limit (start + out_size(dim)); ranges(dim) = idx_vector (start, limit); } out = padded.index (ranges); } else { if (erosion) out = T (out_size, octave_Inf); else if (typeid (P) == typeid (bool)) out = T (out_size, false); else out = T (out_size, -octave_Inf); if (flat) if (erosion) erode_nd (padded.data (), cum_size, out.fortran_vec (), out_size.cumulative (), out_size, offsets.data (), heights.data (), offsets.numel (), ndims -1); else erode_nd (padded.data (), cum_size, out.fortran_vec (), out_size.cumulative (), out_size, offsets.data (), heights.data (), offsets.numel (), ndims -1); else if (erosion) erode_nd (padded.data (), cum_size, out.fortran_vec (), out_size.cumulative (), out_size, offsets.data (), heights.data (), offsets.numel (), ndims -1); else erode_nd (padded.data (), cum_size, out.fortran_vec (), out_size.cumulative (), out_size, offsets.data (), heights.data (), offsets.numel (), ndims -1); } return octave_value (out); } static octave_value base_action (const std::string& func, const bool& erosion, const octave_value_list& args) { octave_value retval; const octave_idx_type nargin = args.length (); if (nargin < 2 || nargin > 4) { print_usage (func); return retval; } // Default shape is "same" const std::string shape = nargin > 2? args(2).string_value () : "same"; if (error_state) { error ("%s: SHAPE must be a string", func.c_str ()); return retval; } strel se (args(1)); if (error_state) { error ("%s: SE must be a strel object or matrix of 1's and 0's", func.c_str ()); return retval; } if (! erosion) // must be dilation, then get the se reflection se = se.reflect (); octave_value im = args(0); for (octave_idx_type idx = 0; idx < se.numel (); idx++) { const strel se_elem = se(idx); if (im.is_bool_matrix ()) im = erode (im.bool_array_value (), se_elem, shape, erosion); else if (im.is_int8_type ()) im = erode (im.int8_array_value (), se_elem, shape, erosion); else if (im.is_int16_type ()) im = erode (im.int16_array_value (), se_elem, shape, erosion); else if (im.is_int32_type ()) im = erode (im.int32_array_value (), se_elem, shape, erosion); else if (im.is_int64_type ()) im = erode (im.int64_array_value (), se_elem, shape, erosion); else if (im.is_uint8_type ()) im = erode (im.uint8_array_value (), se_elem, shape, erosion); else if (im.is_uint16_type ()) im = erode (im.uint16_array_value (), se_elem, shape, erosion); else if (im.is_uint32_type ()) im = erode (im.uint32_array_value (), se_elem, shape, erosion); else if (im.is_uint64_type ()) im = erode (im.uint64_array_value (), se_elem, shape, erosion); else if (im.is_real_type ()) if (im.is_single_type ()) im = erode (im.float_array_value (), se_elem, shape, erosion); else // must be double im = erode (im.array_value (), se_elem, shape, erosion); else if (im.is_complex_type ()) if (im.is_single_type ()) im = erode (im.float_complex_array_value (), se_elem, shape, erosion); else // must be double im = erode (im.complex_array_value (), se_elem, shape, erosion); else im = octave_value (); } return im; } DEFUN_DLD(imerode, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} imerode (@var{im}, @var{SE})\n\ @deftypefnx {Loadable Function} {} imerode (@var{im}, @var{SE}, @var{shape})\n\ Perform morphological erosion.\n\ \n\ The image @var{im} must be a numeric matrix with any number of dimensions.\n\ The erosion is performed with the structuring element @var{se} which can\n\ be a:\n\ \n\ @itemize @bullet\n\ @item strel object;\n\ @item array of strel objects as returned by @code{@@strel/getsequence};\n\ @item matrix of 0's and 1's.\n\ @end itemize\n\ \n\ To perform a non-flat erosion, @var{SE} must be a strel object.\n\ \n\ The size of the result is determined by the optional @var{shape} argument\n\ which takes the following values:\n\ \n\ @table @asis\n\ @item @qcode{\"same\"} (default)\n\ Return image of the same size as input @var{im}.\n\ \n\ @item @qcode{\"full\"}\n\ Return the full erosion (image is padded to accommodate @var{se} near the\n\ borders).\n\ \n\ @item @qcode{\"valid\"}\n\ Return only the parts which do not include the padded edges.\n\ @end table\n\ \n\ In case of a @var{SE} with a size of even length, the center is considered\n\ at indices @code{floor ([size(@var{SE})/2] + 1)}.\n\ \n\ @seealso{imdilate, imopen, imclose, strel}\n\ @end deftypefn") { return base_action ("imerode", true, args); } /* ## using [1] or nothing as mask returns the same value %!assert (imerode (eye (3), [1]), eye (3)); %!assert (imerode (eye (3), []), eye (3)); ## test normal usage with non-symmetric SE %!test %! im = [0 1 0 %! 1 1 1 %! 0 1 0]; %! se = [1 0 0 %! 0 1 0 %! 0 1 1]; %! assert (imerode (im, se), [0 1 0; 0 0 0; 0 1 0]); %! assert (imerode (logical(im), se), logical ([0 1 0; 0 0 0; 0 1 0])); %! assert (imerode (im, se, "full"), %! [ 0 0 0 0 Inf %! 1 0 1 0 Inf %! 0 0 0 0 0 %! Inf 0 1 0 1 %! Inf Inf 0 1 0]); %! assert (imerode (logical(im), se, "full"), %! logical([0 0 0 0 1 %! 1 0 1 0 1 %! 0 0 0 0 0 %! 1 0 1 0 1 %! 1 1 0 1 0])); %!test %! a = rand ([10 40 15 6 8 5]) > 0.2; %! se = ones ([5 3 7]); %! %! ## the image is not really indexed but this way it is padded with 1s %! assert (imerode (a, se), colfilt (a, "indexed", size (se), "sliding", @all)) %! %! assert (imerode (a, se, "valid"), convn (a, se, "valid") == nnz (se)) %! ## again, we need to pad it ourselves because convn pads with zeros %! b = true (size (a) + [4 2 6 0 0 0]); %! b(3:12, 2:41, 4:18,:,:,:) = a; %! assert (imdilate (b, se, "same"), convn (b, se, "same") > 0) %! b = true (size (a) + [8 4 12 0 0 0]); %! b(5:14, 3:42, 7:21,:,:,:) = a; %! assert (imdilate (b, se, "full"), convn (b, se, "full") > 0) %!test %! im = [0 0 0 0 0 0 0 %! 0 0 1 0 1 0 0 %! 0 0 1 1 0 1 0 %! 0 0 1 1 1 0 0 %! 0 0 0 0 0 0 0]; %! se = [0 0 0 %! 0 1 0 %! 0 1 1]; %! out = [0 0 0 0 0 0 0 %! 0 0 1 0 0 0 0 %! 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0]; %! assert (imerode (im, se), out); %! assert (imerode (logical (im), se), logical (out)); %! assert (imerode (im, logical (se)), out); %! assert (imerode (logical (im), logical (se)), logical (out)); %! %! # with an even-size SE %! se = [0 0 0 1 %! 0 1 0 0 %! 0 1 1 1]; %! out = [0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 1 0 0 0 0 %! 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0]; %! assert (imerode (im, se), out); %! out = [ 0 0 0 0 1 0 1 %! 0 0 1 0 1 1 0 %! 0 0 1 1 1 1 1 %! 0 0 1 1 1 1 1 %! 0 0 1 1 1 1 1]; %! assert (imdilate (im, se), out); ## normal usage for grayscale images %!test %! a = [ 82 2 97 43 79 43 41 65 51 11 %! 60 65 21 56 94 77 36 38 75 39 %! 32 68 78 1 16 75 76 90 81 56 %! 43 90 82 41 36 1 87 19 18 63 %! 63 64 2 48 18 43 38 25 22 99 %! 12 46 90 79 3 92 39 79 10 22 %! 38 98 11 10 40 90 88 38 4 76 %! 54 37 9 4 33 98 36 47 53 57 %! 38 76 82 50 14 74 64 99 7 33 %! 88 96 41 62 84 89 97 23 41 3]; %! %! domain = ones (3); %! out = [ 2 1 1 1 16 36 36 11 %! 21 1 1 1 1 1 18 18 %! 2 1 1 1 1 1 18 18 %! 2 2 2 1 1 1 10 10 %! 2 2 2 3 3 25 4 4 %! 9 4 3 3 3 36 4 4 %! 9 4 4 4 14 36 4 4 %! 9 4 4 4 14 23 7 3]; %! assert (imerode (a, domain, "valid"), out); %! assert (imerode (uint8 (a), domain, "valid"), uint8 (out)); %! assert (imerode (uint8 (a), strel ("arbitrary", domain), "valid"), uint8 (out)); %! assert (imerode (uint8 (a), strel ("square", 3), "valid"), uint8 (out)); %! %!## Test for non-flat strel %! assert (imerode (a, strel ("arbitrary", domain, ones (3)), "valid"), out -1); %! %! out = [ 97 97 97 94 94 90 90 90 %! 90 90 94 94 94 90 90 90 %! 90 90 82 75 87 90 90 99 %! 90 90 90 92 92 92 87 99 %! 98 98 90 92 92 92 88 99 %! 98 98 90 98 98 98 88 79 %! 98 98 82 98 98 99 99 99 %! 96 96 84 98 98 99 99 99]; %! assert (imdilate (a, domain, "valid"), out); %! assert (imdilate (uint8 (a), domain, "valid"), uint8 (out)); %! %!## Test for non-flat strel %! assert (imdilate (a, strel ("arbitrary", domain, ones (3)), "valid"), out +1); %! %! ## test while using SE that can be decomposed and an actual sequence %! domain = ones (5); %! out = [ 2 1 1 1 1 1 16 11 11 11 %! 2 1 1 1 1 1 1 1 11 11 %! 2 1 1 1 1 1 1 1 11 11 %! 2 1 1 1 1 1 1 1 10 10 %! 2 1 1 1 1 1 1 1 4 4 %! 2 2 2 1 1 1 1 1 4 4 %! 2 2 2 2 2 3 3 4 4 4 %! 9 4 3 3 3 3 3 3 3 3 %! 9 4 4 4 4 4 4 3 3 3 %! 9 4 4 4 4 4 7 3 3 3]; %! assert (imerode (a, domain), out); %! assert (imerode (a, strel ("square", 5)), out); %! assert (imerode (a, getsequence (strel ("square", 5))), out); %! %! ## using a non-symmetric SE %! domain = [ 1 1 0 %! 0 1 1 %! 0 1 0]; %! %! out = [ 2 2 1 16 36 36 38 39 %! 60 1 1 16 1 36 19 18 %! 32 2 1 1 1 19 18 18 %! 2 2 18 3 1 1 19 10 %! 46 2 2 3 18 38 10 4 %! 11 9 4 3 3 36 4 4 %! 9 4 4 10 36 36 38 4 %! 37 9 4 4 33 36 7 7]; %! assert (imerode (a, domain, "valid"), out); %! assert (imerode (a, strel ("arbitrary", domain, ones (3)), "valid"), out -1); %! %! out = [ 78 97 56 94 94 90 90 81 %! 90 82 78 94 87 87 90 90 %! 90 90 82 43 75 87 90 99 %! 90 90 79 92 92 87 79 25 %! 98 90 90 90 92 92 79 79 %! 98 98 79 98 98 90 88 57 %! 98 82 50 74 98 99 99 53 %! 96 82 84 89 98 97 99 99]; %! assert (imdilate (a, domain, "valid"), out); %! assert (imdilate (a, strel ("arbitrary", domain, ones (3)), "valid"), out +1); // Tests for N-dimensions %!test %! im = reshape (magic(16), [4 8 4 2]); %! se = true (3, 3, 3); %! out = zeros (4, 8, 4, 2); %! out(:,:,1,1) = [ %! 3 3 46 2 2 2 47 47 %! 3 3 30 2 2 2 31 31 %! 17 17 16 16 16 20 13 13 %! 33 33 16 16 16 36 13 13]; %! out(:,:,2,1) = [ %! 3 3 46 2 2 2 43 43 %! 3 3 30 2 2 2 27 27 %! 17 17 12 12 12 20 13 13 %! 33 33 12 12 12 36 13 13]; %! out(:,:,3,1) = [ %! 3 3 42 6 6 6 43 43 %! 3 3 26 6 6 6 27 27 %! 21 21 12 12 12 20 9 9 %! 37 37 12 12 12 36 9 9]; %! out(:,:,4,1) = [ %! 7 7 42 6 6 6 43 43 %! 7 7 26 6 6 6 27 27 %! 21 21 12 12 12 24 9 9 %! 37 37 12 12 12 40 9 9]; %! out(:,:,1,2) = [ %! 11 11 38 10 10 10 39 39 %! 11 11 22 10 10 10 23 23 %! 25 25 8 8 8 28 5 5 %! 41 41 8 8 8 44 5 5]; %! out(:,:,2,2) = [ %! 11 11 38 10 10 10 35 35 %! 11 11 22 10 10 10 19 19 %! 25 25 4 4 4 28 5 5 %! 41 41 4 4 4 44 5 5]; %! out(:,:,3,2) = [ %! 11 11 34 14 14 14 35 35 %! 11 11 18 14 14 14 19 19 %! 29 29 4 4 4 28 1 1 %! 45 45 4 4 4 44 1 1]; %! out(:,:,4,2) = [ %! 15 15 34 14 14 14 35 35 %! 15 15 18 14 14 14 19 19 %! 29 29 4 4 4 32 1 1 %! 45 45 4 4 4 48 1 1]; %! assert (imerode (im, se), out); %! assert (imerode (uint16 (im), se), uint16 (out)); %! %! ## trying a more weird SE %! se(:,:,1) = [1 0 1; 0 1 1; 0 0 0]; %! se(:,:,3) = [1 0 1; 0 1 1; 0 0 1]; %! out(:,:,1,1) = [ %! 3 17 46 2 2 2 47 47 %! 17 3 30 2 2 2 31 31 %! 17 17 16 16 16 20 13 31 %! 33 33 16 16 16 36 13 13]; %! out(:,:,2,1) = [ %! 3 3 46 2 2 20 43 61 %! 3 3 30 2 20 2 27 43 %! 33 17 12 20 20 20 13 13 %! 51 33 12 12 30 36 13 13]; %! out(:,:,3,1) = [ %! 3 21 42 6 6 6 43 43 %! 21 3 26 6 6 6 27 27 %! 21 21 12 12 12 20 9 27 %! 37 37 12 12 12 36 9 9]; %! out(:,:,4,1) = [ %! 7 7 42 6 6 24 57 57 %! 7 7 26 6 24 6 43 43 %! 37 21 26 24 24 24 9 9 %! 55 37 12 12 26 40 9 9]; %! out(:,:,1,2) = [ %! 11 25 38 10 10 10 39 39 %! 25 11 22 10 10 10 23 23 %! 25 25 8 8 8 28 5 23 %! 41 41 8 8 8 44 5 5]; %! out(:,:,2,2) = [ %! 11 11 38 10 10 28 35 53 %! 11 11 22 10 22 10 19 35 %! 41 25 4 22 22 28 5 5 %! 59 41 4 4 22 44 5 5]; %! out(:,:,3,2) = [ %! 11 29 34 14 14 14 35 35 %! 29 11 18 14 14 14 19 19 %! 29 29 4 4 4 28 1 19 %! 45 45 4 4 4 44 1 1]; %! out(:,:,4,2) = [ %! 15 15 34 14 14 32 49 49 %! 15 15 18 14 18 14 35 35 %! 45 29 18 18 18 32 1 1 %! 63 45 4 4 18 48 1 1]; %! assert (imerode (im, se), out); %! assert (imerode (uint16 (im), se), uint16 (out)); ## Test input check %!error imerode (ones (10), 45) %!error imerode (ones (10), "some text") %!error imerode (ones (10), {23, 45}) ## No binary erosion for non-flat strel %!error imerode (rand (10) > 10 , strel ("arbitrary", true (3), ones (3))) */ // PKG_ADD: autoload ("imdilate", which ("imerode")); // PKG_DEL: autoload ("imdilate", which ("imerode"), "remove"); DEFUN_DLD(imdilate, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} imdilate (@var{im}, @var{SE})\n\ @deftypefnx {Loadable Function} {} imdilate (@var{im}, @var{SE}, @var{shape})\n\ Perform morphological dilation.\n\ \n\ The image @var{im} must be a numeric matrix with any number of dimensions.\n\ The dilation is performed with the structuring element @var{se} which can\n\ be a:\n\ \n\ @itemize @bullet\n\ @item strel object;\n\ @item array of strel objects as returned by @code{@@strel/getsequence};\n\ @item matrix of 0's and 1's.\n\ @end itemize\n\ \n\ To perform a non-flat dilation, @var{SE} must be a strel object.\n\ \n\ The size of the result is determined by the optional @var{shape} argument\n\ which takes the following values:\n\ \n\ @table @asis\n\ @item @qcode{\"same\"} (default)\n\ Return image of the same size as input @var{im}.\n\ \n\ @item @qcode{\"full\"}\n\ Return the full dilation (matrix is padded to accommodate @var{se} near the\n\ borders).\n\ \n\ @item @qcode{\"valid\"}\n\ Return only the parts which do not include the padded edges.\n\ @end table\n\ \n\ In case of a @var{SE} with a size of even length, the center is considered\n\ at indices @code{floor ([size(@var{SE})/2] + 1)}.\n\ \n\ @seealso{imerode, imopen, imclose}\n\ @end deftypefn") { return base_action ("imdilate", false, args); } /* // Tests for N-dimensions %!test %! a = rand ([10 40 15 6 8 5]) > 0.8; %! se = ones ([5 3 7]); %! assert (imdilate (a, se), convn (a, se, "same") > 0) %! assert (imdilate (a, se, "full"), convn (a, se, "full") > 0) %! assert (imdilate (a, se, "valid"), convn (a, se, "valid") > 0) %! assert (imdilate (a, se), colfilt (a, size (se), "sliding", @any)) %!test %! im = reshape (magic(16), [4 8 4 2]); %! se = true (3, 3, 3); %! out = zeros (4, 8, 4, 2); %! %! out(:,:,1,1) = [ %! 256 256 209 253 253 253 212 212 %! 256 256 225 253 253 253 228 228 %! 238 238 243 243 243 239 242 242 %! 222 222 243 243 243 223 242 242]; %! out(:,:,2,1) = [ %! 256 256 213 253 253 253 212 212 %! 256 256 229 253 253 253 228 228 %! 238 238 243 243 243 239 246 246 %! 222 222 243 243 243 223 246 246]; %! out(:,:,3,1) = [ %! 252 252 213 253 253 253 216 216 %! 252 252 229 253 253 253 232 232 %! 238 238 247 247 247 235 246 246 %! 222 222 247 247 247 219 246 246]; %! out(:,:,4,1) = [ %! 252 252 213 249 249 249 216 216 %! 252 252 229 249 249 249 232 232 %! 234 234 247 247 247 235 246 246 %! 218 218 247 247 247 219 246 246]; %! out(:,:,1,2) = [ %! 248 248 217 245 245 245 220 220 %! 248 248 233 245 245 245 236 236 %! 230 230 251 251 251 231 250 250 %! 214 214 251 251 251 215 250 250]; %! out(:,:,2,2) = [ %! 248 248 221 245 245 245 220 220 %! 248 248 237 245 245 245 236 236 %! 230 230 251 251 251 231 254 254 %! 214 214 251 251 251 215 254 254]; %! out(:,:,3,2) = [ %! 244 244 221 245 245 245 224 224 %! 244 244 237 245 245 245 240 240 %! 230 230 255 255 255 227 254 254 %! 214 214 255 255 255 211 254 254]; %! out(:,:,4,2) = [ %! 244 244 221 241 241 241 224 224 %! 244 244 237 241 241 241 240 240 %! 226 226 255 255 255 227 254 254 %! 210 210 255 255 255 211 254 254]; %! assert (imdilate (im, se), out); %! assert (imdilate (uint16 (im), se), uint16 (out)); %! %! ## trying a more weird SE %! se(:,:,1) = [1 0 1; 0 1 1; 0 0 0]; %! se(:,:,3) = [1 0 1; 0 1 1; 0 0 1]; %! out(:,:,1,1) = [ %! 256 256 209 239 253 253 212 194 %! 256 256 225 239 239 239 228 212 %! 222 222 243 239 243 239 242 242 %! 208 208 225 243 243 223 242 242]; %! out(:,:,2,1) = [ %! 256 256 213 253 253 253 212 212 %! 238 256 229 253 253 253 228 228 %! 238 238 243 243 243 239 246 228 %! 222 222 243 243 243 223 228 246]; %! out(:,:,3,1) = [ %! 252 252 213 235 253 253 216 198 %! 252 252 229 235 235 253 232 216 %! 222 238 247 235 247 235 246 246 %! 204 222 229 247 247 219 246 246]; %! out(:,:,4,1) = [ %! 252 252 213 249 249 249 216 216 %! 234 252 229 249 249 249 232 232 %! 234 234 247 247 247 235 246 232 %! 218 218 247 247 247 219 232 246]; %! out(:,:,1,2) = [ %! 248 248 217 231 245 245 220 202 %! 248 248 233 233 233 231 236 220 %! 214 214 251 233 251 231 250 250 %! 200 200 233 251 251 215 250 250]; %! out(:,:,2,2) = [ %! 248 248 221 245 245 245 220 220 %! 230 248 237 245 245 245 236 236 %! 230 230 251 251 251 231 254 236 %! 214 214 251 251 251 215 236 254]; %! out(:,:,3,2) = [ %! 244 244 221 227 245 245 224 206 %! 244 244 237 237 237 245 240 224 %! 214 230 255 237 255 227 254 254 %! 196 214 237 255 255 211 254 254]; %! out(:,:,4,2) = [ %! 244 244 221 241 241 241 224 224 %! 226 244 237 241 241 241 240 240 %! 226 226 255 255 255 227 254 240 %! 210 210 255 255 255 211 240 254]; %! assert (imdilate (im, se), out); %! assert (imdilate (uint16 (im), se), uint16 (out)); */ image-2.4.1/src/PaxHeaders.6632/conndef.cc0000644000000000000000000000013212561122761014772 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/conndef.cc0000644000175000017500000002173312561122761017623 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2014 Carnë Draug // // 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 3 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 // . #include #include "connectivity.h" using namespace octave::image; // The conndef() function is really really simple and could have easily // been a m file (actually it once was, check the hg log if it ever needs // to be recovered) but then it would be awkward to call it from oct // functions so we made a C++ class for it. DEFUN_DLD(conndef, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} conndef (@var{conn})\n\ @deftypefnx {Loadable Function} {} conndef (@var{mask})\n\ @deftypefnx {Loadable Function} {} conndef (@var{ndims}, @var{type})\n\ Create connectivity array.\n\ \n\ Creates a matrix of for morphological operations, where elements with\n\ a value of 1 are considered connected to the center element (a\n\ connectivity array).\n\ \n\ It can be specified by the number of dimensions, @var{ndims}, and\n\ @var{type} which must be one of the following strings:\n\ \n\ @table @asis\n\ @item @qcode{\"minimal\"}\n\ Neighbours touch the central element on a (@var{ndims}-1)-dimensional\n\ surface.\n\ \n\ @item @qcode{\"maximal\"}\n\ Neighbours touch the central element in any way. Equivalent to\n\ @code{ones (repmat (3, 1, @var{ndims}))}.\n\ \n\ @end table\n\ \n\ the number of connected elements to the center element, @var{conn},\n\ in which case the following are valid:\n\ \n\ @table @asis\n\ @item 4\n\ Two-dimensional 4-connected neighborhood.\n\ \n\ @item 8\n\ Two-dimensional 8-connected neighborhood.\n\ \n\ @item 6\n\ Three-dimensional 6-connected neighborhood.\n\ \n\ @item 18\n\ Three-dimensional 18-connected neighborhood.\n\ \n\ @item 26\n\ Three-dimensional 26-connected neighborhood.\n\ \n\ @end table\n\ \n\ or a connectivity array itself, in which case it checks for its validity\n\ and returns itself. In such case, it is equivalent to @code{iptcheckconn}.\n\ \n\ @seealso{iptcheckconn, strel}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return octave_value (); } connectivity conn; if (nargin == 1) { try {conn = connectivity (args(0));} catch (invalid_connectivity& e) { error ("conndef: CONN %s", e.what ()); return octave_value (); } } else { const octave_idx_type arg0 = args(0).idx_type_value (true); if (error_state || arg0 < 1) { error ("conndef: NDIMS must be a positive integer"); return octave_value (); } const std::string type = args(1).string_value (); if (error_state) { error ("conndef: TYPE must be a string"); return octave_value (); } try {conn = connectivity (arg0, type);} catch (invalid_connectivity& e) { error ("conndef: TYPE %s", e.what ()); return octave_value (); } } // we must return an array of class double return octave_value (NDArray (conn.mask)); } /* %!assert (conndef (1, "minimal"), [1; 1; 1]); %!assert (conndef (2, "minimal"), [0 1 0; 1 1 1; 0 1 0]); %!test %! C = zeros (3, 3, 3); %! C(:,2,2) = 1; %! C(2,:,2) = 1; %! C(2,2,:) = 1; %! assert (conndef (3, "minimal"), C); %!test %! C = zeros (3, 3, 3, 3); %! C(:,:,2,1) = [0 0 0 %! 0 1 0 %! 0 0 0]; %! C(:,:,1,2) = [0 0 0 %! 0 1 0 %! 0 0 0]; %! C(:,:,2,2) = [0 1 0 %! 1 1 1 %! 0 1 0]; %! C(:,:,3,2) = [0 0 0 %! 0 1 0 %! 0 0 0]; %! C(:,:,2,3) = [0 0 0 %! 0 1 0 %! 0 0 0]; %! assert (conndef (4, "minimal"), C); %!assert (conndef (1, "maximal"), ones (3, 1)); %!assert (conndef (2, "maximal"), ones (3, 3)); %!assert (conndef (3, "maximal"), ones (3, 3, 3)); %!assert (conndef (4, "maximal"), ones (3, 3, 3, 3)); %!assert (nnz (conndef (3, "minimal")), 7) %!assert (nnz (conndef (4, "minimal")), 9) %!assert (nnz (conndef (5, "minimal")), 11) %!assert (nnz (conndef (6, "minimal")), 13) %!assert (find (conndef (3, "minimal")), [5 11 13 14 15 17 23](:)) %!assert (find (conndef (4, "minimal")), [14 32 38 40 41 42 44 50 68](:)) %!assert (find (conndef (5, "minimal")), %! [ 41 95 113 119 121 122 123 125 131 149 203](:)) %!assert (find (conndef (6, "minimal")), %! [ 122 284 338 356 362 364 365 366 368 374 392 446 608](:)) %!error conndef () %!error conndef (-2, "minimal") %!error conndef (char (2), "minimal") %!error conndef ("minimal", 3) %!error conndef (3, "invalid") %!error conndef (10) %!assert (conndef (2, "minimal"), conndef (4)) %!assert (conndef (2, "maximal"), conndef (8)) %!assert (conndef (3, "minimal"), conndef (6)) %!assert (conndef (3, "maximal"), conndef (26)) %!assert (conndef (18), reshape ([0 1 0 1 1 1 0 1 0 %! 1 1 1 1 1 1 1 1 1 %! 0 1 0 1 1 1 0 1 0], [3 3 3])) */ // PKG_ADD: autoload ("iptcheckconn", which ("conndef")); // PKG_DEL: autoload ("iptcheckconn", which ("conndef"), "remove"); DEFUN_DLD(iptcheckconn, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} iptcheckconn (@var{conn}, @var{func}, @var{var})\n\ @deftypefnx {Loadable Function} {} iptcheckconn (@var{conn}, @var{func}, @var{var}, @var{pos})\n\ Check if argument is valid connectivity.\n\ \n\ If @var{conn} is not a valid connectivity argument, gives a properly\n\ formatted error message. @var{func} is the name of the function to be\n\ used on the error message, @var{var} the name of the argument being\n\ checked (for the error message), and @var{pos} the position of the\n\ argument in the input.\n\ \n\ A valid connectivity argument must be either double or logical. It must\n\ also be either a scalar from set [4 6 8 18 26], or a symmetric matrix\n\ with all dimensions of size 3, with only 0 or 1 as values, and 1 at its\n\ center.\n\ \n\ @seealso{conndef}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 3 || nargin > 4) { print_usage (); return octave_value (); } const std::string func = args(1).string_value (); if (error_state) { error ("iptcheckconn: FUNC must be a string"); return octave_value (); } const std::string var = args(2).string_value (); if (error_state) { error ("iptcheckconn: VAR must be a string"); return octave_value (); } octave_idx_type pos (0); if (nargin > 3) { pos = args(3).idx_type_value (true); if (error_state || pos < 1) { error ("iptcheckconn: POS must be a positive integer"); return octave_value (); } } try {const connectivity conn (args(0));} catch (invalid_connectivity& e) { if (pos == 0) error ("%s: %s %s", func.c_str (), var.c_str (), e.what ()); else error ("%s: %s, at pos %i, %s", func.c_str (), var.c_str (), pos, e.what ()); } return octave_value (); } /* // the complete error message should be "expected error <.> but got none", // but how to escape <> within the error message? %!error fail ("iptcheckconn ( 4, 'func', 'var')"); %!error fail ("iptcheckconn ( 6, 'func', 'var')"); %!error fail ("iptcheckconn ( 8, 'func', 'var')"); %!error fail ("iptcheckconn (18, 'func', 'var')"); %!error fail ("iptcheckconn (26, 'func', 'var')"); %!error fail ("iptcheckconn (1, 'func', 'var')"); %!error fail ("iptcheckconn (ones (3, 1), 'func', 'var')"); %!error fail ("iptcheckconn (ones (3, 3), 'func', 'var')"); %!error fail ("iptcheckconn (ones (3, 3, 3), 'func', 'var')"); %!error fail ("iptcheckconn (ones (3, 3, 3, 3), 'func', 'var')"); %!error iptcheckconn (3, "func", "VAR"); %!error iptcheckconn ([1 1 1; 1 0 1; 1 1 1], "func", "VAR"); %!error iptcheckconn ([1 2 1; 1 1 1; 1 1 1], "func", "VAR"); %!error iptcheckconn ([0 1 1; 1 1 1; 1 1 1], "func", "VAR"); %!error iptcheckconn (ones (3, 3, 3, 4), "func", "VAR"); */ image-2.4.1/src/PaxHeaders.6632/nonmax_supress.cc0000644000000000000000000000013212561122761016442 xustar0030 mtime=1438950897.790252238 30 atime=1438950897.790252238 30 ctime=1438950899.342252237 image-2.4.1/src/nonmax_supress.cc0000644000175000017500000001324612561122761021273 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2005 Søren Hauberg // // 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 3 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 . #include #include #include #include static bool any_bad_argument(const octave_value_list& args) { /* TODO: We should check that the matrices have the same size. */ int nargin = args.length(); if ( (nargin >= 2) && args(0).is_real_matrix() && args(1).is_real_matrix() ) { if (nargin == 2) { return false; } else if (nargin == 4 && args(2).is_real_scalar() && args(3).is_real_scalar() ) { return false; } } error("Input arguments must be two 2-dimensional matrices of the same size."); return true; } DEFUN_DLD(nonmax_supress,args,nargout,"\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {} nonmax_supress (@var{Es}, @var{Eo})\n\ Performs non-maximum supression on the given edge data. \ @var{Es} is a matrix containing the edge strength (the length of \ the gradient), and @var{Eo} is the edge normal orientation (the \ direction of the gradient).\n\ \n\ @end deftypefn\n\ @deftypefn {Loadable Function} {} nonmax_supress (@var{Es}, @var{Eo},\ @var{low}, @var{high} )\n\ Performs non-maximum supression and hysteresis thresholdong, using \ @var{low} and @var{high} as thresholds.\n\ \n\ This function is designed to be used as part of the Canny edge \ detection, and not to be used in general. So if you use this function: \ Beware...\n\ \n\ @seealso{edge}\n\ @end deftypefn\n\ ") { octave_value_list retval; if (any_bad_argument(args)) { return retval; } std::stack< std::pair > S; /* Neighbourhood directions in radians */ const double d[4] = { 0.0, M_PI * 45.0 / 180.0, M_PI * 90.0 / 180.0, M_PI * 135.0 / 180.0 }; const Matrix Es = args(0).matrix_value(); Matrix Eo = args(1).matrix_value(); double low, high; bool hysteresis = (args.length()==4); if (hysteresis) { low = args(2).scalar_value(); high = args(3).scalar_value(); } else { low = high = 0; } const int rows = Es.rows(); const int cols = Es.columns(); /**************************** ** Non-maximum supression ** ****************************/ Matrix In = Matrix( rows, cols, 0.0 ); for (int r = 1; r < rows-1; r++) { for (int c = 1; c < cols-1; c++) { const double orientation = Eo(r,c); const double strength = Es(r,c); int best_d = 0; const double dist = fabs( orientation-d[0] ); for (int i = 1; i < 4; i++) { if ( fabs( orientation-d[i] ) < dist ) { best_d = i; } } Eo(r,c) = best_d; switch (best_d) { case 0: // 0 degrees if ( (strength > Es(r,c-1)) && (strength > Es(r,c+1)) ) { In(r,c) = strength; } break; case 1: // 45 degrees if ( (strength > Es(r-1,c+1)) && (strength > Es(r+1,c-1)) ) { In(r,c) = strength; } break; case 2: // 90 degrees if ( (strength > Es(r-1,c)) && (strength > Es(r+1,c)) ) { In(r,c) = strength; } break; case 3: // 135 degrees if ( (strength > Es(r-1,c-1)) && (strength > Es(r+1,c+1)) ) { In(r,c) = strength; } break; } if (hysteresis && In(r,c) > high) { S.push( std::pair(r,c) ); } } } if (hysteresis == false) { retval.append(In); return retval; } /************************** ** Hysteresis threshold ** **************************/ boolMatrix out = boolMatrix( rows, cols, false ); while (S.empty() == false) { std::pair p = S.top(); S.pop(); const int r = p.first; const int c = p.second; if (r < 0 || r >= rows || c < 0 || c >= cols || out(r,c) == true) { continue; } out(r,c) = true; const int dir = (int)Eo(r,c); switch (dir) { case 0: // 0 degrees if ( In(r-1,c) > low ) { S.push(std::pair(r-1,c)); } if ( In(r+1,c) > low ) { S.push(std::pair(r+1,c)); } break; case 1: // 45 degrees if ( In(r-1,c-1) > low ) { S.push(std::pair(r-1,c-1)); } if ( In(r+1,c+1) > low ) { S.push(std::pair(r+1,c+1)); } break; case 2: // 90 degrees if ( In(r,c-1) > low ) { S.push(std::pair(r,c-1)); } if ( In(r,c+1) > low ) { S.push(std::pair(r,c+1)); } break; case 3: // 135 degrees if ( In(r-1,c+1) > low ) { S.push(std::pair(r-1,c+1)); } if ( In(r+1,c-1) > low ) { S.push(std::pair(r+1,c-1)); } break; } } retval.append(out); return retval; } image-2.4.1/src/PaxHeaders.6632/bwfill.cc0000644000000000000000000000013212561122761014635 xustar0030 mtime=1438950897.786252238 30 atime=1438950897.786252238 30 ctime=1438950899.342252237 image-2.4.1/src/bwfill.cc0000644000175000017500000001477612561122761017477 0ustar00carandraugcarandraug00000000000000// Copyright (C) 1999 Andy Adler // // 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 3 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 . #include #define ptUP (-1) #define ptDN (+1) #define ptRT (+ioM) #define ptLF (-ioM) /* * check if the point needs to be filled, if so * fill it and change the appropriate variables */ void checkpoint (int pt, unsigned char *imo, int *ptstack, int *npoints) { // printf("filling %d np=%d fill=%d\n",pt,*npoints, *(imo+pt)==0 ); if (*(imo+pt) != 0) return; *(imo+pt) = 2; *(ptstack + (*npoints))= pt; (*npoints)++; } DEFUN_DLD (bwfill, args, ,"\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{bw2}, @var{idx}] =} bwfill(@var{bw1}, @var{c}, @var{r}, @var{n})\n\ Perform a flood-fill operation on the binary image @var{bw1}.\n\ \n\ The flood-filling starts in the pixel (@var{r}, @var{c}). If @var{r} and @var{c}\n\ are vectors of the same length, each pixel pair (@var{r}(i), @var{c}(i)) will\n\ be a starting point for a flood-fill operation.\n\ The argument @var{n} changes the neighborhood connectivity (of the holes) for the flood-fill\n\ operation. @var{n} can be either 4 or 8, and has a default value of 8.\n\ \n\ The output is the processed image @var{bw2} and the indexes of the filled\n\ pixels @var{idx}\n\ \n\ @end deftypefn\n\ @deftypefn {Loadable Function} {[@var{bw2}, @var{idx}] =} bwfill(@var{bw1}, \"holes\", @var{n})\n\ If the string \"holes\" is given instead of starting points for the flood-fill\n\ operation, the function finds interior holes in @var{bw1} and fills them.\n\ @end deftypefn\n\ ") { octave_value_list retval; octave_value tmp; ColumnVector xseed, yseed ; const int nargin = args.length (); if (nargin < 2 ) { print_usage (); return retval; } const Matrix im = args (0).matrix_value (); if (error_state) { error ("bwfill: first input argument must be a matrix"); return retval; } const int imM = im.rows (); const int imN = im.columns (); if (imM == 1 || imN == 1) // check for vector inputs. { retval (0)= im; retval (1)= ColumnVector (0); return retval; } int nb = 8; int npoints = 0; bool fillmode= false; if (args (1).is_string () && args (1).string_value () == "holes") { fillmode= true; npoints= 2 * (imM + imN - 4); // don't start fill from corners xseed = ColumnVector (npoints); yseed = ColumnVector (npoints); int idx= 0; for (int j=2; j<= imN-1; j++) { xseed (idx) = j; yseed (idx++) = 1; xseed (idx) = j; yseed (idx++) = imM; } for (int i=2; i<= imM-1; i++) { yseed (idx) = i; xseed (idx++) = 1; yseed (idx) = i; xseed (idx++) = imN; } if (nargin >= 3) nb = (int)args (2).double_value (); } else // end: holes mode? { { ColumnVector tmp (args (1).vector_value ()); if (error_state) { error ("bwfill: second input argument must be a string"); return retval; } xseed = tmp; } { ColumnVector tmp (args (2).vector_value ()); if (error_state) { error ("bwfill: third input argument must be a string"); return retval; } yseed = tmp; } npoints= xseed.length (); if (nargin >= 4) nb = (int)args (3).double_value (); } // holes mode? /* * put a one pixel thick boundary around the image * so that we can be more efficient in the main loop */ int ioM = imM + 2; OCTAVE_LOCAL_BUFFER (unsigned char, imo, (imM+2) * (imN+2)); for (int i = 0; i < imM; i++) for (int j = 0; j < imN; j++) imo [(i+1) + ioM*(j+1)] = (im (i, j) > 0); for (int i = 0; i < ioM; i++) imo [i]= imo [i + ioM*(imN+1)] = 3; for (int j = 1; j < imN+1; j++) imo [ioM*j]= imo[imM+1 + ioM*j] = 3; // This is obviously big enough for the point stack, but I'm // sure it can be smaller. OCTAVE_LOCAL_BUFFER (int, ptstack, ioM*imN); int seedidx = npoints; npoints= 0; while ( (--seedidx) >= 0 ) { // no need to add 1 to convert indexing style because we're adding a boundary const int x = xseed (seedidx); const int y = yseed (seedidx); if (x < 1 || y < 1 || x > imN || y > imM) { warning ("bwfill: (%d, %d) out of bounds", x, y); continue; } const int pt = x * ioM + y; checkpoint (pt , imo, ptstack, &npoints); } while (npoints > 0) { npoints--; int pt = ptstack [npoints]; checkpoint (pt + ptLF, imo, ptstack, &npoints); checkpoint (pt + ptRT, imo, ptstack, &npoints); checkpoint (pt + ptUP, imo, ptstack, &npoints); checkpoint (pt + ptDN, imo, ptstack, &npoints); if (nb==8) { checkpoint (pt + ptLF + ptUP, imo, ptstack, &npoints); checkpoint (pt + ptRT + ptUP, imo, ptstack, &npoints); checkpoint (pt + ptLF + ptDN, imo, ptstack, &npoints); checkpoint (pt + ptRT + ptDN, imo, ptstack, &npoints); } } // while ( npoints > 0) boolNDArray imout ( dim_vector (imM, imN)); ColumnVector idxout (imM*imN); int idx = 0; int notvalidpt = 0; int idxpoint = 2; if (fillmode) { notvalidpt = 2; idxpoint = 0; } for (int i = 0; i < imM; i++) for (int j = 0; j < imN; j++) { imout (i, j) = imo [(i+1) + ioM*(j+1)] != notvalidpt; if (imo [(i+1) + ioM*(j+1)] == idxpoint) idxout (idx++) = (double) (i + j*imM + 1); } /* Matrix imout( imM+2, imN+2 ); for (int i=0; i 0) retval (1)= idxout.extract (0, idx-1); else retval (1)= ColumnVector (0); return retval; } image-2.4.1/PaxHeaders.6632/NEWS0000644000000000000000000000013212561122761012757 xustar0030 mtime=1438950897.666252238 30 atime=1438950897.666252238 30 ctime=1438950899.342252237 image-2.4.1/NEWS0000644000175000017500000005651212561122761015613 0ustar00carandraugcarandraug00000000000000 Summary of important user-visible changes for image 2.4.1 (2015/08/07): ------------------------------------------------------------------------- ** Image 2.4.1 is a bug fixing release. ** Fixed regression on bwhitmiss which was completely broken since version 2.2.0. ** Fixed regressions on rangefilt and stdfilt which made them always throw an error. ** Removed broken support for signed integers to entropyfilt(). Not only it was returning incorrect values and ocasional endless loops, it failed to build in some architectures. Summary of important user-visible changes for image 2.4.0 (2015/04/06): ------------------------------------------------------------------------- ** The following functions are new: bwareafilt imcast imregionalmin bwpropfilt imclearborder otf2psf edgetaper immse psf2otf fftconvn imreconstruct psnr imattributes imregionalmax subimage ** The implementation of normxcorr2 has been changed. The new method is Matlab compatible and will return values in the range [-1 1]. ** The image package is no longer dependent on the signal package. ** The disk shaped filter of fspecial has been changed for Matlab compatibility. The elements on the border of the disk are now weighted by how much of them is covered by the disk. Note that this change is backwards incompatible. ** The following functions will display the output image as a figure instead of printing to the command line, when there are no output arguments: grayslice im2bw ** For better compatibility with Matlab, the imrotate, imremap, and imperspectivewarp functions now use 0 instead of NA for the default extrapolation value. ** The regionprops function now supports the "Eccentricity", "MajorAxisLength", "MinorAxisLength", "EquivDiameter" and "Extrema" properties. The "Orientation" property has also been rewritten for Matlab compatibility and may yield different results than previous versions. ** The conndef function has new function signatures so that it covers all common ways of defining an connectivity array. The following will return the same matrix: mask = conndef (2, "minimal") mask = conndef (4) mask = conndef ([0 1 0; 1 1 1; 0 1 0]) and would throw a detailed error in case of an incorrect connectivity. ** Creating disk shaped strel objects must now specify the N argument for number of periodic lines used to approximate a disk. The value used must be zero to obtain the same results as previous releases of the image package. No other value is at the moment valid, and this is to prevent future backwards incompatibility since Matlab default is 4. Replace any `strel ("disk", radius)' with `strel ("disk", radius, 0)' ** The following functions have been completely rewritten and will perform a lot of faster. bwconncomp bwlabeln Which indirectly will also cause the following to perform faster: bwareaopen bwpropfilt regionprops ** Deprecated functions. The following functions were deprecated in image 2.2.0 and have been removed from image 2.4.0. bwborder iptchecknargin readexif impad iptcheckstrs imrotate_Fourier uintlut ** Other functions that have been changed for smaller bugfixes, increased Matlab compatibility, or performance: grayslice im2single imsmooth im2double im2uint8 label2rgb im2int16 im2uint16 Summary of important user-visible changes for image 2.2.2 (2014/10/06): ------------------------------------------------------------------------- ** Multiple documentation fixes for compatibility with new versions of Texinfo. ** Fix error with imcrop when image was all zeros. ** Fix endless loop in bwdist when using the quasi-euclidean method in x86 systems. Summary of important user-visible changes for image 2.2.1 (2014/03/08): ------------------------------------------------------------------------- ** imcrop had many alternative interfaces added for more flexibility. Added support in the input for indexed images, figures handles, N-dimensional images, and specific bounding box vector for a non-interactive usage. Output can now also return the bounding box used for the cropping in addition to the cropped image. It will no longer loop forever until it gets two valid coordinates for the bounding box. ** Fixed bug in imcomplement to compute the complement of signed integers correctly. ** Fix imrotate to handle RGB images. ** Fix regression in bwdist when calculating the closest pixel map. Summary of important user-visible changes for image 2.2.0 (2014/01/08): ------------------------------------------------------------------------- ** The imerode and imdilate have been completely rewritten for increased performance and many Matlab compatibility fixes. Performance gains between 1.5-30X have been demonstrated. Main compatibility changes include the addition of the shape option, support for the strel class, and allowing structuring elements and images of different classes. Non-flat grayscale erosion and dilation has also been implemented by making use of the new strel class. ** With the increased performance in imerode and imdilate, all other functions that use them, such imopen and imclose, get an equivalent performance boost. ** Most of bwmorph operations now support N dimensional images and have increased performance. Other Matlab compatibility fixes have been made such as displaying image when there's no output variable. ** The __spatial_filtering__ function has been mostly rewritten and performs in approximattely 1/5 to 2/5 of the previous time, depending on the filter. With this change, all functions dependent on it, rangefilt, entropyfilt, ordfilt2/n, medfilt2/n, and stdfilt, will also perform faster. ** The following functions are new: bwareaopen impixel strel checkerboard imtransform tformfwd cp2tform intlut tforminv findbounds labelmatrix ycbcr2rgb imgradient maketform imgradientxy montage ** The following functions have been moved from the Octave Forge Image package to GNU Octave core: cmpermute cmunique iscolormap rgbplot ** The following functions have been deprecated in the previous release of the Image package and have now been removed: blkproc bmpwrite dilate erode ** The following functions have been deprecated (see their help text for the recommended alternatives): bwborder imrotate_Fourier iptcheckstrs impad iptchecknargin uintlut ** The functions im2col and col2im has been completely rewritten for massive performace increase (increases greater than 500X have been observed, with biggest differences for smaller blocks and sliding option), and support of N-dimensional blocks and images. ** rgb2ycbcr was completely rewritten to accept images of other classes, and colormaps. A new argument was implemented to convert the RGB values according to different standards. ** The use of non logical matrices to specify the neighborhood for the medfilt2 function has been deprecated. Also, when using a vector to specify the size of the neighborhood, the elements were swapped (first element is now the number of rows and the second the number of columns). ** For consistency with other functions that allow specification of padding values, the function padarray now accepts the string "zeros" as a valid option. ** The plot produced by imhist is correctly scaled on the X axis so that the colorbar corresponds to the actual intensity of the stems; the given colormarp is used on the colorbar for indexed images; and the stems no longer display the markers at their top. The Y axis is also adjusted in case of peaks with high values that prevent a good overview of the histogram. ** The option to create poisson noise to an image has been added to imnoise. ** With the addition of the strel class, imdilate and imerode are able to handle strel objects. ** The performance of imresize has been greatly improved when using the nearest neighbor method for N or 1/N scale factors (e.g.: 2, 50, 1/4, 1/7). ** The imperspectivewarp, imremap, imresize, and imrotate functions will now accept any interpolation method from the interp2 function thus extending the available methods to "spline" and "pchip". This in addition to the "bilinear" and "bicubic" methods (same as "linear" and "cubic" respectively) which are kept for matlab compatibility. For the same reason, the "triangle" method (interpolation kernel) has also been added (which is the same as "linear" method). ** Bug fixes on the concavity, intermodes, maxlikelihood, and minimum methods of graythresh. ** The bwdist function will now consider any non zero value as object pixels, the class of the distance matrix has changed to single, and indexes an uint dependent on the matrix size. ** The transform option of imtophat has been removed (it was deprecated in version 2.0.0) in favour of using imbothat. ** The function bwconncomp now returns the indices for each element in each object, no longer the indices for the elements in the object boundaries only. The connectivity default was changed to 8. ** The original Shepp-Logan model in the function phantom as been changed to return all values in the range [0 1] rather than [0 2] by changing the intensity of the first ellipse from 2 to 1. ** Other functions that have been changed for smaller bugfixes, increased Matlab compatibility, or performance: bwlabel bwperim padarray ** The following functions now fully support matrices with an arbitrary number of dimensions: bestblk col2im im2col bwconncomp colfilt nlfilter Summary of important user-visible changes for image 2.0.0 (2012/11/08): ------------------------------------------------------------------------- ** The following functions are new: analyze75info imabsdiff iptcheckconn analyze75read imadd iptcheckmap analyze75write imbothat iptchecknargin blockproc imcrop iptcheckstrs bwlabeln imdivide iptnum2ordinal getrangefromclass imlincomb iscolormap im2int16 immultiply normxcorr2 im2single imsubtract wavelength2rgb ** The following functions have been deprecated in previous releases of the image package and have now been removed: imginfo ** The function `deriche' has been removed. ** The complete set of functions to work with Analyze 7.5 files has been implemented. See `analyze75info', `analyze75read' and `analyze75write'. ** `graythresh' can optionally accept an histogram rather than an image. This allows for preprocessing of the histogram previous to an automatic threshold selection. ** Otsu's method for automatic threshold selection (default for `graythresh') has been completely rewritten and should perform faster. Now, it can also return a second value representing the ``goodness'' of the computed threshold value (within class variance). ** Alternative algorithms for automatic threshold have been implemented in `graythresh' (thanks to Antti Niemistö for releasing HistThresh toolbox http://www.cs.tut.fi/~ant/histthresh/ from where many were ported, under a GPL license). Currently, the following algorithms have been implemented (see graythresh for notes and references): concavity MaxEntropy minimum Otsu intermeans MaxLikelihood MinError percentile intermodes mean moments ** The following functions have been deprecated (see their help text for the recommended alternatives): blkproc bmpwrite dilate erode ** With the new function `imbothat' the transform option of `imtophat' has been deprecated. ** The following functions have had been changed for bug fixes and/or improved matlab compatibility bwarea imhist im2uint8 isind bweuler imnoise im2uint16 mat2gray bwfill conndef isbw rgb2gray cmpermute im2bw isgray cmunique im2double isrgb ** `bwarea' now supports all image classes and considers objects all non zero pixels (not all pixels higher than zero). ** `rgb2gray' now also supports images of the class single and performs a weighted conversion to keep the image luminance instead of a the mean through each color. ** `im2bw' now supports input images of the int16 class and deals better with RGB images since it uses `rgb2gray' internally (see changes to rgb2gray). Threshold is performed on all values greater than value instead of greater than or equal. ** `imhist' is much more compatible with matlab and among other changes, it now uses the whole range of the class for the histogram rather than the minimum and maximum of the input image and displays a colorbar under the histogram. ** `isbw' now defines a black-and-white image as a binary non-sparse matrix. This is compatible with matlab. To use the old behaviour, use the new option for the call "isbw (img, "non-logical"). For backwards compatibility, if a non-logical matrix of 0 and 1 is used as input, `isbw' will still return true but a warning will be issued since this will deprecated later. ** `isgray' now also returns true for matrices of the int16 class. ** `isrgb' now returns false for logical matrix. ** `tiff_tag_read' had several bug fixes and can now check IFDs beyond the first. It can also accept mutiple tag values and IFDs simultaneously and return a matrix of the values found. Its documentation has been expanded (as well as an explanation of TIFF structure on the source) ** For sake of matlab compatibility, the behaviour of `mat2gray' has been greatly changed. Among the changes, it will no longer swap the minimum and maximum options if the first is larger than the later. Instead, will return the image complement after truncation. Also, when the maximum and minimum values are equal, `mat2gray' will truncate all values between 0 and 1. See the help text (or source) for a detailed description of cautions. ** `bwfill' was fixed to always returns a logical matrix. ** `imnoise' has been expanded to accept images of differente classes instead of only double and single. ** The private function `__bwdist` has been renamed `__bwdist__` ** Package is now dependent on GNU Octave version 3.6.0 or later. ** Package is now dependent on the signal package version 1.2.0 or later. ** Package is no longer automatically loaded. ******************************************************************************** ** ** ** NEWS below this point were written after their releases for history ** ** purposes and extracted from the Octave Forge general NEWS. Previous to ** ** the image package version 1.0.11, all Octave Forge packages would be ** ** released at the same time. Previous to the package version 1.0.0 there ** ** were monolithic releases with no actual packages. This means that some ** ** releases actually had no changes in the image package itself or changes ** ** were small compared to the whole Octave Forge project and so, not ** ** mentioned on the NEWS file. Inspection of the actual log in the ** ** repository should be used if exact details are required. ** ** ** ******************************************************************************** Summary of important user-visible changes for image 1.0.15 (2011/09/21): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.14 (2011/04/12): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.13 (2010/05/22): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.12 (2010/03/22): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.11 (2010/03/05): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.10 (2009/06/07): -------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.9 (2009/05/08): ------------------------------------------------------------------------- ** The following functions are new: entropyfilt ordfiltn rangefilt stdfilt ** The following functions have been removed as they are now part of Octave core: imread imwrite Summary of important user-visible changes for image 1.0.8 (2008/08/31): ------------------------------------------------------------------------- ** Fix build issues with the last release. Summary of important user-visible changes for image 1.0.7 (2008/08/24): ------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.6 (2008/04/29): ------------------------------------------------------------------------- ** The following functions are new: imcomplement rgbplot ** Implemented support for bilateral filtering. ** Build fixes for new versions of ImageMagick. Summary of important user-visible changes for image 1.0.5 (2008/02/16): ------------------------------------------------------------------------- ** The following functions are new: imfilter imsmooth Summary of important user-visible changes for image 1.0.4 (2007/12/12): ------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.3 (2007/10/14): ------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.2 (2007/07/26): ------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.1 (2007/05/26): ------------------------------------------------------------------------- Summary of important user-visible changes for image 1.0.0 (2007/03/28): ------------------------------------------------------------------------- ** First non-monolithic release. ** The following functions are new: __bwarea fspecial impersepectivewap apply graythresh imremap bwarea im2double label2rgb bwperim im2uint8 __magick_read__ deriche im2uint16 ** Fixex for non 8bit images. ** Quantum sizes in imagemagick. ** Compatiability changes to imwrite, isgray and rgb2gray. ** imread, probe depth from bits rather than Red field, allows loading of gray scale images. ** Convert all functions to use texinfo help. Summary of important user-visible changes for image (Octave Forge 2006.07.09): -------------------------------------------------------------------------------- Summary of important user-visible changes for image (Octave Forge 2006.03.17): -------------------------------------------------------------------------------- Summary of important user-visible changes for image (Octave Forge 2006.01.28): -------------------------------------------------------------------------------- ** imread() now return the appropriate numeric class. Colour images are of size MxNx3, gray images MxN. Summary of important user-visible changes for image (Octave Forge 2005.06.13): -------------------------------------------------------------------------------- ** The following functions are new: bwarea imresize Summary of important user-visible changes for image (Octave Forge 2004.11.16): -------------------------------------------------------------------------------- ** No important changes to the image package in this Octave Forge release. Summary of important user-visible changes for image (Octave Forge 2004.09.09): -------------------------------------------------------------------------------- ** The following functions are new: applylut cmunique houghtf poly2mask uintlut bestblk col2im im2col qtdecomp blkproc conndef isrgb qtgetblk bweuler dilate makelut qtsetblk bwmorph erode nlfilter roicolor cmpermute graycomatrix padarray stretchlim ** Implemented initial support for int* types. Summary of important user-visible changes for image (Octave Forge 2004.07.07): -------------------------------------------------------------------------------- ** No important changes to the image package in this Octave Forge release. Summary of important user-visible changes for image (Octave Forge 2004.02.12): -------------------------------------------------------------------------------- ** `imread' now supports 16-bit grayscale images. Summary of important user-visible changes for image (Octave Forge 2003.06.02): -------------------------------------------------------------------------------- ** The following functions are new: rotate_scale Summary of important user-visible changes for image (Octave Forge 2003.02.22): -------------------------------------------------------------------------------- ** No important changes to the image package in this Octave Forge release. Summary of important user-visible changes for image (Octave Forge 2002.11.30): -------------------------------------------------------------------------------- ** The following functions are new: colfilt imginfo imrotate imshear imtranslate ** The `colorgradient' function now allow instantaneous transitions (weight 0) ** The `bwlabel' function has been implemented in C++ and may behave different. Summary of important user-visible changes for image (Octave Forge 2002.05.09): -------------------------------------------------------------------------------- Summary of important user-visible changes for image (Octave Forge 2002.04.20): -------------------------------------------------------------------------------- Summary of important user-visible changes for image (Octave Forge 2002.03.10): -------------------------------------------------------------------------------- Summary of important user-visible changes for image (Octave Forge 2001.11.02): -------------------------------------------------------------------------------- ** First release.