./PaxHeaders.16724/image-2.6.20000644000000000000000000000013213201323064012415 xustar0030 mtime=1510319668.279933706 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/0000755000175000017500000000000013201323064015075 5ustar00carandraugcarandraug00000000000000image-2.6.2/PaxHeaders.16724/inst0000644000000000000000000000013213201323063013234 xustar0030 mtime=1510319667.159947464 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/inst/0000755000175000017500000000000013201323063016051 5ustar00carandraugcarandraug00000000000000image-2.6.2/inst/PaxHeaders.16724/imtranslate.m0000644000000000000000000000013213201323063016012 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imtranslate.m0000644000175000017500000000510413201323063020552 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, nc, nr, bbox = "wrap") if (strcmp (bbox, "crop")) pre = post = [0 0]; if (nc > 0) post(2) = ceil (nc); else pre(2) = ceil (nc); endif if (nr > 0) pre(1) = ceil (nr); else post(1) = ceil (nr); endif pre = abs (pre); post = abs (post); X = padarray (X, abs (pre), "pre"); X = padarray (X, abs (post), "post"); endif [dimy, dimx] = size(X); x = fft2(X); px = exp(-2*pi*i*nc*(0:dimx-1)/dimx); py = exp(-2*pi*i*nr*(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")) Y = Y(pre(1)+1:dimy-post(1) , pre(2)+1:dimx-post(2)); endif endfunction %!test %! obs = imtranslate (ones (5, 5), 2, 1, "crop"); %! exp = zeros (5, 5); %! exp(1:4, 3:5) = 1; %! assert (obs, exp, eps * 10) %! %! obs = imtranslate (ones (5, 5), -2, -1, "crop"); %! exp = zeros (5, 5); %! exp(2:5, 1:3) = 1; %! assert (obs, exp, eps * 10) image-2.6.2/inst/PaxHeaders.16724/montage.m0000644000000000000000000000013013201323063015117 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/montage.m0000644000175000017500000003441713201323063017672 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}. Of special significance is that an empty array uses the ## image minimum and maximum values for limits. Defaults to the limits of ## the image data type, i.e., the range returned by @code{getrangefromclass}. ## ## @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; filepath = img_info(1).Filename; ## 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 (filepath, 1:nPages); else [tmp_img, map] = imread (filepath, 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 im_type_range = getrangefromclass (images); if (strfind (which ("inputParser"), ["@inputParser" filesep "inputParser.m"])) p = p.addParamValue ("DisplayRange", im_type_range, @(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", im_type_range(2), @(x) isnumeric (x) && any (numel (x) == [1 3])); p = p.addParamValue ("BackgroundColor", im_type_range(1), @(x) isnumeric (x) && any (numel (x) == [1 3])); p = p.parse (varargin{:}); else p.addParamValue ("DisplayRange", im_type_range, @(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", im_type_range(2), @(x) isnumeric (x) && any (numel (x) == [1 3])); p.addParamValue ("BackgroundColor", im_type_range(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 = p.Results.Size(1); nCols = 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; ## When there is more than one layout that returns equal "squariness", ## we must pick the one with most columns. This is because monitors ## have more horizontal space, so a wider image will be better. Hence ## the "last". [nRows, nCols] = find (HxW_diff == min (HxW_diff(:)), 1, "last"); 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 tmp_h = imshow (disp_img, p.Results.DisplayRange); 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 %!function cdata = montage_cdata (varargin) %! h = figure (); %! set (h, "visible", "off"); %! mh = montage (varargin{:}); %! cdata = get (mh, "cdata"); %! close (h); %!endfunction ## Test automatic distribution of panels %!test %! im = uint8 (ones (2, 2, 1, 5)) .* reshape ([1 2 3 4 5], [1 1 1 5]); %! cdata = montage_cdata (im); %! expected = uint8 ([ %! 1 1 2 2 3 3 %! 1 1 2 2 3 3 %! 4 4 5 5 0 0 %! 4 4 5 5 0 0 %! ]); %! assert (cdata, expected) %!test %! im = uint8 (ones (2, 4, 1, 6)) .* reshape ([1 2 3 4 5 6], [1 1 1 6]); %! cdata = montage_cdata (im); %! expected = uint8 ([ %! 1 1 1 1 2 2 2 2 %! 1 1 1 1 2 2 2 2 %! 3 3 3 3 4 4 4 4 %! 3 3 3 3 4 4 4 4 %! 5 5 5 5 6 6 6 6 %! 5 5 5 5 6 6 6 6 %! ]); %! assert (cdata, expected) image-2.6.2/inst/PaxHeaders.16724/im2uint16.m0000644000000000000000000000013213201323063015225 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2uint16.m0000644000175000017500000000624013201323063017767 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.6.2/inst/PaxHeaders.16724/normxcorr2.m0000644000000000000000000000013013201323063015600 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/normxcorr2.m0000644000175000017500000001252613201323063020350 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 cross-correlation coefficient of matrices @var{template} ## and @var{img}, a matrix of (roughly) 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. ## ## Note that the size of the cross-correlation array is slightly bigger ## than @var{img} because the input image is padded during the calculation. ## ## @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))); ## remove small machine precision errors after substraction b(b < 0) = 0; 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); ## test for no small imaginary parts in result (bug #46160) %!test %! a = [ 252 168 50 1 59; %! 114 0 0 0 0] ./ 255; %! b = [ 1 171 255 255 255 255 240 71 131 254 255 255 255; %! 0 109 254 255 255 233 59 0 131 254 255 255 255; %! 76 13 195 253 194 34 0 19 217 255 255 255 255; %! 110 0 0 0 0 0 3 181 255 255 255 255 255; %! 153 0 0 0 0 2 154 254 255 255 255 255 255]./255; %! c = normxcorr2 (a, b); %! assert (max (imag (c(:))), 0); image-2.6.2/inst/PaxHeaders.16724/psf2otf.m0000644000000000000000000000013213201323063015052 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/psf2otf.m0000644000175000017500000000641113201323063017614 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.6.2/inst/PaxHeaders.16724/ordfiltn.m0000644000000000000000000000013013201323063015306 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/ordfiltn.m0000644000175000017500000001140013201323063020044 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.6.2/inst/PaxHeaders.16724/imregionalmax.m0000644000000000000000000000013213201323063016323 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/imregionalmax.m0000644000175000017500000000547313201323063021074 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.6.2/inst/PaxHeaders.16724/houghtf.m0000644000000000000000000000013213201323063015133 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/houghtf.m0000644000175000017500000000760713201323063017705 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.6.2/inst/PaxHeaders.16724/iptnum2ordinal.m0000644000000000000000000000013213201323063016436 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/iptnum2ordinal.m0000644000175000017500000000667513201323063021214 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.6.2/inst/PaxHeaders.16724/fchcode.m0000644000000000000000000000013213201323063015062 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/fchcode.m0000644000175000017500000000472713201323063017634 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.6.2/inst/PaxHeaders.16724/fftconv2.m0000644000000000000000000000013213201323063015216 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/fftconv2.m0000644000175000017500000001303513201323063017760 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2013-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 ## . ## ## This file incorporates work covered by the following copyright and ## permission notice: ## ## 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.6.2/inst/PaxHeaders.16724/lab2xyz.m0000644000000000000000000000013213201323063015062 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/lab2xyz.m0000644000175000017500000001247013201323063017626 0ustar00carandraugcarandraug00000000000000## 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{xyz} =} lab2xyz (@var{lab}) ## @deftypefnx {Function File} {@var{xyz_map} =} lab2xyz (@var{lab_map}) ## Transform a colormap or image from CIE L*a*b* to CIE XYZ color space. ## ## A color in the CIE L*a*b* (or CIE Lab) space consists of lightness L* and ## two color-opponent dimensions a* and b*. The whitepoint is taken as D65. ## The CIE L*a*b* colorspace is a colorimetric colorspace, meaning that their values ## do not depend on the display device hardware. This colorspace is designed ## to incorporate the human perception of color differences. ## ## A color in the CIE XYZ color space consists of three values X, Y and Z. ## Those values are also designed to be colorimetric. ## ## Input values of class single and double are accepted. ## The shape and the class of the input are conserved. ## ## The input values of L* are normally in the inteval [0, 100] ## and the values of a* and b* in the interval [-127, 127]. ## ## @seealso{xyz2lab, rgb2lab, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function xyz = lab2xyz (lab) if (nargin != 1) print_usage (); endif [lab, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("lab2xyz", "Lab", lab, 1); # currently only accept single and double inputs (as Matlab does) # (Integer types would be possible, but would need an explanation in the # help text how to scale them.) ## use the whitepoint D65 (reference: en.wikipedia.org/wiki/Illuminant_D65) D65 = [0.95047, 1, 1.08883]; # Matlab truncates to D65_Matlab = [0.9504, 1.0000, 1.0888]; ## transformation Lab -> XYZ L = lab(:,1); a = lab(:,2); b = lab(:,3); L_prime = (L + 16) ./ 116; x = D65(1) .* f (L_prime + a./500); y = D65(2) .* f (L_prime); z = D65(3) .* f (L_prime - b./200); xyz = [x, y, z]; # always return values of type double for Matlab compatibility (exception: type single) xyz = colorspace_conversion_revert (xyz, cls, sz, is_im, is_nd, is_int, 1); endfunction function out = f (in) epsilon = (6/29)^3; kappa = 1/116 * (29/3)^3; out = in; mask = in.^3 > epsilon; out(mask) = in(mask).^3; out(! mask) = (in(! mask) - 16/116)./kappa; endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (lab2xyz ([0, 0, 0]), [0 0 0], 1e-3) %!assert (lab2xyz ([53.24, 80.09, 67.20]), [0.4125, 0.2127, 0.0193], 1e-3) %!assert (lab2xyz ([97.14, -21.55, 94.48]), [0.7700, 0.9278, 0.1385], 1e-3) %!assert (lab2xyz ([87.74, -86.18, 83.18]), [0.3576, 0.7152, 0.1192], 1e-3) %!assert (lab2xyz ([91.11, -48.09, -14.13]), [0.5380, 0.7873, 1.0694], 1e-3) %!assert (lab2xyz ([32.30, 79.19, -107.86]), [0.1804, 0.07217, 0.9502], 1e-3) %!assert (lab2xyz ([60.32, 98.24, -60.83]), [0.5929, 0.28484, 0.9696], 1e-3) %!assert (lab2xyz ([100, 0.00, 0.00]), [0.9505, 1.0000, 1.0888], 1e-3) %!assert (lab2xyz ([53.39, 0.00, 0.00]), [0.2034, 0.2140, 0.2330], 1e-3) %!assert (lab2xyz ([39.77, 64.51, 54.13]), [0.2155, 0.1111, 0.0101], 1e-3) %!assert (lab2xyz ([25.42, 47.91, 37.91]), [0.0883, 0.0455, 0.0041], 1e-3) %!assert (lab2xyz ([9.66, 29.68, 15.24]), [0.02094, 0.0108, 0.00098], 1e-3) %!assert (lab2xyz ([68.11, 48.39, 22.83]), [0.5276, 0.3812, 0.2482], 1e-3) ## Test tolarant input checking on floats %!assert (lab2xyz ([150 130 130]), [4.596, 2.931, 0.519], 1e-3) %!test %! lab_map = rand (64, 3); %! lab_map(:,1) = lab_map(:,1) .* 100; %! lab_map(:,2) = lab_map(:,2) .* 254 - 127; %! lab_map(:,3) = lab_map(:,3) .* 254 - 127; %! assert (xyz2lab (lab2xyz (lab_map)), lab_map, 1e-5); %!test %! lab_img = rand (64, 64, 3); %! lab_img(:,:,1) = lab_img(:,:,1) .* 100; %! lab_img(:,:,2) = lab_img(:,:,2) .* 254 - 127; %! lab_img(:,:,3) = lab_img(:,:,3) .* 254 - 127; %! assert (xyz2lab (lab2xyz (lab_img)), lab_img, 1e-5); ## support sparse input %!assert (lab2xyz (sparse ([0 0 0])), [0 0 0], 1e-3) %!assert (lab2xyz (sparse ([100, 0.00, 0.00])), [0.9505, 1.0000, 1.0888], 1e-3) ## conserve class of single input %!assert (class (lab2xyz (single([50 50 50]))), 'single') ## Test input validation %!error lab2xyz () %!error lab2xyz (1,2) %!error lab2xyz ({1}) %!error lab2xyz (ones (2,2)) ## Test ND input %!test %! lab = rand (16, 16, 3, 5); %! lab(:,:,1,:) = lab(:,:,1,:) .* 100; %! lab(:,:,2,:) = lab(:,:,2,:) .* 254 - 127; %! lab(:,:,3,:) = lab(:,:,3,:) .* 254 - 127; %! xyz = zeros (size (lab)); %! for i = 1:5 %! xyz(:,:,:,i) = lab2xyz (lab(:,:,:,i)); %! endfor %! assert (lab2xyz (lab), xyz) image-2.6.2/inst/PaxHeaders.16724/col2im.m0000644000000000000000000000013013201323063014652 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/col2im.m0000644000175000017500000002130013201323063017410 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.6.2/inst/PaxHeaders.16724/wavelength2rgb.m0000644000000000000000000000013213201323063016410 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/wavelength2rgb.m0000644000175000017500000001444113201323063021154 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.6.2/inst/PaxHeaders.16724/medfilt2.m0000644000000000000000000000013013201323063015173 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/medfilt2.m0000644000175000017500000001035113201323063017735 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.6.2/inst/PaxHeaders.16724/lab2uint16.m0000644000000000000000000000013213201323063015356 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/lab2uint16.m0000644000175000017500000000555013201323063020123 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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} {} lab2double (@var{lab}) ## Convert L*a*b* data to uint16 precision. ## ## @var{lab} must be a L*a*b* image or colormap, i.e., its dimensions ## must be MxNx3xK or Mx3. Its type must be double, single, uint16, ## or uint8. ## ## When converted from double or single, L* values usually range from 0 to ## 100, while a* and b* range from -128 to 127. The upper limit values ## will be converted to 65280. ## ## @seealso{lab2double, lab2rgb, lab2single, lab2uint8, lab2uin16, lab2xyz} ## @end deftypefn function [lab] = lab2uint16 (lab) if (nargin () != 1) print_usage (); endif lab = lab2cls (lab, "uint16"); endfunction ## Instead of testing the lab2uint16 function here, we test the ## conversion from uint16 type. The actual tests for lab2uint16, ## are spread all other lab2* functions. This makes the tests ## simpler. %!test %! cm_uint16 = uint16 ([0 127 128 383 384 65151 65152 65279 65280 65281 65534 65535]); %! cm_uint16 = repmat (cm_uint16(:), [1 3]); %! im2d_uint16 = reshape (cm_uint16, [4 3 3]); %! imnd_uint16 = permute (im2d_uint16, [1 4 3 2]); %! %! cm_uint8 = uint8 ([0 0 1 1 2 254 255 255 255 255 255 255]); %! cm_uint8 = repmat (cm_uint8(:), [1 3]); %! assert (lab2uint8 (cm_uint16), cm_uint8) %! im2d_uint8 = reshape (cm_uint8, [4 3 3]); %! assert (lab2uint8 (im2d_uint16), im2d_uint8) %! assert (lab2uint8 (imnd_uint16), permute (im2d_uint8, [1 4 3 2])) %! %! l1 = 100/65280; %! ab1 = 255/65280; %! cm = [ %! 0 -128 %! 127*l1 -128+(ab1*127) %! 128*l1 -128+(ab1*128) %! 383*l1 -128+(ab1*383) %! 384*l1 -128+(ab1*384) %! 65151*l1 -128+(ab1*65151) %! 65152*l1 -128+(ab1*65152) %! 65279*l1 -128+(ab1*65279) %! 100 127 %! 65281*l1 -128+(ab1*65281) %! 65534*l1 -128+(ab1*65534) %! 65535*l1 -128+(ab1*65535)]; %! cm(:,3) = cm(:,2); %! im2d = reshape (cm, [4 3 3]); %! imnd = permute (im2d, [1 4 3 2]); %! %! assert (lab2double (cm_uint16), cm) %! assert (lab2double (im2d_uint16), im2d) %! assert (lab2double (imnd_uint16), imnd) %! %! assert (lab2single (cm_uint16), single (cm)) %! assert (lab2single (im2d_uint16), single (im2d)) %! assert (lab2single (imnd_uint16), single (imnd)) image-2.6.2/inst/PaxHeaders.16724/rgb2ycbcr.m0000644000000000000000000000013213201323063015346 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/rgb2ycbcr.m0000644000175000017500000000510513201323063020107 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" ## 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.6.2/inst/PaxHeaders.16724/imclose.m0000644000000000000000000000013213201323063015122 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imclose.m0000644000175000017500000001114713201323063017666 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.6.2/inst/PaxHeaders.16724/imquantize.m0000644000000000000000000000013213201323063015655 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/imquantize.m0000644000175000017500000001526013201323063020421 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} {[@var{quant}, @var{idx}] =} imquantize (@var{img}, @var{levels}) ## @deftypefnx {Function File} {[@dots{}] =} imquantize (@var{img}, @var{levels}, @var{values}) ## Quantize image with multiple threshold levels and values. ## ## This function reduces the number of unique values in @var{img} by ## performing multiple thresholds, one for each element in @var{levels}, ## and assigning it values from @var{values}. ## ## The output @var{quant} is the quantized image, of same size as @var{img} ## and same class as @var{values}. @var{idx} are the indices into ## @var{values} such that @code{@var{quant} == @var{values}(@var{idx})}. ## ## For the simpler case where @var{values} is not defined, it defaults ## to @code{1:N+1} and this function becomes equivalent to: ## ## @example ## out = ones (size (@var{img})); ## for i = 1:numel(@var{levels}) ## out(@var{img} > @var{levels}(i)) += 1; ## endfor ## @end example ## ## So that for example: ## ## @example ## >> img = [1 2 3; 4 5 6; 7 8 9]; ## >> imquantize (img, [3 6]) ## @result{} ans = ## ## 1 1 1 ## 2 2 2 ## 3 3 3 ## @end example ## ## For the more general case, when @var{values} is defined, this function ## is equivalent to: ## ## @example ## @var{levels} = [-Inf @var{levels} Inf]; ## out = zeros (size (@var{img}), class (@var{values})); ## for i = 1:numel(@var{values}) ## out(@var{img} > @var{levels}(i) & @var{img} <= @var{levels}(i+1)) = @var{values}(i); ## endfor ## @end example ## ## So that for example: ## ## @example ## >> img = [1 2 3; 4 5 6; 7 8 9]; ## >> imquantize (img, [3 6], [0 5 8]) ## @result{} ans = ## ## 0 0 0 ## 5 5 5 ## 8 8 8 ## @end example ## ## @seealso{gray2ind, ind2gray, ind2rgb, intlut, label2rgb, lookup, rgb2ind} ## @end deftypefn function [quant, idx] = imquantize (img, levels, values) if (nargin < 2 || nargin > 3) print_usage (); elseif (! isimage (img)) error ("imquantize: IMG must be an image - numeric array with real values"); endif validateattributes (levels, {"numeric"}, {"nondecreasing", "vector"}, "imquantize", "LEVELS"); ## Add eps to levels because lookup does ## "table(idx(i)) <= y(i) < table(idx(i+1))" ## But we want: ## "table(idx(i)) < y(i) <= table(idx(i+1))" levels = double (levels); if (isfloat (img)) ## Beware when img is of class single. The comparison in lookup() ## will be done in the class of the image if it is float. levels += eps (cast (levels, class (img))); else levels += eps (levels); endif idx = lookup ([-Inf; levels(:); Inf], img); if (nargin < 3) quant = idx; else if (! isvector (values) || ! isnumeric (values)) error ("imquantize: VALUES must be a numeric vector") elseif (numel (values) != numel (levels) +1) error ("imquantize: VALUES must have 1 element more than LEVELS"); endif quant = values(idx); endif endfunction %!error %! imquantize (rand (5), [3 4 2 5]) %!error %! imquantize (rand (5), [1 2 3], "foo") %!error %! imquantize (rand (5), [1 2 3 4], 1:6) %!error %! imquantize (rand (5), [1 2 3 4], 1:2) %!test %! img = [-inf 0 10000000; -100000 -3 1/1000000; 5 5 10]; %! [q, q_idx] = imquantize (img, 5); %! assert (q, [1 1 2; 1 1 1; 1 1 2]) %! assert (q_idx, q) %!test %! img = [1:10; 11:20; 21:30; 31:40; 41:50; 51:60; 61:70]; %! %! expected_q = [ %! 0 0 0 0 0 1 1 1 1 1 %! 1 1 1 1 1 5 5 5 5 5 %! 5 5 5 5 5 10 10 10 10 10 %! 20 20 20 20 20 20 20 20 20 20 %! 30 30 30 30 30 30 30 30 30 30 %! 30 30 30 30 30 30 30 30 30 30 %! 15 15 15 15 15 15 15 15 15 15]; %! %! expected_q_idx = [ %! 1 1 1 1 1 2 2 2 2 2 %! 2 2 2 2 2 3 3 3 3 3 %! 3 3 3 3 3 4 4 4 4 4 %! 5 5 5 5 5 5 5 5 5 5 %! 6 6 6 6 6 6 6 6 6 6 %! 6 6 6 6 6 6 6 6 6 6 %! 7 7 7 7 7 7 7 7 7 7]; %! %! [q, q_idx] = imquantize (img, [5 15 25 30 40 60], [0 1 5 10 20 30 15]); %! assert (q, expected_q) %! assert (q_idx, expected_q_idx) %! %! [q, q_idx] = imquantize (single (img), [5 15 25 30 40 60], %! [0 1 5 10 20 30 15]); %! assert (q, expected_q) %! assert (q_idx, expected_q_idx) %! %! [q, q_idx] = imquantize (uint8 (img), [5 15 25 30 40 60], %! [0 1 5 10 20 30 15]); %! assert (q, expected_q) %! assert (q_idx, expected_q_idx) %! %! [q, q_idx] = imquantize (uint8 (img), uint8 ([5 15 25 30 40 60]), %! [0 1 5 10 20 30 15]); %! assert (q, expected_q) %! assert (q_idx, expected_q_idx) %! %! [q, q_idx] = imquantize (uint8 (img), uint8 ([5 15 25 30 40 60]), %! uint8 ([0 1 5 10 20 30 15])); %! assert (q, uint8 (expected_q)) %! assert (q_idx, expected_q_idx) ## Test output class %!test %! img = randi ([0 255], 10, "uint8"); %! [q, q_idx] = imquantize (img, [50 100 150 200]); %! assert (class (q), "double") %! assert (class (q_idx), "double") %! %! [q, q_idx] = imquantize (img, [50 100 150 200], uint16 ([5 7 8 9 2])); %! assert (class (q), "uint16") %! assert (class (q_idx), "double") %! %! [q, q_idx] = imquantize (img, [50 100 150 200], uint8 ([5 7 8 9 2])); %! assert (class (q), "uint8") %! assert (class (q_idx), "double") ## A test with non-ordered pixel values, tested against ordered %!test %! img = [1:10; 11:20; 21:30; 31:40; 41:50; 51:60; 61:70].'; %! r_idx = reshape (randperm (numel (img)), size (img)); %! %! [quant, quant_idx] = imquantize (img, [5 15 25 30 40 60]); %! [quant_r, quant_r_idx] = imquantize (img(r_idx), [5 15 25 30 40 60]); %! %! assert (imquantize (img(r_idx), [5 15 25 30 40 60]), quant(r_idx)) %! assert (quant_r, quant_r_idx) image-2.6.2/inst/PaxHeaders.16724/analyze75write.m0000644000000000000000000000013213201323063016361 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/analyze75write.m0000644000175000017500000002431113201323063021122 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.6.2/inst/PaxHeaders.16724/stretchlim.m0000644000000000000000000000013213201323063015645 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/stretchlim.m0000644000175000017500000003261113201323063020410 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2004 Josep Monés i Teixidor ## 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} {} stretchlim (@var{I}) ## @deftypefnx {Function File} {} stretchlim (@var{RGB}) ## @deftypefnx {Function File} {} stretchlim (@dots{}, @var{tol}) ## Find limits to contrast stretch an image. ## ## Returns a 2 element column vector, @code{[@var{low}; @var{high}]}, ## with the pair of intensities to contrast stretch @var{I} which ## saturates at most @var{tol} of the image. The output of this ## function matches the input expected by @code{imadjust}. ## ## The input argument @var{tol}, controls the fraction of the image to be ## saturated and defaults to @code{[0.01 0.99]}, i.e., a 1% saturation ## on both sides of the image histogram. It can be specified in two ways: ## ## @itemize ## @item a two element vector with lower and higher fraction of the ## the image to be saturated. These values must be in the range ## [0 1], the display range of images of floating point class. ## ## @item a scalar value with the fraction of image to be saturated on ## each side; e.g., a @var{tol} with a value of @code{0.05} is equivalent ## to @code{[0.05 0.95]}. This value must be in the range @code{[0 0.5]}. ## ## @end itemize ## ## A common use case wanting to maximize contrast without causing any ## saturation. In such case @var{tol} should be 0 (zero). It is the ## equivalent to @code{[min(@var{I}(:)); max(@var{I}(:))]} for a single ## plane. ## ## The return values are of class double and in the range [0 1] regardless ## of the input image class. These values are scaled in the image class ## range (see @code{im2double}). ## ## If the input is a RGB image, i.e., the 3rd dimension has length 3, then ## it returns a @code{[2 3]} matrix with separate limits for each colour. ## It will actually do this for each plane, so an input of size, ## @code{[M N P]} will return a @code{[2 P]} matrix. ## ## Higher dimensions of @var{I} are also valid. As in the 3 dimensional ## case, the limits for each 2 dimensional plane are returned in a 2 row ## vector for each 2 dimensional plane, one dimension below. That is, an ## input of size @code{[M N P Q R]} will return an array of size ## @code{[2 P Q R]}. ## ## Note the detail that @var{tol} is the maximum fraction of saturation. ## It is rare that there is a value for that exact saturation. In such ## case, @code{stretchlim} will always round down and saturate less. ## @var{tol} is the saturation limit. For example, if @var{tol} is ## @code{0.10}, but there are only values that will lead to 5 or 11% ## saturation, it will return the value for a 5% saturation. ## ## @seealso{brighten, contrast, histeq, imadjust} ## @end deftypefn function low_high = stretchlim (img, tol = [0.01 0.99]) if (nargin () <1 || nargin () > 2) print_usage (); endif if (! isimage (img)) error("stretchlim: I or RGB must be an image"); endif ## Handle tol if (nargin > 1) if (! isnumeric (tol)) error ("stretchlim: TOL must be numeric"); endif if (isscalar (tol)) if (min (tol) < 0 || max (tol) > 0.5) error ("stretchlim: TOL must be in the [0 1] range"); endif tol = [tol (1-tol)]; elseif (isvector (tol)) if (numel (tol) != 2) error ("stretchlim: TOL must be a 2 element vector"); endif endif endif ## tol is about the percentage of values that will be saturated. ## So instead of percentages, we convert to the actual number of ## pixels that need to be saturated. After sorting the values in ## the image, that number of pixels simply becomes the index for ## the limits. ## ## Note that the actual intensity value that we set the limits to, ## is not saturated. Only the values below or above the lower and ## higher limits it will be considered saturated. ## ## And since most images will have repeated values in the pixels, ## chances are that there's not a limit that would cause only the ## exact percentage of pixels to be saturated. In such cases, we ## must prefer a limit that would saturate less pixels than the ## requested, rather than the opposite. ## ## We want to compute this for each plane, so we reshape the image ## in order to have each plane into a single column, while respecting ## any other dimensions beyond the 3rd. sz = postpad (size (img), max (3, ndims (img)), 1); plane_length = sz(1) * sz(2); img = reshape (img, [plane_length sz(3:end)]); lo_idx = floor (tol(1) * plane_length) + 1; hi_idx = ceil (tol(2) * plane_length); if (lo_idx == 1 && hi_idx == plane_length) ## special case, equivalent to tol [0 1], even if tol was not ## actually [0 1] but the image size would effectively make it. low_high = [min(img, [], 1); max(img, [], 1)]; else strides = reshape ((0:plane_length:(numel(img)-1)), [1 sz(3:end)]); lo_hi_idx = [lo_idx; hi_idx] .+ strides; sorted = sort (img, 1); low_high = sorted(lo_hi_idx); endif low_high = im2double (low_high); ## This will only happen if the input was floating point and with ## values already outside the [0 1] range (common for users to simply ## convert an uint8 image to double and forget that display is [0 1] ## only). low_high(low_high < 0) = 0; low_high(low_high > 1) = 1; ## If a plane has a single value, then both limits will have the same ## value. In such case, we must return [0; 1] equal_cols = low_high(1,:) == low_high(2,:); low_high(:, equal_cols) = repmat ([0; 1], 1, nnz (equal_cols)); endfunction %!error (stretchlim ()); %!error (stretchlim ("bad parameter")); #%!error (stretchlim (zeros (10, 10, 3, 2))); %!error (stretchlim (zeros (10, 10), "bad parameter")); %!error (stretchlim (zeros (10, 10), 0.01, 2)); ## default parameters %!assert (stretchlim (0.01:.01:1), [0.02; 0.99]) %!assert (stretchlim (0.01:.01:1), stretchlim (0.01:.01:1, [0.01 0.99])) ## use scalar for tol %!assert (stretchlim (0.01:.01:1, 0.15), stretchlim (0.01:.01:1, [0.15 0.85])) ## this is different than Matlab but it looks like it's a Matlab bug ## (Matlab returns [0.018997482261387; 0.951003280689708]) ## We actually have differences from Matlab which sometimes returns ## values that are not present in the image. %!assert (stretchlim (0.01:.01:1, [0.01,0.95]), [0.02; 0.95], eps) ## corner case of zero tolerance %!assert (stretchlim (0.01:.01:1, 0), [0.01; 1]) %!test %! im = rand (5); %! assert (stretchlim (im, 0), [min(im(:)); max(im(:))]) %!test %! im = rand (5, 5, 3); %! assert (stretchlim (im, 0), %! [min(im(:,:,1)(:)) min(im(:,:,2)(:)) min(im(:,:,3)(:)); %! max(im(:,:,1)(:)) max(im(:,:,2)(:)) max(im(:,:,3)(:))]) ## corner case where tol is not zero but the image is so small that ## it might as well be. %!test %! im = rand (5); %! assert (stretchlim (im, 0.03), [min(im(:)); max(im(:))]) %! assert (stretchlim (im, 0.0399), [min(im(:)); max(im(:))]) ## Test with non double data-types %!assert (stretchlim (uint8 (1:100)), im2double (uint8 ([2; 99]))) %!assert (stretchlim (uint8 (1:100), .25), im2double (uint8 ([26; 75]))) %!assert (stretchlim (uint16 (1:1000)), im2double (uint16 ([11; 990]))) %!assert (stretchlim (int16 (-100:100)), im2double (int16 ([-98; 98]))) %!assert (stretchlim (single (0.01:.01:1)), %! double (single (0.01:.01:1)([2; 99])).') ## non uniform histogram tests %!assert (stretchlim (uint8 ([1 repmat(2, [1, 90]) 92:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 4]) 6:100]), 0.05), %! im2double (uint8 ([6; 95]))) ## test limit rounding (actually, lack of rounding, we always round down) ## Note that this tests were different in the image package before v2.6. ## Back then we performed rounding of the fraction that was saturated. %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) 7:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 6]) 8:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 7]) 9:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 8]) 10:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) repmat(3, [1 5]) 9:100]), 0.04), %! im2double (uint8 ([2; 96]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) repmat(3, [1 5]) 9:100]), 0.05), %! im2double (uint8 ([2; 95]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) repmat(3, [1 5]) 9:100]), 0.06), %! im2double (uint8 ([3; 94]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) repmat(3, [1 5]) 9:100]), 0.07), %! im2double (uint8 ([3; 93]))) %!assert (stretchlim (uint8 ([1 repmat(2, [1 5]) repmat(3, [1 5]) 9:100]), 0.08), %! im2double (uint8 ([3; 92]))) ## test RGB %!test %! RGB = zeros (100, 1, 3, "uint16"); %! RGB(:,:,1) = [1:1:100]; %! RGB(:,:,2) = [2:2:200]; %! RGB(:,:,3) = [4:4:400]; %! assert (stretchlim (RGB) , im2double (uint16 ([2 4 8; 99 198 396]))) ## test other 3D lengths %!test %! im6c = zeros (100, 1, 6, "uint16"); %! im6c(:,:,1) = [1:1:100]; %! im6c(:,:,2) = [2:2:200]; %! im6c(:,:,3) = [4:4:400]; %! im6c(:,:,4) = [8:8:800]; %! im6c(:,:,5) = [16:16:1600]; %! im6c(:,:,6) = [32:32:3200]; %! assert (stretchlim (im6c) , %! im2double (uint16 ([2 4 8 16 32 64; 99 198 396 792 1584 3168]))) %!test %! im = [0 0 .1 .1 .1 .1 .2 .2 .2 .4 .4 .6 .6 .7 .7 .9 .9 .9 1 1]; %! %! assert (stretchlim (im), [0; 1]) %! %! ## Consider the returned lower limit in this test. A lower limit %! ## of 0.1 will saturate two elements (10%), while 0.2 will saturate %! ## 6 elements (30%). Both have the same distance to 20% but returning %! ## 0.1 is Matlab compatible. %! ## Now looking at the higher limit. A limit of .9 will saturate %! ## 2 elements (10%), while a limit of 0.7 will saturate 5 elements (25%). %! ## However, for Matlab compatibility we must return .9 even though %! ## 25% would be closer to 20%. %! ## Basically, it's not just rounded. %! assert (stretchlim (im, .2), [0.1; 0.9]) %! %! assert (stretchlim (im, .15), [0.1; 0.9]) %! assert (stretchlim (im, .1), [0.1; 0.9]) %! assert (stretchlim (im, .25), [0.1; 0.7]) %! %! ## Reorder the vector of values (real images don't have the values %! ## already sorted), just to be sure it all works. %! im([6 3 16 11 7 17 14 8 5 19 15 1 2 4 18 13 9 20 10 12]) = im; %! assert (stretchlim (im, .2), [0.1; 0.9]) %! assert (stretchlim (im, .15), [0.1; 0.9]) %! assert (stretchlim (im, .1), [0.1; 0.9]) %! assert (stretchlim (im, .25), [0.1; 0.7]) ## odd length images to test rounding of saturated fraction. With a 1% ## fraction to be saturated and 991 elements, that's 9.91 pixels. Since ## TOL is the limit, we must saturate the top and bottom 9 pixels (not 10). %!assert (stretchlim (0.01:.001:1), [0.019; 0.991], eps) %!assert (stretchlim (0.01:.001:1, [0.01,0.95]), [0.019; 0.951], eps) %!assert (stretchlim (0.01:.001:1, 0), [0.01; 1]) %!assert (stretchlim (single (0.01:.001:1)), %! double (single (0.01:.001:1)([10; 982])).') ## Test ignoring floating point values outside [0 1] and how they do ## count for the fraction of saturated values, but are simply clipped ## to the [0 1] range %!test %! assert (stretchlim ([(.05:.05:1) (2:4)], 0.2), [0.25; 0.95], eps) %! assert (stretchlim ([(.05:.05:1) (2:5)], 0.2), [0.25; 1]) %! assert (stretchlim ([(.05:.05:1) (2:6)], 0.2), [0.3; 1]) %! assert (stretchlim ([(.05:.05:1) (2:7)], 0.2), [0.3; 1]) %!test %! assert (stretchlim ([(-6:0) (.05:.05:1)], 0.2), [0; 0.75], eps) %! assert (stretchlim ([(-5:0) (.05:.05:1)], 0.2), [0; 0.75], eps) ## Test N dimensions %!test %! im = rand (4, 4, 2, 3, 2); %! rv = zeros (2, 2, 3, 2); %! for p = 1:2 %! for q = 1:3 %! for r = 1:2 %! rv(:,p,q,r) = stretchlim (im(:,:,p,q,r), 0.25); %! endfor %! endfor %! endfor %! assert (stretchlim (im, 0.25), rv) ## The same but important because of our special code path for tol == 0 %!test %! im = rand (4, 4, 2, 3, 2); %! rv = zeros (2, 2, 3, 2); %! for p = 1:2 %! for q = 1:3 %! for r = 1:2 %! rv(:,p,q,r) = stretchlim (im(:,:,p,q,r), 0); %! endfor %! endfor %! endfor %! assert (stretchlim (im, 0), rv) ## Corner case there's a single value in the whole image %!assert (stretchlim (zeros (5)), [0; 1]) %!assert (stretchlim (ones (5)), [0; 1]) %!assert (stretchlim (.6 * ones (5)), [0; 1]) %!assert (stretchlim (zeros (3, 3, 3, 3)), repmat ([0; 1], [1 3 3])) %!assert (stretchlim ([0 .5 .5 .5 .5 1], .2), [0; 1]) ## Cornier case when some of the planes have a single unique value %!test %! im = repmat ((magic (5) -1) / 24, [1 1 3 3]); %! im(:,:,1,1) = 0; %! im(:,:,2,2) = .5; %! im(:,:,3,3) = 1; %! lims = stretchlim (im, 0.2); %! assert (size (lims), [2 3 3]) %! assert (lims(:, [2 3 4 6 7 8]), %! repmat ([(1/24)*round(24*.2); 1-((1/24)*round(24*.2))], [1 6]), eps) %! assert (lims(:, [1 5 9]), repmat ([0; 1], [1 3])) image-2.6.2/inst/PaxHeaders.16724/regionprops.m0000644000000000000000000000013213201323063016036 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/regionprops.m0000644000175000017500000014764413201323063020616 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2010 Søren Hauberg ## Copyright (C) 2012 Jordi Gutiérrez Hermoso ## Copyright (C) 2015 Hartmut Gimpel ## 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} {} regionprops (@var{BW}) ## @deftypefnx {Function File} {} regionprops (@var{L}) ## @deftypefnx {Function File} {} regionprops (@var{CC}) ## @deftypefnx {Function File} {} regionprops (@dots{}, @var{properties}) ## @deftypefnx {Function File} {} regionprops (@dots{}, @var{I}, @var{properties}) ## Compute properties of image regions. ## ## Measures several properties for each region within an image. Returns ## a struct array, one element per region, whose field names are the ## measured properties. ## ## Individual regions can be defined in three different ways, a binary ## image, a labelled image, or a bwconncomp struct, each providing ## different advantages. ## ## @table @asis ## @item @var{BW} ## A binary image. Must be of class logical. Individual regions will be ## the connected component as computed by @code{bwconnmp} using the ## maximal connectivity for the number of dimensions of @var{bw} (see ## @code{conndef} for details). For alternative connectivities, call ## @code{bwconncomp} directly and use its output instead. ## ## @var{bw} must really be of class logical. If not, even if it is a ## numeric array of 0's and 1's, it will be treated as a labelled image ## with a single discontinuous region. For example: ## ## @example ## ## Handled as binary image with 3 regions ## bw = logical ([ ## 1 0 1 0 1 ## 1 0 1 0 1 ## ]); ## ## ## Handled as labelled image with 1 region ## bw = [ ## 1 0 1 0 1 ## 1 0 1 0 1 ## ]; ## @end example ## ## @item @var{L} ## A labelled image. Each region is the collection of all positive ## elements with the same value. This allows computing properties of ## regions that would otherwise be considered separate or connected. ## For example: ## ## @example ## ## Recognizes 4 regions ## l = [ ## 1 2 3 4 ## 1 2 3 4 ## ]; ## ## ## Recognizes 2 (discontinuous) regions ## l = [ ## 1 2 1 2 ## 1 2 1 2 ## ]; ## @end example ## ## @item @var{CC} ## A @code{bwconnmp()} structure. This is a struct with the following ## 4 fields: Connectivity, ImageSize, NumObjects, and PixelIdxList. See ## @code{bwconncomp} for details. ## ## @end table ## ## The properties to be measured can be defined via a cell array or a ## comma separated list or strings. Some of the properties are only ## supported if the matching grayscale image @var{I} is also supplied. ## Others are only supported for 2 dimensional images. See the list ## below for details on each property limitation. If none is specified, ## it defaults to the @qcode{"basic"} set of properties. ## ## @table @asis ## @item @qcode{"Area"} ## The number of pixels in the region. Note that this differs from ## @code{bwarea} where each pixel has different weights. ## ## @item @qcode{"BoundingBox"} ## The smalles rectangle that encloses the region. This is represented ## as a row vector such as ## @code{[x y z @dots{} x_length y_length z_length @dots{}]}. ## ## The first half corresponds to the lower coordinates of each dimension ## while the second half, to the length in that dimension. For the two ## dimensional case, the first 2 elements correspond to the coordinates ## of the upper left corner of the bounding box, while the two last entries ## are the width and the height of the box. ## ## @item @qcode{"Centroid"} ## The coordinates for the region centre of mass. This is a row vector ## with one element per dimension, such as @code{[x y z @dots{}]}. ## ## @item @qcode{"Eccentricity"} ## The eccentricity of the ellipse that has the same normalized ## second central moments as the region (value between 0 and 1). ## ## @item @qcode{"EquivDiameter"} ## The diameter of a circle with the same area as the object. ## ## @item @qcode{"EulerNumber"} ## The Euler number of the region using connectivity 8. Only supported ## for 2D images. See @code{bweuler} for details. ## ## @item @qcode{"Extent"} ## The area of the object divided by the area of the bounding box. ## ## @item @qcode{"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 @qcode{"FilledArea"} ## The area of the object including possible holes. ## ## @item @qcode{"FilledImage"} ## A binary image with the same size as the object's bounding box that contains ## the object with all holes removed. ## ## @item @qcode{"Image"} ## An image with the same size as the bounding box that contains the original ## pixels. ## ## @item @qcode{"MajorAxisLength"} ## The length of the major axis of the ellipse that has the same ## normalized second central moments as the object. ## ## @item @qcode{"MaxIntensity"} ## The maximum intensity value inside each region. ## Requires a grayscale image @var{I}. ## ## @item @qcode{"MeanIntensity"} ## The mean intensity value inside each region. ## Requires a grayscale image @var{I}. ## ## @item @qcode{"MinIntensity"} ## The minimum intensity value inside each region. ## Requires a grayscale image @var{I}. ## ## @item @qcode{"MinorAxisLength"} ## The length of the minor axis of the ellipse that has the same ## normalized second central moments as the object. ## ## @item @qcode{"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 @qcode{"Perimeter"} ## The length of the boundary of the object. ## ## @item @qcode{"PixelIdxList"} ## The linear indices for the elements of each region in a column vector. ## ## @item @qcode{"PixelList"} ## The subscript indices for the elements of each region. This is a p-by-Q ## matrix where p is the number of elements and Q is the number of ## dimensions. Each row is of the form @code{[x y z @dots{}]}. ## ## @item @qcode{"PixelValues"} ## The actual pixel values inside each region in a column vector. ## Requires a grayscale image @var{I}. ## ## @item @qcode{"SubarrayIdx"} ## A cell array with subscript indices for the bounding box. This can ## be used as @code{@var{I}(@var{props}(@var{p}).SubarrayIdx@{:@})}, where ## @var{p} is one of the regions, to extract the image in its bounding box. ## ## @item @qcode{"WeightedCentroid"} ## The coordinates for the region centre of mass when using the intensity ## of each element as weight. This is a row vector with one element per ## dimension, such as @code{[x y z @dots{}]}. ## Requires a grayscale image @var{I}. ## ## @end table ## ## In addition, the strings @qcode{"basic"} and @qcode{"all"} can be ## used to select a subset of the properties: ## ## @table @asis ## @item @qcode{"basic"} (default) ## Compute @qcode{"Area"}, @qcode{"Centroid"}, and @qcode{"BoundingBox"}. ## ## @item @qcode{"all"} ## Computes all possible properties for the image, i.e., it will not ## compute properties that require grayscale unless the grayscale image ## is available, and it will not compute properties that are limited to ## 2 dimensions, unless the image is 2 dimensions. ## ## @end table ## ## @seealso{bwlabel, bwperim, bweuler} ## @end deftypefn function props = regionprops (bw, varargin) if (nargin < 1) print_usage (); endif if (isstruct (bw)) if (! isempty (setxor (fieldnames (bw), {"Connectivity", "ImageSize", ... "NumObjects", "PixelIdxList"}))) error ("regionprops: CC is an invalid bwconnmp() struct"); endif cc = bw; elseif (islogical (bw)) cc = bwconncomp (bw); elseif (isnumeric (bw)) if (isinteger (bw)) if (intmin (class (bw)) < 0 && any (bw(:) < 0)) error ("regionprops: L must be non-negative integers only"); endif else if (any (bw(:) < 0) || any (fix (bw(:)) != bw(:))) error ("regionprops: L must be non-negative integers only"); endif endif n_obj = max (bw(:)); if (! n_obj) ## workaround for https://savannah.gnu.org/bugs/index.php?47287 cc = struct ("ImageSize", size (bw), "NumObjects", n_obj, "PixelIdxList", {cell(1, 0)}); else l_idx = find (bw); cc = struct ("ImageSize", size (bw), "NumObjects", n_obj, "PixelIdxList", {accumarray(bw(l_idx)(:), l_idx, [1 n_obj], @(x) {x})}); endif else error ("regionprops: no valid BW, CC, or L input"); endif is_2d = numel (cc.ImageSize) == 2; next_idx = 1; has_gray = false; if (numel (varargin) && isnumeric (varargin{1})) next_idx++; has_gray = true; img = varargin{1}; sz = size (img); if (! size_equal (sz, cc.ImageSize) || any (sz != cc.ImageSize)) error ("regionprops: BW and I sizes must be equal"); endif endif if (numel (varargin) >= next_idx) if (iscell (varargin{next_idx})) properties = varargin{next_idx++}; if (numel (varargin) >= next_idx) print_usage (); endif else properties = varargin(next_idx++:end); endif if (! iscellstr (properties)) error ("regionprops: PROPERTIES must be a string or a cell array of strings"); endif properties = tolower (strrep (properties, "_", "")); else properties = {"basic"}; endif properties = select_properties (properties, is_2d, has_gray); ## Some properties require the value of others. In addition, most ## properties have common code. Ideally, to avoid repeating ## computations, we would make use not only of the already measured ## properties. but also of their intermediary steps. We handle this ## with a stack of properties that need to be measured and we push ## dependencies into it as we find them. A scalar struct keeps all ## values whose fields are the properties and intermediary steps names. ## ## Note that we do not want to fill the return value just yet. The ## reason is that props is a struct array. Since the computation of ## the properties is vectorized, it would require a constant back and ## forth conversion between cell arrays and numeric arrays. So we ## keep everything in a numeric array and everything is much faster. ## At the end, we put everything in place in a struct array. dependencies = struct ( "area", {{}}, "accum_subs", {{"area"}}, # private "accum_subs_nd", {{"accum_subs"}}, # private "boundingbox", {{"pixellist", "accum_subs_nd"}}, "centroid", {{"accum_subs_nd", "pixellist", "area"}}, "filledarea", {{"filledimage"}}, "filledimage", {{"image"}}, "image", {{"subarrayidx", "accum_subs", "pixelidxlist"}}, "pixelidxlist", {{}}, "pixellist", {{"pixelidxlist"}}, "subarrayidx", {{"boundingbox"}}, "convexarea", {{}}, "convexhull", {{}}, "conveximage", {{}}, "eccentricity", {{"minoraxislength", "majoraxislength"}}, "equivdiameter", {{"area"}}, "eulernumber", {{"image"}}, "extent", {{"area", "boundingbox"}}, "extrema", {{"area", "accum_subs_nd", "pixellist"}}, "local_ellipse", {{"area", "pixellist"}}, # private "majoraxislength", {{"local_ellipse"}}, "minoraxislength", {{"local_ellipse"}}, "orientation", {{"local_ellipse"}}, "perimeter", {{}}, "solidity", {{}}, "maxintensity", {{"accum_subs", "pixelidxlist"}}, "meanintensity", {{"total_intensity", "area"}}, "minintensity", {{"accum_subs", "pixelidxlist"}}, "pixelvalues", {{"pixelidxlist"}}, "total_intensity", {{"accum_subs", "pixelidxlist"}}, "weightedcentroid", {{"accum_subs_nd", "total_intensity", "pixellist", "pixelidxlist", "area"}} ); to_measure = properties; values = struct (); ## There's too many indirectly dependent on "area", and even if not ## required, it will be required later to create the struct array. values.area = rp_area (cc); while (! isempty (to_measure)) pname = to_measure{end}; ## Already computed. Pop it and move on. if (isfield (values, pname)) to_measure(end) = []; continue endif ## There's missing dependencies. Push them and start again. deps = dependencies.(pname); missing = deps(! isfield (values, deps)); if (! isempty (missing)) to_measure(end+1:end+numel(missing)) = missing; continue endif to_measure(end) = []; switch (pname) case "area" values.area = rp_area (cc); case "accum_subs" values.accum_subs = rp_accum_subs (cc, values.area); case "accum_subs_nd" values.accum_subs_nd = rp_accum_subs_nd (cc, values.accum_subs); case "boundingbox" values.boundingbox = rp_bounding_box (cc, values.pixellist, values.accum_subs_nd); case "centroid" values.centroid = rp_centroid (cc, values.pixellist, values.area, values.accum_subs_nd); case "filledarea" values.filledarea = rp_filled_area (values.filledimage); case "filledimage" values.filledimage = rp_filled_image (values.image); case "image" values.image = rp_image (cc, bw, values.pixelidxlist, values.accum_subs, values.subarrayidx); case "pixelidxlist" values.pixelidxlist = rp_pixel_idx_list (cc); case "pixellist" values.pixellist = rp_pixel_list (cc, values.pixelidxlist); case "subarrayidx" values.subarrayidx = rp_subarray_idx (cc, values.boundingbox); case "convexarea" error ("regionprops: property \"ConvexArea\" not yet implemented"); case "convexhull" error ("regionprops: property \"ConvexHull\" not yet implemented"); case "conveximage" error ("regionprops: property \"ConvexImage\" not yet implemented"); case "eccentricity" values.eccentricity = rep_eccentricity (values.minoraxislength, values.majoraxislength); case "equivdiameter" values.equivdiameter = rp_equivdiameter (values.area); case "eulernumber" values.eulernumber = rp_euler_number (values.image); case "extent" values.extent = rp_extent (values.area, values.boundingbox); case "extrema" values.extrema = rp_extrema (cc, values.pixellist, values.area, values.accum_subs_nd); case "local_ellipse" values.local_ellipse = true; [values.minoraxislength, values.majoraxislength, ... values.orientation] = rp_local_ellipse (values.area, values.pixellist); case {"majoraxislength", "minoraxislength", "orientation"} ## Do nothing. These are "virtual" targets which are computed ## in local_ellipse. case "perimeter" values.perimeter = rp_perimeter (cc, bw); case "solidity" error ("regionprops: property \"Solidity\" not yet implemented"); case "maxintensity" values.maxintensity = rp_max_intensity (cc, img, values.pixelidxlist, values.accum_subs); case "meanintensity" values.meanintensity = rp_mean_intensity (cc, values.total_intensity, values.area); case "minintensity" values.minintensity = rp_min_intensity (cc, img, values.pixelidxlist, values.accum_subs); case "pixelvalues" values.pixelvalues = rp_pixel_values (cc, img, values.pixelidxlist); case "total_intensity" values.total_intensity = rp_total_intensity (cc, img, values.pixelidxlist, values.accum_subs); case "weightedcentroid" values.weightedcentroid = rp_weighted_centroid (cc, img, values.pixellist, values.pixelidxlist, values.total_intensity, values.accum_subs_nd, values.area); otherwise error ("regionprops: unknown property `%s'", pname); endswitch endwhile ## After we have made all the measurements, we need to pack everything ## into struct arrays. Area = values.area; props = repmat (struct (), cc.NumObjects, 1); for ip = 1:numel (properties) switch (properties{ip}) case "area" [props.Area] = num2cell (Area){:}; case "boundingbox" [props.BoundingBox] = mat2cell (values.boundingbox, ones (cc.NumObjects, 1)){:}; case "centroid" [props.Centroid] = mat2cell (values.centroid, ones (cc.NumObjects, 1)){:}; case "filledarea" [props.FilledArea] = num2cell (values.filledarea){:}; case "filledimage" [props.FilledImage] = values.filledimage{:}; case "image" [props.Image] = values.image{:}; case "pixelidxlist" [props.PixelIdxList] = mat2cell (values.pixelidxlist, Area){:}; case "pixellist" [props.PixelList] = mat2cell (values.pixellist, Area){:}; case "subarrayidx" [props.SubarrayIdx] = values.subarrayidx{:}; # case "convexarea" # case "convexhull" # case "conveximage" case "eccentricity" [props.Eccentricity] = num2cell (values.eccentricity){:}; case "equivdiameter" [props.EquivDiameter] = num2cell (values.equivdiameter){:}; case "eulernumber" [props.EulerNumber] = num2cell (values.eulernumber){:}; case "extent" [props.Extent] = num2cell (values.extent){:}; case "extrema" [props.Extrema] = mat2cell (values.extrema, repmat (8, 1, cc.NumObjects)){:}; case "majoraxislength" [props.MajorAxisLength] = num2cell (values.majoraxislength){:}; case "minoraxislength" [props.MinorAxisLength] = num2cell (values.minoraxislength){:}; case "orientation" [props.Orientation] = num2cell (values.orientation){:}; case "perimeter" [props.Perimeter] = num2cell (values.perimeter){:}; # case "solidity" case "maxintensity" [props.MaxIntensity] = num2cell (values.maxintensity){:}; case "meanintensity" [props.MeanIntensity] = num2cell (values.meanintensity){:}; case "minintensity" [props.MinIntensity] = num2cell (values.minintensity){:}; case "pixelvalues" [props.PixelValues] = mat2cell (values.pixelvalues, Area){:}; case "weightedcentroid" [props.WeightedCentroid] = mat2cell (values.weightedcentroid, ones (cc.NumObjects, 1)){:}; otherwise error ("regionprops: unknown property `%s'", pname); endswitch endfor endfunction function props = select_properties (props, is_2d, has_gray) persistent props_basic = { "area", "boundingbox", "centroid", }; persistent props_2d = { # "convexarea", # "convexhull", # "conveximage", "eccentricity", "equivdiameter", "extrema", "majoraxislength", "minoraxislength", "orientation", "perimeter", # "solidity", }; persistent props_gray = { "maxintensity", "meanintensity", "minintensity", "pixelvalues", "weightedcentroid", }; persistent props_others = { "eulernumber", "extent", # Matlab limits Extent to 2D. Octave does not. "filledarea", "filledimage", "image", "pixelidxlist", "pixellist", "subarrayidx", }; props = props(:); p_basic = strcmp ("basic", props); p_all = strcmp ("all", props); props(p_basic | p_all) = []; if (any (p_all)) props = vertcat (props, props_basic, props_others); if (is_2d) props = vertcat (props, props_2d); endif if (has_gray) props = vertcat (props, props_gray); endif elseif (any (p_basic)) props = vertcat (props, props_basic); endif if (! is_2d) non_2d = ismember (props, props_2d); if (any (non_2d)) warning ("regionprops: ignoring %s properties for non 2 dimensional image", strjoin (props(non_2d), ", ")); props(non_2d) = []; endif endif if (! has_gray) non_val = ismember (props, props_gray); if (any (non_val)) warning ("regionprops: ignoring %s properties due to missing grayscale image", strjoin (props(non_val), ", ")); props(non_val) = []; endif endif endfunction function area = rp_area (cc) area = cellfun (@numel, cc.PixelIdxList(:)); endfunction function centroid = rp_centroid (cc, pixel_list, area, subs_nd) nd = numel (cc.ImageSize); no = cc.NumObjects; weighted_sub = pixel_list ./ vec (repelems (area, [1:no; vec(area, 2)])); centroid = accumarray (subs_nd, weighted_sub(:), [no nd]); endfunction function bounding_box = rp_bounding_box (cc, pixel_list, subs_nd) nd = numel (cc.ImageSize); no = cc.NumObjects; init_corner = accumarray (subs_nd, pixel_list(:), [no nd], @min) - 0.5; end_corner = accumarray (subs_nd, pixel_list(:), [no nd], @max) + 0.5; bounding_box = [(init_corner) (end_corner - init_corner)]; endfunction function eccentricity = rep_eccentricity (minoraxislength, majoraxislength) eccentricity = sqrt (1 - (minoraxislength ./ majoraxislength).^2); endfunction function equivdiameter = rp_equivdiameter (area) equivdiameter = sqrt (4 * area / pi); endfunction function euler = rp_euler_number (bb_images) ## TODO there should be a way to vectorize this, right? euler = cellfun (@bweuler, bb_images); endfunction function extent = rp_extent (area, bounding_box) bb_area = prod (bounding_box(:,(end/2)+1:end), 2); extent = area ./ bb_area; endfunction function extrema = rp_extrema (cc, pixel_list, area, subs_nd) ## Note that this property is limited to 2d regions no = cc.NumObjects; ## Algorithm: ## 1. Find the max and min values for row and column values on ## each object. That is, max and min of each column in ## pixel_list, for each object. ## ## 2. Get a mask for pixel_list, for those rows and columns indices. ## ## 3. Use that mask on the other dimension to find the max and min ## values for each object. ## ## 4. Assign those values to a (8*no)x2 array. ## ## This gets a bit convoluted because we do the two dimensions and ## all objects at the same time. ## In the following, "head" and "base" are the top and bottom index for ## each dimension. We use the words "head" and "base" to avoid confusion ## with the rest where top and bottom only refer to the row dimension. ## So "head" has the lowest index values (rows for top left/right, and ## columns for left top/bottom), while "base" has the highest index ## values (rows for bottom left/right, and columns for right top/bottom). ## 1. Find the max and min values for row and column values on ## each object. That is, max and min of each column in ## pixel_list, for each object. head = accumarray (subs_nd, pixel_list(:), [no 2], @min); base = accumarray (subs_nd, pixel_list(:), [no 2], @max); ## 2. Get a mask for pixel_list, for those rows and columns indices. ## ## 3. Use that mask on the other dimension to find the max and min ## values for each object. ## ## head_head and head_base, have the lowest index (head) and the ## highest index (base) values, for the "head" indices. ## Same logic for base_head and base_base. px_l_sz = size (pixel_list); rep_extrema = @(x) reshape (repelems (x, [1:(no*2); area(:)' area(:)']), px_l_sz); head_mask = (pixel_list == rep_extrema (head))(:, [2 1]); head_head = accumarray (subs_nd(head_mask), pixel_list(head_mask), [no 2], @min); head_base = accumarray (subs_nd(head_mask), pixel_list(head_mask), [no 2], @max); base_mask = (pixel_list == rep_extrema (base))(:, [2 1]); base_head = accumarray (subs_nd(base_mask), pixel_list(base_mask), [no 2], @min); base_base = accumarray (subs_nd(base_mask), pixel_list(base_mask), [no 2], @max); ## Adjust from idx integer to pixel border coordinates head -= 0.5; head_head -= 0.5; head_base += 0.5; base += 0.5; base_head -= 0.5; base_base += 0.5; ## 4. Assign those values to a (8*no)x2 array. nr = 8 * no; extrema = zeros (nr, 2); extrema(1:8:nr, 2) = head(:,2); # y values for top left extrema(2:8:nr, 2) = head(:,2); # y values for top right extrema(7:8:nr, 1) = head(:,1); # x values for left bottom extrema(8:8:nr, 1) = head(:,1); # x values for left top extrema(5:8:nr, 2) = base(:,2); # y values for bottom right extrema(6:8:nr, 2) = base(:,2); # y values for bottom left extrema(3:8:nr, 1) = base(:,1); # x values for right top extrema(4:8:nr, 1) = base(:,1); # x values for right bottom extrema(1:8:nr, 1) = head_head(:,1); # x value for top left extrema(8:8:nr, 2) = head_head(:,2); # y value for left top extrema(2:8:nr, 1) = head_base(:,1); # x value for top right extrema(7:8:nr, 2) = head_base(:,2); # y value for left bottom extrema(6:8:nr, 1) = base_head(:,1); # x value for bottom left extrema(3:8:nr, 2) = base_head(:,2); # y value for right top extrema(5:8:nr, 1) = base_base(:,1); # x value for bottom right extrema(4:8:nr, 2) = base_base(:,2); # y value for right bottom endfunction function filled_area = rp_filled_area (bb_filled_images) filled_area = cellfun ('nnz', bb_filled_images); endfunction function bb_filled_images = rp_filled_image (bb_images) ## Beware if attempting to vectorize this. The bounding boxes of ## different regions may overlap, and a "hole" may be a hole for ## several regions (e.g., concentric circles). There should be tests ## this weird cases. bb_filled_images = cellfun (@(x) imfill (x, "holes"), bb_images, "UniformOutput", false); endfunction function bb_images = rp_image (cc, bw, idx, subs, subarray_idx) ## For this property, we must remember to remove elements from other ## regions (remember that bounding boxes may overlap). We do that by ## creating a labelled image, extracting the bounding boxes, and then ## comparing elements. no = cc.NumObjects; ## If BW is numeric then it already is a labeled image. if (isnumeric (bw)) L = bw; else if (no < 255) cls = "uint8"; elseif (no < 65535) cls = "uint16" elseif (no < 4294967295) cls = "uint32"; else cls = "double"; endif L = zeros (cc.ImageSize, cls); L(idx) = subs; endif sub_structs = num2cell (struct ("type", "()", "subs", subarray_idx)); bb_images = cellfun (@subsref, {L}, sub_structs, "UniformOutput", false); bb_images = cellfun (@eq, bb_images, num2cell (1:no)(:), "UniformOutput", false); endfunction function perim = rp_perimeter (cc, bw) if (! islogical (bw)) # Then input was not really a bw. Create it. bw = false (cc.ImageSize); bw(cell2mat (cc.PixelIdxList(:))) = true; endif no = cc.NumObjects; boundaries = bwboundaries (bw, 8, "noholes"); npx = cellfun ("size", boundaries, 1); dists = diff (cell2mat (boundaries)); dists(cumsum (npx)(1:end-1),:) = []; dists = sqrt (sumsq (dists, 2)); subs = repelems (1:no, [1:no; (npx-1)(:)']); perim = accumarray (subs(:), dists(:), [no 1]); endfunction function idx = rp_pixel_idx_list (cc) idx = cell2mat (cc.PixelIdxList(:)); endfunction function pixel_list = rp_pixel_list (cc, idx) nd = numel (cc.ImageSize); pixel_list = cell2mat (nthargout (1:nd, @ind2sub, cc.ImageSize, idx)); ## If idx is empty, pixel_list will have size (0x0) so we need to expand ## it to (0xnd). Unfortunately, in2sub() returns (0x0) and not (0x1) pixel_list = postpad (pixel_list, nd, 0, 2); pixel_list(:,[1 2]) = pixel_list(:,[2 1]); endfunction function pixel_values = rp_pixel_values (cc, img, idx) pixel_values = img(idx); endfunction function max_intensity = rp_max_intensity (cc, img, idx, subs) max_intensity = accumarray (subs, img(idx), [cc.NumObjects 1], @max); endfunction function mean_intensity = rp_mean_intensity (cc, totals, area) mean_intensity = totals ./ area; endfunction function min_intensity = rp_min_intensity (cc, img, idx, subs) min_intensity = accumarray (subs, img(idx), [cc.NumObjects 1], @min); endfunction function subarray_idx = rp_subarray_idx (cc, bounding_box) nd = columns (bounding_box) / 2; bb_limits = bounding_box; ## Swap x y coordinates back to row and column bb_limits(:,[1 2 [1 2]+nd]) = bounding_box(:,[2 1 [2 1]+nd]); ## Set initial coordinates (it is faster to add 0.5 than to call ceil()) bb_limits(:,1:nd) += 0.5; ## Set the end coordinates bb_limits(:,(nd+1):end) += bb_limits(:,1:nd); bb_limits(:,(nd+1):end) -= 1; subarray_idx = arrayfun (@colon, bb_limits(:,1:nd), bb_limits(:,(nd+1):end), "UniformOutput", false); subarray_idx = mat2cell (subarray_idx, ones (cc.NumObjects, 1)); endfunction function weighted_centroid = rp_weighted_centroid (cc, img, pixel_list, pixel_idx_list, totals, subs_nd, area) no = cc.NumObjects; nd = numel (cc.ImageSize); rep_totals = vec (repelems (totals, [1:no; vec(area, 2)])); ## Note that we need 1 column, even if pixel_idx_list is [], hence (:) ## so that we get (0x1) instead of (0x0) vals = img(pixel_idx_list)(:); weighted_pixel_list = pixel_list .* (double (vals) ./ rep_totals); weighted_centroid = accumarray (subs_nd, weighted_pixel_list(:), [no nd]); endfunction ## ## Intermediary steps -- no match to specific property ## ## Creates subscripts for use with accumarray, when computing a column vector. function subs = rp_accum_subs (cc, area) rn = 1:cc.NumObjects; R = [rn; vec(area, 2)]; subs = vec (repelems (rn, R)); endfunction ## Creates subscripts for use with accumarray, when computing something ## with a column per number of dimensions function subs_nd = rp_accum_subs_nd (cc, subs) nd = numel (cc.ImageSize); no = cc.NumObjects; ## FIXME workaround bug #47085 subs_nd = vec (bsxfun (@plus, subs, [0:no:(no*nd-1)])); endfunction ## Total/Integrated density of each region. function totals = rp_total_intensity (cc, img, idx, subs) totals = accumarray (subs, img(idx), [cc.NumObjects 1]); endfunction function [minor, major, orientation] = rp_local_ellipse (area, pixellist) ## FIXME: this should be vectorized. See R.M. Haralick and Linda G. ## Shapiro, "Computer and Robot Vision: Volume 1", Appendix A no = numel (area); minor = zeros (no, 1); major = minor; orientation = minor; c_idx = 1; for idx = 1:no sel = c_idx:(c_idx + area(idx) -1); c_idx += area(idx); X = pixellist(sel, 2); Y = pixellist(sel, 1); ## calculate (centralised) second moment of region with pixels [X, Y] ## This is equivalent to "cov ([X(:) Y(:)], 1)" but will work as ## expected even if X and Y have only one row each. C = center ([X(:) Y(:)], 1); C = C' * C / (rows (C)); 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)); minor(idx) = min (lambda_d); [major(idx), major_idx] = max (lambda_d); major_vec = V(:, major_idx); if (major(idx) == minor(idx)) orientation(idx) = 0; elseif (major_vec(2) == 0) orientation(idx) = 90; else orientation(idx) = -(180/pi) .* atan (major_vec(1) ./ major_vec(2)); endif endfor endfunction %!shared bw2d, gray2d, bw2d_over_bb, bw2d_insides %! bw2d = logical ([ %! 0 1 0 1 1 0 %! 0 1 1 0 1 1 %! 0 1 0 0 0 0 %! 0 0 0 1 1 1 %! 0 0 1 1 0 1]); %! %! gray2d = [ %! 2 4 0 7 5 2 %! 3 0 4 9 3 7 %! 0 5 3 4 8 1 %! 9 2 0 5 8 6 %! 8 9 7 2 2 5]; %! %! ## For testing overlapping bounding boxes %! bw2d_over_bb = logical ([ %! 0 1 1 1 0 1 1 %! 1 1 0 0 0 0 1 %! 1 0 0 1 1 0 1 %! 1 0 0 1 1 0 0 %! 0 0 0 1 1 1 1]); %! %! ## For testing when there's regions inside regions %! bw2d_insides = logical ([ %! 0 0 0 0 0 0 0 0 %! 0 1 1 1 1 1 1 0 %! 0 1 0 0 0 0 1 0 %! 0 1 0 1 1 0 1 0 %! 0 1 0 1 1 0 1 0 %! 0 1 0 0 0 0 1 0 %! 0 1 1 1 1 1 1 0 %! 0 0 0 0 0 0 0 0]); %!function c = get_2d_centroid_for (idx) %! subs = ind2sub ([5 6], idx); %! m = false ([5 6]); %! m(idx) = true; %! y = sum ((1:5)' .* sum (m, 2) /sum (m(:))); %! x = sum ((1:6) .* sum (m, 1) /sum (m(:))); %! c = [x y]; %!endfunction %!assert (regionprops (bw2d, "Area"), struct ("Area", {8; 6})) %!assert (regionprops (double (bw2d), "Area"), struct ("Area", {14})) %!assert (regionprops (bwlabel (bw2d, 4), "Area"), struct ("Area", {4; 6; 4})) ## These are different from Matlab because the indices in PixelIdxList ## do not appear sorted. This is because we get them from bwconncomp() ## which does not sort them (it seems bwconncomp in Matlab returns them ## sorted but that's undocumented, just like the order here is undocumented) %!assert (regionprops (bw2d, "PixelIdxList"), %! struct ("PixelIdxList", {[6; 7; 12; 8; 16; 21; 22; 27] %! [15; 19; 20; 24; 29; 30]})) %!assert (regionprops (bwlabel (bw2d, 4), "PixelIdxList"), %! struct ("PixelIdxList", {[6; 7; 8; 12] %! [15; 19; 20; 24; 29; 30] %! [16; 21; 22; 27]})) %!assert (regionprops (bw2d, "PixelList"), %! struct ("PixelList", {[2 1; 2 2; 3 2; 2 3; 4 1; 5 1; 5 2; 6 2] %! [3 5; 4 4; 4 5; 5 4; 6 4; 6 5]})) %!assert (regionprops (bwlabel (bw2d, 4), "PixelList"), %! struct ("PixelList", {[2 1; 2 2; 2 3; 3 2] %! [3 5; 4 4; 4 5; 5 4; 6 4; 6 5] %! [4 1; 5 1; 5 2; 6 2]})) ## Also different from Matlab because we do not sort the values by index %!assert (regionprops (bw2d, gray2d, "PixelValues"), %! struct ("PixelValues", {[4; 0; 4; 5; 7; 5; 3; 7] %! [7; 5; 2; 8; 6; 5]})) %!assert (regionprops (bw2d, gray2d, "MaxIntensity"), %! struct ("MaxIntensity", {7; 8})) %!assert (regionprops (bw2d, gray2d, "MinIntensity"), %! struct ("MinIntensity", {0; 2})) %!assert (regionprops (bw2d, "BoundingBox"), %! struct ("BoundingBox", {[1.5 0.5 5 3]; [2.5 3.5 4 2]})) %!assert (regionprops (bw2d, "Centroid"), %! struct ("Centroid", {get_2d_centroid_for([6 7 8 12 16 21 22 27]) %! get_2d_centroid_for([15 19 20 24 29 30])}), %! 5 * eps) %!test %! props = struct ("Area", {8; 6}, %! "Centroid", {get_2d_centroid_for([6 7 8 12 16 21 22 27]) %! get_2d_centroid_for([15 19 20 24 29 30])}, %! "BoundingBox", {[1.5 0.5 5 3]; [2.5 3.5 4 2]}); %! assert (regionprops (bw2d, "basic"), props, 5 * eps) %! assert (regionprops (bwconncomp (bw2d, 8), "basic"), props, 5 * eps) %! assert (regionprops (bwlabeln (bw2d, 8), "basic"), props, 5 * eps) %!test %! props = struct ("Area", {4; 6; 4}, %! "Centroid", {get_2d_centroid_for([6 7 8 12]) %! get_2d_centroid_for([15 19 20 24 29 30]) %! get_2d_centroid_for([16 21 22 27])}, %! "BoundingBox", {[1.5 0.5 2 3]; [2.5 3.5 4 2]; [3.5 0.5 3 2]}); %! assert (regionprops (bwconncomp (bw2d, 4), "basic"), props, 5 * eps) %! assert (regionprops (bwlabeln (bw2d, 4), "basic"), props, 5 * eps) ## This it is treated as labeled image with a single discontiguous region. %!assert (regionprops (double (bw2d), "basic"), %! struct ("Area", 14, %! "Centroid", get_2d_centroid_for (find (bw2d)), %! "BoundingBox", [1.5 0.5 5 5]), eps*1000) %!assert (regionprops ([0 0 1], "Centroid").Centroid, [3 1]) %!assert (regionprops ([0 0 1; 0 0 0], "Centroid").Centroid, [3 1]) ## bug #39701 %!assert (regionprops ([0 1 1], "Centroid").Centroid, [2.5 1]) %!assert (regionprops ([0 1 1; 0 0 0], "Centroid").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*1000) %!test %! a = [0 0 2 2; 3 3 0 0; 0 1 0 1]; %! c = regionprops (a, "centroid"); %! assert (c(1).Centroid, [3 3]) %! assert (c(2).Centroid, [3.5 1]) %! assert (c(3).Centroid, [1.5 2]) %!test %!assert (regionprops (bw2d, gray2d, "WeightedCentroid"), %! struct ("WeightedCentroid", %! {sum([2 1; 2 2; 3 2; 2 3; 4 1; 5 1; 5 2; 6 2] %! .* ([4; 0; 4; 5; 7; 5; 3; 7] / 35)) %! sum([3 5; 4 4; 4 5; 5 4; 6 4; 6 5] %! .* ([7; 5; 2; 8; 6; 5] / 33))}), 5 * 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 (regionprops (bw2d, gray2d, "MeanIntensity"), %! struct ("MeanIntensity", {mean([4 0 5 4 7 5 3 7]) %! mean([7 5 2 8 6 5])})) %!assert (regionprops (bwlabel (bw2d, 4), gray2d, "MeanIntensity"), %! struct ("MeanIntensity", {mean([4 0 5 4]) %! mean([7 5 2 8 6 5]) %! mean([7 5 3 7])})) %!assert (regionprops (bw2d, "SubarrayIdx"), %! struct ("SubarrayIdx", {{[1 2 3], [2 3 4 5 6]} %! {[4 5], [3 4 5 6]}})) %!assert (regionprops (bwlabel (bw2d, 4), "SubarrayIdx"), %! struct ("SubarrayIdx", {{[1 2 3], [2 3]} %! {[4 5], [3 4 5 6]} %! {[1 2], [4 5 6]}})) %!test %! out = struct ("Image", {logical([1 0 1 1 0; 1 1 0 1 1; 1 0 0 0 0]) %! logical([0 1 1 1; 1 1 0 1])}); %! assert (regionprops (bw2d, "Image"), out) %! assert (regionprops (bw2d, gray2d, "Image"), out) %! assert (regionprops (bwlabel (bw2d), "Image"), out) %!assert (regionprops (bwlabel (bw2d, 4), "Image"), %! struct ("Image", {logical([1 0; 1 1; 1 0]) %! logical([0 1 1 1; 1 1 0 1]) %! logical([1 1 0; 0 1 1])})) ## Test overlapping bounding boxes %!test %! out = struct ("Image", {logical([0 1 1 1; 1 1 0 0; 1 0 0 0; 1 0 0 0]) %! logical([1 1 0 0; 1 1 0 0; 1 1 1 1]) %! logical([1 1; 0 1; 0 1])}); %! assert (regionprops (bw2d_over_bb, "Image"), out) %! assert (regionprops (bwlabel (bw2d_over_bb), "Image"), out) %!test %! out = struct ("Image", {logical([1 1 1 1 1 1 %! 1 0 0 0 0 1 %! 1 0 0 0 0 1 %! 1 0 0 0 0 1 %! 1 0 0 0 0 1 %! 1 1 1 1 1 1]) %! logical([1 1; 1 1])}); %! assert (regionprops (bw2d_insides, "Image"), out) %! assert (regionprops (bwlabel (bw2d_insides), "Image"), out) %!test %! l = uint8 ([ %! 0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 2 2 1 0 %! 0 1 2 2 1 0 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0 %! ]); %! assert (regionprops (l, "EulerNumber"), %! struct ("EulerNumber", {0; 1})) %! %! l = uint8 ([ %! 0 0 0 0 0 0 0 %! 0 1 1 1 1 1 0 %! 0 1 2 2 2 1 0 %! 0 1 2 3 2 1 0 %! 0 1 2 2 2 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 0 0 0 0 %! ]); %! assert (regionprops (l, "EulerNumber"), %! struct ("EulerNumber", {0; 0; 1})) %!test %! l = uint8 ([ %! 0 0 0 0 0 0 0 %! 0 1 1 1 1 1 0 %! 0 1 0 0 0 1 0 %! 0 1 0 1 0 1 0 %! 0 1 0 0 0 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 0 0 0 0 %! ]); %! assert (regionprops (l, "EulerNumber"), %! struct ("EulerNumber", 1)) %!test %! l = uint8 ([ %! 1 1 1 1 1 1 1 %! 1 1 2 1 2 2 1 %! 1 2 1 2 1 2 1 %! 1 1 2 1 2 1 1 %! 1 2 1 2 1 2 1 %! 1 2 2 1 2 1 1 %! 1 1 1 1 1 1 1 %! ]); %! assert (regionprops (l, "EulerNumber"), %! struct ("EulerNumber", {-9; -4})) %!test %! l = uint8 ([ %! 1 1 1 1 1 1 1 %! 1 1 4 1 5 5 1 %! 1 3 1 4 1 5 1 %! 1 1 3 1 4 1 1 %! 1 2 1 3 1 4 1 %! 1 2 2 1 3 1 1 %! 1 1 1 1 1 1 1 %! ]); %! assert (regionprops (l, "EulerNumber"), %! struct ("EulerNumber", {-9; 1; 1; 1; 1})) ## Test connectivity for hole filling. %!test %! l = uint8 ([ %! 1 1 1 1 1 1 1 %! 0 1 2 1 2 2 1 %! 1 2 1 2 1 2 1 %! 1 1 2 1 2 1 1 %! 1 2 1 2 1 2 1 %! 1 2 2 1 2 1 1 %! 1 1 1 1 1 1 1 %! ]); %! filled = { %! logical([ %! 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 %! ]); %! logical([ %! 0 1 0 1 1 %! 1 1 1 1 1 %! 0 1 1 1 0 %! 1 1 1 1 1 %! 1 1 0 1 0 %! ]); %! }; %! assert (regionprops (l, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", {48; 19})) ## Disconnected regions without holes. %!test %! l = uint8 ([ %! 0 0 0 0 0 0 0 %! 0 1 0 1 0 1 0 %! 0 1 0 1 0 1 0 %! 0 0 0 0 0 0 0 %! ]); %! filled = logical ([ %! 1 0 1 0 1 %! 1 0 1 0 1 %! ]); %! assert (regionprops (l, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", 6)) %! %! l = uint8 ([ %! 2 2 2 2 2 2 2 %! 2 1 2 1 2 1 2 %! 2 1 2 1 2 1 2 %! 2 2 2 2 2 2 2 %! ]); %! filled = { %! logical([ %! 1 0 1 0 1 %! 1 0 1 0 1 %! ]); %! true(4, 7) %! }; %! assert (regionprops (l, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", {6; 28})) ## Concentric regions to fill holes. %!test %! l = uint8 ([ %! 0 0 0 0 0 0 0 %! 0 1 1 1 1 1 0 %! 0 1 2 2 2 1 0 %! 0 1 2 3 2 1 0 %! 0 1 2 2 2 1 0 %! 0 1 1 1 1 1 0 %! 0 0 0 0 0 0 0 %! ]); %! filled = {true(5, 5); true(3, 3); true}; %! assert (regionprops (l, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", {25; 9; 1})) ## Regions with overlapping holes. %!test %! l = uint8 ([ %! 1 1 1 2 0 0 %! 1 0 2 1 2 0 %! 1 2 0 1 0 2 %! 1 2 1 1 0 2 %! 0 1 2 2 2 2 %! ]); %! filled = { %! logical([ %! 1 1 1 0 %! 1 1 1 1 %! 1 1 1 1 %! 1 1 1 1 %! 0 1 0 0 %! ]); %! logical([ %! 0 0 1 0 0 %! 0 1 1 1 0 %! 1 1 1 1 1 %! 1 1 1 1 1 %! 0 1 1 1 1 %! ]) %! }; %! assert (regionprops (l, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", {16; 18})) ## 3D region to fill which requires connectivity 6 (fails with 18 or 26). %!test %! bw = false (5, 5, 5); %! bw(2:4, 2:4, [1 5]) = true; %! bw(2:4, [1 5], 2:4) = true; %! bw([1 5], 2:4, 2:4) = true; %! filled = bw; %! filled(2:4, 2:4, 2:4) = true; %! assert (regionprops (bw, {"FilledImage", "FilledArea"}), %! struct ("FilledImage", filled, "FilledArea", 81)) %!test %! l = uint8 ([ %! 1 1 1 2 0 0 %! 1 0 2 1 2 0 %! 1 2 0 1 0 2 %! 1 2 1 1 0 2 %! 0 1 2 2 2 2 %! ]); %! assert (regionprops (l, {"Extent"}), struct ("Extent", {0.55; 0.44})) %!test %! bw = logical ([0 0 0; 0 1 0; 0 0 0]); %! assert (regionprops (bw, {"MinorAxisLength", "MajorAxisLength", ... %! "Eccentricity", "Orientation"}), %! struct ("MajorAxisLength", 4 .* sqrt (1/12), %! "MinorAxisLength", 4 .* sqrt (1/12), %! "Eccentricity", 0, %! "Orientation", 0)) %!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); ## Tests for multiple 'Orientation' thin cases (bug #49613) %!test %! bw = logical ([0 0 0 0; 0 1 1 0; 0 0 0 0]); %! props = regionprops (bw, "Orientation"); %! assert ([props.Orientation], 0, 0) %! %! props = regionprops (bw', "Orientation"); %! assert ([props.Orientation], 90, 0) %! %! bw = logical ([0 0 0 0; 0 1 1 0; 0 1 1 0; 0 0 0 0]); %! props = regionprops (bw, "Orientation"); %! assert ([props.Orientation], 0, 0) %! %! bw = logical ([1 1 0 0 0 ; 0 0 1 1 0 ; 0 0 0 0 0; 0 0 0 0 0]); %! props = regionprops (bw, "Orientation"); %! assert ([props.Orientation], -22.5, eps (22.5)) %! %! bw = logical ([ %! 1 1 0 0 1 %! 0 0 0 0 1 %! 0 0 0 0 0 %! 0 0 1 1 0 %! 1 0 1 1 0 %! 1 0 0 0 0 %! 0 1 0 0 0 %! 0 1 0 0 0]); %! props = regionprops (bw, "Orientation"); %! assert ([props.Orientation], [0 -67.5 0 90]) %!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); %!test %! bw = false (5); %! bw([8 12 13 14 18]) = true; %! extrema = [2 1; 3 1; 4 2; 4 3; 3 4; 2 4; 1 3; 1 2] + 0.5; %! assert (regionprops (bw, "extrema"), struct ("Extrema", extrema)) %!test %! ext1 = [1 0; 5 0; 6 1; 6 2; 2 3; 1 3; 1 3; 1 0] + 0.5; %! ext2 = [3 3; 6 3; 6 3; 6 5; 6 5; 2 5; 2 5; 2 4] + 0.5; %! assert (regionprops (bw2d, "extrema"), struct ("Extrema", {ext1; ext2})) %!assert (regionprops (bw2d, "equivDiameter"), %! struct ("EquivDiameter", {sqrt(4*8/pi); sqrt(4*6/pi)})) %!assert (regionprops (bw2d_over_bb, "equivDiameter"), %! struct ("EquivDiameter", {sqrt(4*7/pi); sqrt(4*8/pi); sqrt(4*4/pi)})) %!assert (regionprops (bw2d_insides, "equivDiameter"), %! struct ("EquivDiameter", {sqrt(4*20/pi); sqrt(4*4/pi)})) ## Test the diameter of a circle of diameter 21. %!test %! I = zeros (40); %! disk = fspecial ("disk",10); %! disk = disk ./ max (disk(:)); %! I(10:30, 10:30) = disk; %! bw = im2bw (I, 0.5); %! props = regionprops (bw, "Perimeter"); %! assert (props.Perimeter, 10*4 + (sqrt (2) * 4)*4, eps*100) %! %! props = regionprops (bwconncomp (bw), "Perimeter"); %! assert (props.Perimeter, 10*4 + (sqrt (2) * 4)*4, eps*100) %!assert (regionprops (bw2d, "Perimeter"), %! struct ("Perimeter", {(sqrt (2)*6 + 4); (sqrt (2)*3 + 4)}), eps*10) ## Test Perimeter with nested objects %!assert (regionprops (bw2d_insides, "Perimeter"), %! struct ("Perimeter", {20; 4})) %!assert (regionprops (bwconncomp (bw2d_insides), "Perimeter"), %! struct ("Perimeter", {20; 4})) ## Test guessing between labelled and binary image %!assert (regionprops ([1 0 1; 1 0 1], "Area"), struct ("Area", 4)) %!assert (regionprops ([1 0 2; 1 1 2], "Area"), struct ("Area", {3; 2})) ## Test missing labels %!assert (regionprops ([1 0 3; 1 1 3], "Area"), struct ("Area", {3; 0; 2})) ## Test dimensionality of struct array %!assert (size (regionprops ([1 0 0; 0 0 2], "Area")), [2, 1]) %!error regionprops ([1 -2 0 3]) %!error regionprops ([1 1.5 0 3]) ## Test for BW images with zero objects %!test %! im = rand (5); %! %! ## First do this so we get a list of all supported properties and don't %! ## have to update the list each time. %! bw = false (5); %! bw(13) = true; %! props = regionprops (bw, im, "all"); %! all_props = fieldnames (props); %! %! bw = false (5); %! props = regionprops (bw, im, "all"); %! assert (size (props), [0 1]) %! assert (sort (all_props), sort (fieldnames (props))) ## Test for labeled images with zeros objects %!test %! im = rand (5); %! %! ## First do this so we get a list of all supported properties and don't %! ## have to update the list each time. %! labeled = zeros (5); %! labeled(13) = 1; %! props = regionprops (labeled, im, "all"); %! all_props = fieldnames (props); %! %! labeled = zeros (5); %! props = regionprops (labeled, im, "all"); %! assert (size (props), [0 1]) %! assert (sort (all_props), sort (fieldnames (props))) ## Test for bwconncomp struct with zeros objects %!test %! im = rand (5); %! %! ## First do this so we get a list of all supported properties and don't %! ## have to update the list each time. %! bw = false (5); %! bw(13) = true; %! props = regionprops (bwconncomp (bw), im, "all"); %! all_props = fieldnames (props); %! %! bw = false (5); %! props = regionprops (bwconncomp (bw), im, "all"); %! assert (size (props), [0 1]) %! assert (sort (all_props), sort (fieldnames (props))) ## Test MajorAxisLength, MinorAxisLength, and Orientation with ## multiple regions (bug #49613) %!test %! bw = logical ([ %! 0 1 1 1 1 %! 0 1 1 0 0 %! 0 0 0 0 0 %! 0 0 0 1 0 %! 0 1 1 1 0]); %! props = regionprops (bw, "MajorAxisLength", "MinorAxisLength", %! "Orientation"); %! assert ([props.MajorAxisLength] ,[4.51354115 3.65148372], 1.e-8) %! assert ([props.MinorAxisLength], [2.01801654 1.82574186], 1.e-8) %! assert ([props.Orientation], [12.93317840 18.43494882], 1.e-8) ## Test warnings about invalid props for nd images and missing grayscale %!warning %! regionprops (rand (5, 5, 5) > 0.5, {"perimeter", "extrema"}); %!warning %! regionprops (rand (5, 5) > 0.5, {"minintensity", "weightedcentroid"}); ## Input check for labeled images %!error %! regionprops ([0 -1 3 4; 0 -1 3 4]) %!error %! regionprops ([0 1.5 3 4; 0 1.5 3 4]) %!error %! regionprops (int8 ([0 -1 3 4; 0 -1 3 4])) %!error regionprops (rand (5, 5) > 0.5, "ConvexArea") %!error regionprops (rand (5, 5) > 0.5, "ConvexHull") %!error regionprops (rand (5, 5) > 0.5, "ConvexImage") %!error regionprops (rand (5, 5) > 0.5, "Solidity") image-2.6.2/inst/PaxHeaders.16724/isind.m0000644000000000000000000000013213201323063014575 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/isind.m0000644000175000017500000000442613201323063017343 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011, 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} {} 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, ## real array of size @nospell{MxNx1xK}, and: ## ## @itemize @bullet ## @item of class double with all integers above zero; ## @item of class uint8 or uint16. ## @end itemize ## ## @emph{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; a grayscale image may have ## values outside the range [0 1]. 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) if (isfloat (img)) bool = isindex (img); elseif (any (isa (img, {"uint8", "uint16"}))) bool = true; endif 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.6.2/inst/PaxHeaders.16724/imopen.m0000644000000000000000000000013213201323063014756 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/imopen.m0000644000175000017500000001120113201323063017511 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.6.2/inst/PaxHeaders.16724/imdivide.m0000644000000000000000000000013213201323063015261 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imdivide.m0000644000175000017500000000535013201323063020024 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.6.2/inst/PaxHeaders.16724/imfill.m0000644000000000000000000000013213201323063014743 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imfill.m0000644000175000017500000003742213201323063017513 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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{bw2} =} imfill (@var{bw}, "holes") ## @deftypefnx {Function File} {@var{bw2} =} imfill (@var{bw}, @var{conn}, "holes") ## @deftypefnx {Function File} {@var{bw2} =} imfill (@var{bw}, @var{locations}) ## @deftypefnx {Function File} {@var{bw2} =} imfill (@var{bw}, @var{locations}, @var{conn}) ## @deftypefnx {Function File} {@var{I2} =} imfill (@var{I}) ## @deftypefnx {Function File} {@var{I2} =} imfill (@var{I}, "holes") ## @deftypefnx {Function File} {@var{I2} =} imfill (@var{I}, @var{conn}) ## @deftypefnx {Function File} {@var{I2} =} imfill (@var{I}, @var{conn}, "holes") ## Fill image holes or regions. ## ## The image to be filled can be binary @var{bw} or grayscale @var{I}. ## Regions are a series of connected elements whose values are lower than ## at least one of its neighbor elements. ## ## The option @qcode{"holes"}, default for grayscale images, can be used ## to fill all holes, i.e., regions without border elements. ## ## Alternatively, the argument @var{locations} are coordinates for elements ## in the regions to be filled. It can be a a @var{n}-by-1 vector of linear ## indices or a @var{n}-by-@var{d} matrix of subscript indices where @var{n} ## is the number of points and @var{d} is the number of dimensions in the ## image. ## ## The argument @var{conn} specifies the connectivity used for filling ## the region and defaults to ## @code{conndef (ndims (@var{img}, @qcode{"minimal"})} which is 4 for ## the case of 2 dimensional images. ## ## @example ## im = [0 1 0 ## 1 0 1 ## 0 1 0]; ## ## imfill (im, "holes") ## ans = ## ## 0 1 0 ## 1 1 1 ## 0 1 0 ## @end example ## ## @seealso{bwfill, bwselect, imreconstruct} ## @end deftypefn function filled = imfill (img, varargin) if (nargin < 1 || nargin > 3) print_usage (); endif if (! isimage (img)) error ("imfill: IMG and BW must be a binary or grayscale image"); endif ## Default parameter values conn = conndef (ndims (img), "minimal"); fill_holes = false; if (nargin () == 1) if (islogical (img)) ## imfill (BW) error ("imfill: interactive usage is not yet supported"); else ## syntax: imfill (img) fill_holes = true; endif elseif (nargin () == 2) opt2 = varargin{1}; if (ischar (opt2)) ## syntax: imfill (BW, "holes") or imfill (IMG, "holes") validatestring (opt2, {"holes"}, "imfill", "OPTION"); fill_holes = true; elseif (! islogical (img)) ## syntax: imfill (IMG, CONN) fill_holes = true; iptcheckconn (opt2, "imfill", "CONN"); conn = opt2; elseif (islogical (img) && isnumeric (opt2) && isindex (opt2)) ## syntax: imfill (BW, LOCATIONS) locations = check_loc (opt2, img); else error ("imfill: second argument must be 'holes', a connectivity specification, or an index array"); endif elseif (nargin () == 3) opt2 = varargin{1}; opt3 = varargin{2}; if (ischar (opt3)) ## syntax: imfill (BW, CONN, "holes") or imfill (IMG, CONN, "holes") validatestring (opt3, {"holes"}, "imfill", "OPTION"); iptcheckconn (opt2, "imfill", "CONN"); conn = opt2; fill_holes = true; elseif (islogical (img) && isnumeric (opt2) && isindex (opt2)) ## syntax: imfill (BW, LOCATIONS, CONN) iptcheckconn(opt3, "imfill", "CONN"); conn = opt3; locations = check_loc (opt2, img); elseif (islogical (img) && isscalar (opt2) && opt2 == 0) ## syntax: imfill (BW, 0, CONN) error ("imfill: interactive usage is not yet supported"); else print_usage (); endif endif if (fill_holes) ## Hole filling algorithm adapted from the book Gonzalez & Woods ## "Digital Image Processing" (3rd Edition), section 9.5.9 ## "Morphological Reconstruction", subsection "Filling holes" (page 682): ## ## "Let I(x,y) denote a binary image and suppose that we form a ## marker image F that is 0 everywhere, except at the image border ## where it is set to 1-I; that is, ## ## / 1 - I(x,y) if (x,y) is on the border of I ## F(x,y) = | ## \ 0 otherwise ## ## Then ## ## H = complement (reconstruct (F, complement (I))) ## ## is a binary image equal to I with all holes filled." ## ## This is generalized to grayscale images with: ## ## * (1-I) -> complement(I) ## * 0 value -> -Inf value if non logical ## ## step 1: define the mask and marker as complement of input ## step 2: set border elements of marker as false/-Inf ## step 3: do morphological reconstruction ## step 4: complement of reconstruction has the holes filled. ## ## Beware of unusual connectivity definition which changes what is ## defined as border pixels. For example, [0 0 0; 1 1 1; 0 0 0], ## means that top and bottom row of an image are not border pixels. mask = imcomplement (img); if (islogical (img)) marker = set_nonborder_pixels (mask, conn, false); else marker = set_nonborder_pixels (mask, conn, -Inf); endif filled = imreconstruct (marker, mask, conn); filled = imcomplement (filled); else ## Using explicitly given marker pixels instead of "holes" option ## should only be used for logical images ## no border padding necessary in this case mask = imcomplement (img); marker = false (size (img)); marker (locations) = mask (locations); filled = imreconstruct (marker, mask, conn); ## Adjusted step 4: add the filled hole(s) FILLED to the original image IMG filled = img | filled; endif endfunction ## Helper function for LOCATIONS input checking. ## Drops locations outside of the image and proceeds with a warning. ## Additionally transforms matrix indices to linear indices. function loc_lin_idx = check_loc (loc, img) sz = size (img); if (ndims (loc) != 2) error ("imfill: LOCATIONS must be a n-by-1 or n-by-d sized index array"); elseif (columns (loc) == 1) # linear indices given idx_outside = loc > numel (img); loc(idx_outside) = []; loc_lin_idx = loc; elseif (columns (loc) == ndims (img)) # subscript indices given idx_outside = any (loc > sz, 2); loc(idx_outside,:) = []; loc_lin_idx = sub2ind (sz, num2cell (loc, 1){:}); else error ("imfill: LOCATIONS must be a n-by-1 or n-by-d sized index array"); endif if (any (idx_outside)) warning ("imfill: ignored LOCATIONS outside of image borders"); endif endfunction ## Set non border of pixels of IMG according to connectivity CONN to VAL. ## The only tricky part is handling unusual connectivity such as ## [0 0 0; 1 1 1; 0 0 0] which define top and bottom row as non border. ## Another case is 8 connectivity in 3d images. In such case, the first ## row and column of each page is border elements, but the first and last ## page itself are not. function marker = set_nonborder_pixels (img, conn, val) sz = size (img); nonborder_idx = repmat ({":"}, ndims (img), 1); conn_idx_tmp = repmat ({":"}, ndims (conn), 1); for dim = 1:ndims (conn) conn_idx = conn_idx_tmp; ## Because connectivity is symmetric by definition, we only need ## to check the first slice of that dimension. conn_idx{dim} = [1]; if (any (conn(conn_idx{:})(:))) nonborder_idx{dim} = 2:(sz(dim) -1); endif endfor marker = img; marker(nonborder_idx{:}) = val; endfunction ## test the possible INPUT IMAGE TYPES %!test %! I = uint8 (5.*[1 1 1; 1 0 1; 1 1 1]); %! bw = logical ([1 1 1; 1 0 1; 1 1 1]); %! I2 = uint8 (5.*ones (3)); %! bw2 = logical (ones (3)); %! %! assert (imfill (int8 (I)), int8 (I2)) %! assert (imfill (int16 (I)), int16 (I2)) %! assert (imfill (int32 (I)), int32 (I2)) %! assert (imfill (int64 (I)), int64 (I2)) %! assert (imfill (uint8 (I)), uint8 (I2)) %! assert (imfill (uint16 (I)), uint16 (I2)) %! assert (imfill (uint32 (I)), uint32 (I2)) %! assert (imfill (uint64 (I)), uint64 (I2)) %! assert (imfill (single (I)), single (I2)) %! assert (imfill (double (I)), double (I2)) %! assert (imfill (bw, "holes"), bw2) %! assert (imfill (uint8 (bw)), uint8 (bw2)) %!error %! imfill (i + ones (3, 3)); # complex input %!error %! imfill (sparse (double (I))); # sparse input %!error %! imfill (); %!error %! imfill (true (3), 4, "holes", 5) %!error %! imfill (false (3), ones (2, 3)) %!error %! imfill (false (3), ones (2, 3), 4) %!error %! imfill (false (3)) %!error %! imfill (false (3), 0, 4) %!warning %! bw = logical ([1 1 1; 1 0 1; 1 1 1]); %! assert (imfill (bw, [5 5]), bw) %! assert (imfill (bw, 15), bw) %! %! bw = repmat (bw, [1 1 3]); %! assert (imfill (bw, 30), bw) %! assert (imfill (bw, [2 2 5]), bw) ## test BINARY hole filling and binary filling from starting point %!test %! bw = logical ([1 0 0 0 0 0 0 0 %! 1 1 1 1 1 0 0 0 %! 1 0 0 0 1 0 1 0 %! 1 0 0 0 1 1 1 0 %! 1 1 1 1 0 1 1 1 %! 1 0 0 1 1 0 1 0 %! 1 0 0 0 1 0 1 0 %! 1 0 0 0 1 1 1 0]); %! bw2 = logical ([1 0 0 0 0 0 0 0 %! 1 1 1 1 1 0 0 0 %! 1 1 1 1 1 0 1 0 %! 1 1 1 1 1 1 1 0 %! 1 1 1 1 1 1 1 1 %! 1 0 0 1 1 1 1 0 %! 1 0 0 0 1 1 1 0 %! 1 0 0 0 1 1 1 0]); %! bw3 = logical ([1 0 0 0 0 0 0 0 %! 1 1 1 1 1 0 0 0 %! 1 1 1 1 1 0 1 0 %! 1 1 1 1 1 1 1 0 %! 1 1 1 1 0 1 1 1 %! 1 0 0 1 1 0 1 0 %! 1 0 0 0 1 0 1 0 %! 1 0 0 0 1 1 1 0]); %! assert (imfill (bw, "holes"), bw2) %! assert (imfill (bw, 8, "holes"), bw2) %! assert (imfill (bw, 4, "holes"), bw2) %! assert (imfill (bw, [3 3]), bw3) %! assert (imfill (bw, 19), bw3) %! assert (imfill (bw, [3 3], 4), bw3) %! assert (imfill (bw, 19, 4), bw3) %! assert (imfill (bw, [3 3], 8), bw2) %! assert (imfill (bw, 19, 8), bw2) %! assert (imfill (bw, [19; 20]), bw3) %! assert (imfill (bw, [19; 20], 4), bw3) %! assert (imfill (bw, [19; 20], 8), bw2) %!warning %! bw = logical ([1 1 1 1 1 1 1 %! 1 0 0 0 0 0 1 %! 1 0 1 1 1 0 1 %! 1 0 1 0 1 0 1 %! 1 0 1 1 1 0 1 %! 1 0 0 0 0 0 1 %! 1 1 1 1 1 1 1]); %! bw44 = logical ([1 1 1 1 1 1 1 %! 1 0 0 0 0 0 1 %! 1 0 1 1 1 0 1 %! 1 0 1 1 1 0 1 %! 1 0 1 1 1 0 1 %! 1 0 0 0 0 0 1 %! 1 1 1 1 1 1 1]); %! bw9 = logical ([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]); %! assert (imfill (bw, "holes"), logical (ones (7))) %! assert (imfill (bw, [4 4]), bw44) %! assert (imfill (bw, 9), bw9) %! assert (imfill (bw, [4 4; 10 10]), bw44) %!test %! bw = logical ([1 1 0 1 1]); %! assert (imfill (bw, "holes"), bw) %! bw = logical([1 1 0 1 1; 1 1 1 1 1]); %! assert (imfill (bw, "holes"), bw) ## test hole filling with extravagant connectivity definitions %!test %! I = zeros (5); %! I(:, [2 4]) = 1; %! I2_expected = [0 1 1 1 0 %! 0 1 1 1 0 %! 0 1 1 1 0 %! 0 1 1 1 0 %! 0 1 1 1 0]; %! I2 = imfill (I, [0 0 0; 1 1 1; 0 0 0], "holes"); %! assert (I2, I2_expected) %!test %! I = zeros (5); %! I(:, [2 4]) = 1; %! I2_expected = I; %! I2 = imfill (I, [0 1 0; 0 1 0; 0 1 0], "holes"); %! assert (I2, I2_expected) %!test # this test is Matlab compatible %! I = zeros (5); %! I(:, [2 4]) = 1; %! I2_expected = inf .* ones (5); %! I2 = imfill (I, [0 0 0; 0 1 0; 0 0 0], "holes"); %! assert (I2, I2_expected) %!test %! I = false (5); %! I(:, [2 4]) = true; %! I2_expected = true (5); %! I2 = imfill (I, [0 0 0; 0 1 0; 0 0 0], "holes"); %! assert (I2, I2_expected) ## test GRAYSCALE hole filling %!test %! I = uint8 ([10 20 80 85 20 %! 15 90 03 25 88 %! 05 85 02 50 83 %! 90 04 03 80 80 %! 10 81 83 85 30]); %! I2 = uint8 ([10 20 80 85 20 %! 15 90 80 80 88 %! 05 85 80 80 83 %! 90 80 80 80 80 %! 10 81 83 85 30]); %! I3 = uint8 ([10 20 80 85 20 %! 15 90 05 25 88 %! 05 85 05 50 83 %! 90 05 05 80 80 %! 10 81 83 85 30]); %! assert (imfill (I), I2) %! assert (imfill (I, 4), I2) %! assert (imfill (I, 4, "holes"), I2) %! assert (imfill (I, 8), I3) %! assert (imfill (I, "holes"), I2) ## Test dimensions of length 1 whose extremes may or may not be on the ## border due to less typical connectivity. %!test %! v_line = [0 1 0; 0 1 0; 0 1 0]; %! h_line = [0 0 0; 1 1 1; 0 0 0]; %! im = [0 1 0 0 1 0]; %! %! assert (imfill (im, h_line, "holes"), [0 1 1 1 1 0]) %! assert (imfill (im, v_line, "holes"), [0 1 0 0 1 0]) %! assert (imfill (im', h_line, "holes"), [0 1 0 0 1 0]') %! assert (imfill (im', v_line, "holes"), [0 1 1 1 1 0]') %! %! im = repmat (im, [1 1 5]); %! assert (imfill (im, h_line, "holes"), repmat ([0 1 1 1 1 0], [1 1 5])) %! assert (imfill (im, v_line, "holes"), im) %! %! im = permute (im, [2 1 3]); %! assert (imfill (im, h_line, "holes"), im) %! assert (imfill (im, v_line, "holes"), repmat ([0 1 1 1 1 0]', [1 1 5])) %!test %! im = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 0 0 1 0 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! fi = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 1 1 1 0 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! %! assert (imfill (cat (3, im, im, im), 8, 'holes'), cat (3, fi, fi, fi)) %! assert (imfill (cat (3, im, im, im), 'holes'), cat (3, im, im, im)) %! assert (imfill (cat (3, fi, im, fi), 'holes'), cat (3, fi, fi, fi)) %!test %! emp = false (5, 6); %! im = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 0 1 0 1 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! fi = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 1 1 1 1 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! fi1 = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 1 1 0 1 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! fi2 = logical ([0 0 0 0 0 0 %! 0 1 1 1 1 0 %! 0 1 0 1 1 1 %! 0 1 1 1 1 0 %! 0 0 0 0 0 0]); %! %! assert (imfill (cat (3, im, im, im), [3 3 2]), cat (3, fi1, fi1, fi1)) %! assert (imfill (cat (3, im, im, im), [3 5 2]), cat (3, fi2, fi2, fi2)) %! assert (imfill (cat (3, im, im, im), [3 3 2; 3 5 2]), cat (3, fi, fi, fi)) %! assert (imfill (cat (3, emp, im, emp), [3 3 2]), true (5, 6, 3)) image-2.6.2/inst/PaxHeaders.16724/qtgetblk.m0000644000000000000000000000013213201323063015304 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/qtgetblk.m0000644000175000017500000000732213201323063020050 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.6.2/inst/PaxHeaders.16724/subimage.m0000644000000000000000000000013213201323063015263 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/subimage.m0000644000175000017500000000507013201323063020025 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.6.2/inst/PaxHeaders.16724/radon.m0000644000000000000000000000013213201323063014572 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/radon.m0000644000175000017500000000454313201323063017340 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.6.2/inst/PaxHeaders.16724/xyz2rgb.m0000644000000000000000000000013213201323063015076 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/xyz2rgb.m0000644000175000017500000001117413201323063017642 0ustar00carandraugcarandraug00000000000000## 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{rgb} =} xyz2rgb (@var{xyz}) ## @deftypefnx {Function File} {@var{rgb_map} =} xyz2rgb (@var{xyz_map}) ## Transform a colormap or image from CIE XYZ to sRGB color space. ## ## A color in the CIE XYZ color space consists of three values X, Y and Z. ## Those values are designed to be colorimetric, meaning that their values ## do not depend on the display device hardware. ## ## A color in the RGB space consists of red, green, and blue intensities. ## The output RGB values are calculated to be nonlinear sRGB values ## with the white point D65. This means the output values are in the ## colorimetric (sRGB) colorspace. ## ## Input values of class single and double are acceptecd. ## The shape and the class of the input are conserved. ## ## note: outside the definition range (0<=R, G, B<=1) this function might ## return different (but also nonsense) values than Matlab. ## ## @seealso{rgb2xyz, rgb2lab, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function rgb = xyz2rgb (xyz) if (nargin != 1) print_usage (); endif [xyz, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("xyz2rgb", "XYZ", xyz, 1); # only accept single and double inputs because valid xyz values can be >1 ## transform from CIE XYZ to linear sRGB values with whitepoint D65 ## (source of matrix: book of Burger) matrix_xyz2rgb_D65 = ... [3.240479, -1.537150, -0.498535; -0.969256, 1.875992, 0.041556; 0.055648, -0.204043, 1.057311]; # Matlab uses the following slightly different conversion matrix # matrix_xyz2rgb_D65 = ... # [3.2406, -1.5372, -0.4986; # -0.9689, 1.8758, 0.0415; # 0.0557, -0.2040, 1.0570]; rgb_lin = xyz * matrix_xyz2rgb_D65'; ## transform from linear sRGB values to non-linear sRGB values ## (modified gamma transform) rgb = rgb_lin; mask = rgb_lin <= 0.0031308; rgb(mask) = 12.92 .* rgb_lin(mask); rgb(! mask) = 1.055 .* (rgb_lin(! mask) .^ (1/2.4)) -0.055; rgb = colorspace_conversion_revert (rgb, cls, sz, is_im, is_nd, is_int, 0); endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (xyz2rgb ([0, 0, 0]), [0 0 0], 1e-3) %!assert (xyz2rgb ([0.4125, 0.2127, 0.0193]), [1 0 0], 1e-3) %!assert (xyz2rgb ([0.7700, 0.9278, 0.1385]), [1 1 0], 1e-3) %!assert (xyz2rgb ([0.3576, 0.7152, 0.1192]), [0 1 0], 1e-3) %!assert (xyz2rgb ([0.5380, 0.7873, 1.0694]), [0 1 1], 1e-3) %!assert (xyz2rgb ([0.1804, 0.07217, 0.9502]), [0 0 1], 1e-3) %!assert (xyz2rgb ([0.5929, 0.28484, 0.9696]), [1 0 1], 1e-3) %!assert (xyz2rgb ([0.9505, 1.0000, 1.0888]), [1 1 1], 1e-3) %!assert (xyz2rgb ([0.2034, 0.2140, 0.2330]), [0.5 0.5 0.5], 1e-3) %!assert (xyz2rgb ([0.2155, 0.1111, 0.0101]), [0.75 0 0], 1e-3) %!assert (xyz2rgb ([0.0883, 0.0455, 0.0041]), [0.5 0 0], 1e-3) %!assert (xyz2rgb ([0.0210, 0.0108, 0.0010]), [0.25 0 0], 1e-3) %!assert (xyz2rgb ([0.5276, 0.3812, 0.2482]), [1 0.5 0.5], 1e-3) ## Test tolarant input checking on floats %!assert (xyz2rgb ([1.5 1 1]), [1.5712, 0.7109 0.9717], 1e-3) %!test %! xyz_map = rand (64, 3); %! assert (rgb2xyz (xyz2rgb (xyz_map)), xyz_map, 3e-4); %!test %! xyz_img = rand (64, 64, 3); %! assert (rgb2xyz (xyz2rgb (xyz_img)), xyz_img, 3e-4); ## support sparse input (the only useful xyz value with zeros is black) %!assert (xyz2rgb (sparse ([0 0 0])), [0 0 0], 1e-3) ## conserve class of single input %!assert (class (xyz2rgb (single([0.5 0.5 0.5]))), 'single') ## Test input validation %!error xyz2rgb () %!error xyz2rgb (1,2) %!error xyz2rgb ({1}) %!error xyz2rgb (ones (2,2)) ## Test ND input %!test %! xyz = rand (16, 16, 3, 5); %! rgb = zeros (size (xyz)); %! for i = 1:5 %! rgb(:,:,:,i) = xyz2rgb (xyz(:,:,:,i)); %! endfor %! assert (xyz2rgb (xyz), rgb) image-2.6.2/inst/PaxHeaders.16724/nlfilter.m0000644000000000000000000000013013201323063015304 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/nlfilter.m0000644000175000017500000001425513201323063020055 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.6.2/inst/PaxHeaders.16724/corr2.m0000644000000000000000000000013013201323063014514 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/corr2.m0000644000175000017500000000235513201323063017263 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.6.2/inst/PaxHeaders.16724/imcast.m0000644000000000000000000000013213201323063014747 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imcast.m0000644000175000017500000001543713201323063017521 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.6.2/inst/PaxHeaders.16724/@strel0000644000000000000000000000013213201323063014465 xustar0030 mtime=1510319667.087948349 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/0000755000175000017500000000000013201323063017302 5ustar00carandraugcarandraug00000000000000image-2.6.2/inst/@strel/PaxHeaders.16724/getheight.m0000644000000000000000000000013213201323063016670 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/getheight.m0000644000175000017500000000205113201323063021426 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.6.2/inst/@strel/PaxHeaders.16724/size.m0000644000000000000000000000013213201323063015672 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/size.m0000644000175000017500000000241613201323063020435 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.6.2/inst/@strel/PaxHeaders.16724/subsref.m0000644000000000000000000000013213201323063016371 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/subsref.m0000644000175000017500000000330313201323063021130 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.6.2/inst/@strel/PaxHeaders.16724/getsequence.m0000644000000000000000000000013213201323063017230 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/getsequence.m0000644000175000017500000000521113201323063021767 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.6.2/inst/@strel/PaxHeaders.16724/isscalar.m0000644000000000000000000000013213201323063016521 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/isscalar.m0000644000175000017500000000243313201323063021263 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.6.2/inst/@strel/PaxHeaders.16724/isflat.m0000644000000000000000000000013213201323063016202 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/isflat.m0000644000175000017500000000232213201323063020741 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.6.2/inst/@strel/PaxHeaders.16724/strel.m0000644000000000000000000000013213201323063016051 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/strel.m0000644000175000017500000006153713201323063020625 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.6.2/inst/@strel/PaxHeaders.16724/translate.m0000644000000000000000000000013213201323063016715 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/translate.m0000644000175000017500000000223113201323063021453 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.6.2/inst/@strel/PaxHeaders.16724/display.m0000644000000000000000000000013213201323063016365 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/display.m0000644000175000017500000000275413201323063021135 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.6.2/inst/@strel/PaxHeaders.16724/getneighbors.m0000644000000000000000000000013213201323063017400 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/getneighbors.m0000644000175000017500000000375613201323063022153 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.6.2/inst/@strel/PaxHeaders.16724/getnhood.m0000644000000000000000000000013213201323063016527 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/getnhood.m0000644000175000017500000000170313201323063021270 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.6.2/inst/@strel/PaxHeaders.16724/reflect.m0000644000000000000000000000013213201323063016344 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/reflect.m0000644000175000017500000000501013201323063021100 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.6.2/inst/@strel/PaxHeaders.16724/numel.m0000644000000000000000000000013213201323063016040 xustar0030 mtime=1510319667.083948398 30 atime=1510319667.083948398 30 ctime=1510319668.283933657 image-2.6.2/inst/@strel/numel.m0000644000175000017500000000202613201323063020600 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.6.2/inst/PaxHeaders.16724/im2bw.m0000644000000000000000000000013213201323063014507 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2bw.m0000644000175000017500000001350213201323063017250 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2012-2016 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}) ## @deftypefnx {Function File} {} im2bw (@var{X}, @var{cmap}) ## @deftypefnx {Function File} {} im2bw (@dots{}, @var{threshold}) ## @deftypefnx {Function File} {} im2bw (@dots{}, @var{method}) ## 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}: ## ## @example ## bw = im2bw (img_of_class_uint8, im2double (thresh_of_uint8_class)); ## @end example ## ## For an automatic threshold value, consider using @code{graythresh}. ## The argument @var{method} is a string that specifies a valid algorithm ## available in @code{graythresh}. The following are equivalent: ## ## @example ## bw = im2bw (img, "moments"); ## bw = im2bw (img, graythresh (img(:), "moments")); ## @end example ## ## @seealso{graythresh, ind2gray, rgb2gray} ## @end deftypefn function BW = im2bw (img, cmap, thresh = 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) thresh = cmap; endif if (! isimage (img)) error ("im2bw: IMG must be an image"); elseif (! ischar (thresh) && ! (isnumeric (thresh) && isscalar (thresh) && thresh >= 0 && thresh <= 1)) error ("im2bw: THRESHOLD must be a string or 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 if (ischar (thresh)) thresh = graythresh (img(:), thresh); endif ## Convert the threshold value to same class as the image which ## is faster and saves more memory than the opposite. if (isinteger (img)) ## We do the conversion from double to int ourselves (instead ## of using im2uint* functions), because those functions round ## during the conversion but we need thresh to be the limit. ## See bug #46390. cls = class(img); I_min = double (intmin (cls)); I_range = double (intmax (cls)) - I_min; thresh = cast (floor ((thresh * I_range) + I_min), cls); elseif (isfloat (img)) ## do nothing else ## we should have never got here in the first place anyway error ("im2bw: unsupported image of class '%s'", class (img)); endif tmp = (img > thresh); 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 ## We use "bw = im2bw (...)" because otherwise it would display a figure %!warning bw = im2bw (logical ([0 1 0])); %!warning bw = im2bw (logical ([0 1 0]), 1); %!test %! warning ("off", "all", "local"); %! 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])) ## bug #46390 (on the rounding/casting of the threshold value) %!assert (nnz (im2bw (uint8 ([0:255]), 0.9)), 26) %!test %! img = uint8 ([0:255]); %! s = 0; %! for i=0:.1:1 %! s += nnz (im2bw (img, i)); %! endfor %! assert (s, 1405) ## threshold may be a negative value in the image class so care must ## taken when casting and rounding it. %!assert (nnz (im2bw (int16 ([-128:127]), 0.499)), 194) %!assert (nnz (im2bw (int16 ([-128:127]), 0.500)), 128) %!assert (nnz (im2bw (int16 ([-128:127]), 0.501)), 62) %!test %! img = uint16 ([0:intmax("uint16")]); %! s = 0; %! for i=0:.1:1 %! s += nnz (im2bw (img, i)); %! endfor %! assert (s, 360445) %!test %! img = int16 ([intmin("int16"):intmax("int16")]); %! s = 0; %! for i=0:.1:1 %! s += nnz (im2bw (img, i)); %! endfor %! assert (s, 360445) %!test %! im = [((randn(10)/10)+.3) ((randn(10)/10)+.7)]; %! assert (im2bw (im, "Otsu"), im2bw (im, graythresh (im(:), "Otsu"))) %! assert (im2bw (im, "moments"), im2bw (im, graythresh (im(:), "moments"))) %!test %! im = [((randn(10)/10)+.3) ((randn(10)/10)+.7)]; %! im = reshape (im, [10 10 1 2]); %! assert (im2bw (im, "Otsu"), im2bw (im, graythresh (im(:), "Otsu"))) %! assert (im2bw (im, "moments"), im2bw (im, graythresh (im(:), "moments"))) image-2.6.2/inst/PaxHeaders.16724/tformfwd.m0000644000000000000000000000013213201323063015317 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/tformfwd.m0000644000175000017500000000433313201323063020062 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{XY}] =} tformfwd (@var{T}, @var{UV}) ## @deftypefnx {Function File} {[@var{X}, @var{Y}] =} tformfwd (@var{T}, @var{U}, @var{V}) ## ## Given a transform structure @var{T}, transform coordinates @var{UV} ## in the input space into coordinates @var{XY} in the output space. ## ## Input and output coordinates may be given/retrieved either as a ## n-by-2 array, or as two n-by-1 vectors. ## ## The function makes use of the "forward_fcn" field of the transform ## structure @var{T}, which should thus be defined. ## @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.6.2/inst/PaxHeaders.16724/mat2gray.m0000644000000000000000000000013213201323063015215 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/mat2gray.m0000644000175000017500000001104413201323063017755 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); idx_max = (in >= out_max); in(in <= out_min) = 0; in(idx_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 ## bug #47516 (when MIN is greater than input max value) %!assert (mat2gray ([-3 -2 -1]), [0 0.5 1]) image-2.6.2/inst/PaxHeaders.16724/poly2mask.m0000644000000000000000000000013213201323063015410 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/poly2mask.m0000644000175000017500000001553613201323063020162 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.6.2/inst/PaxHeaders.16724/bwhitmiss.m0000644000000000000000000000012613201323063015503 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bwhitmiss.m0000644000175000017500000000642113201323063020243 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} {} bwhitmiss (@var{bw}, @var{se1}, @var{se2}) ## @deftypefnx {Function File} {} bwhitmiss (@var{bw}, @var{interval}) ## Perform binary hit-or-miss transform. ## ## This transform returns the set of positions, where the structuring ## element @var{se1} fits in the foregrond of @var{bw}, while the ## structuring element @var{se2} misses it completely. It is equivalent ## to: ## ## @example ## imerode (@var{bw}, @var{se1}) & imerode (! @var{bw}, @var{se2}) ## @end example ## ## For example, the following will remove every pixel with adjacent ## horizontal foreground pixels: ## ## @example ## >> bw = [ 0 1 0 1 1 0 ## 0 1 0 1 1 0 ## 0 1 0 1 1 0]; ## ## >> bwhitmiss (bw, [1; 0; 1], [1 0 1]) ## @result{} ans = ## ## 0 1 0 0 0 0 ## 0 1 0 0 0 0 ## 0 1 0 0 0 0 ## @end example ## ## Note that while @var{se1} and @var{se2} must have disjoint neighbourhoods ## for this transform to be meaningful, no error or warning is throw about ## it. ## ## Alternatively a single array @var{interval} can be defined, of values ## from @code{[1 0 -1]}. In this case, the two structuring elements are ## extracted as: ## ## @example ## @var{se1} = (@var{interval} == 1) ## @var{se2} = (@var{interval} == -1) ## @end example ## ## @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.6.2/inst/PaxHeaders.16724/isrgb.m0000644000000000000000000000013213201323063014575 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/isrgb.m0000644000175000017500000000476613201323063017352 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2004 Josep Monés i Teixidor ## Copyright (C) 2011, 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} {} 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, ## real array of size @nospell{MxNx3xK}, and: ## ## @itemize @bullet ## @item of floating point class with values in the [0 1] range or NaN; ## @item of class uint8, uint16, or int16. ## @end itemize ## ## @emph{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; a grayscale image may have ## values outside the range [0 1]. 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) if (isfloat (img)) bool = ispart (@is_float_image, img); elseif (any (isa (img, {"uint8", "uint16", "int16"}))) bool = true; endif 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) + eps), false); %!assert (isrgb (zeros (5, 5, 3) - eps), false); %!assert (isrgb (rand (5, 5, 3) > 0.5), false); %!assert (isrgb (randi ([-100 100], 5, 5, 3, "int16")), true) image-2.6.2/inst/PaxHeaders.16724/graythresh.m0000644000000000000000000000013213201323063015647 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/graythresh.m0000644000175000017500000007430313201323063020416 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.6.2/inst/PaxHeaders.16724/ycbcr2rgb.m0000644000000000000000000000013213201323063015346 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/ycbcr2rgb.m0000644000175000017500000000413113201323063020105 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" ## 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.6.2/inst/PaxHeaders.16724/imattributes.m0000644000000000000000000000013213201323063016203 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imattributes.m0000644000175000017500000001214713201323063020750 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.6.2/inst/PaxHeaders.16724/blockproc.m0000644000000000000000000000012613201323063015450 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/blockproc.m0000644000175000017500000001400713201323063020207 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. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{rgb} =} lab2rgb (@var{lab}) ## @deftypefnx {Function File} {@var{rgb_map} =} lab2rgb (@var{lab_map}) ## Transform a colormap or image from CIE L*a*b* to sRGB color space. ## ## A color in the CIE L*a*b* (or CIE Lab) space consists of lightness L* and ## two color-opponent dimensions a* and b*. The whitepoint is taken as D65. ## The CIE L*a*b* colorspace is a colorimetric colorspace. It is additionally ## designed to incorporate the human perception of color differences. ## ## A color in the RGB space consists of red, green, and blue intensities. ## The input RGB values are interpreted as nonlinear sRGB values ## with the white point D65. This means the input values are assumed to ## be in a colorimetric (sRGB) colorspace. ## ## Input values of class single and double are accepted. ## The shape and the class of the input are conserved. ## ## The input values of L* are normally in the inteval [0, 100] ## and the values of a* and b* in the interval [-127, 127]. ## ## note: This function returns slightly different values than the Matlab ## version. But it has a better "round trip accuracy" (<2e-5) ## for RGB -> Lab -> RGB. ## ## @seealso{rgb2lab, rgb2xyz, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function rgb = lab2rgb (lab) if (nargin != 1) print_usage (); endif [lab, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("lab2rgb", "Lab", lab, 1); # currently only accept single and double inputs (as Matlab does) # (Integer types would be possible, but would need an explanation in the # help text how to scale them.) ## transform from CIE L*a*b* to CIE XYZ values xyz = lab2xyz (lab); ## transform from CIE XYZ to non-linear sRGB values rgb = xyz2rgb (xyz); # always return values of type double for Matlab compatibility (exception: type single) rgb = colorspace_conversion_revert (rgb, cls, sz, is_im, is_nd, is_int, 1); endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (lab2rgb ([0 0 0]), [0, 0, 0], 1e-3) %!assert (lab2rgb ([53.24, 80.09, 67.20]), [1 0 0], 1e-3) %!assert (lab2rgb ([97.14, -21.55, 94.48]), [1 1 0], 1e-3) %!assert (lab2rgb ([87.74, -86.18, 83.18]), [0 1 0], 1e-3) %!assert (lab2rgb ([91.11, -48.09, -14.13]), [0 1 1], 1e-3) %!assert (lab2rgb ([32.30, 79.19, -107.86]), [0 0 1], 1e-3) %!assert (lab2rgb ([60.32, 98.24, -60.83]), [1 0 1], 1e-3) %!assert (lab2rgb ([100, 0.00, 0.00]), [1 1 1], 1e-3) %!assert (lab2rgb ([53.39, 0.00, 0.00]), [0.5 0.5 0.5], 1e-3) %!assert (lab2rgb ([39.77, 64.51, 54.13]), [0.75 0 0], 1e-3) %!assert (lab2rgb ([25.42, 47.91, 37.91]), [0.5 0 0], 1e-3) %!assert (lab2rgb ([9.66, 29.68, 15.24]), [0.25 0 0], 1e-3) %!assert (lab2rgb ([68.11, 48.39, 22.83]), [1 0.5 0.5], 1e-3) ## Test tolarant input checking %!assert (lab2rgb ([150 130 130]), [2.714, 1.028, 0.492], 1e-3) %!test %! lab_map = rand (64, 3); %! lab_map(:,1) = lab_map(:,1) .* 100; %! lab_map(:,2) = lab_map(:,2) .* 254 - 127; %! lab_map(:,3) = lab_map(:,3) .* 254 - 127; %! assert (rgb2lab (lab2rgb (lab_map)), lab_map, 5e-3); %!test %! lab_img = rand (64, 64, 3); %! lab_img(:,:,1) = lab_img(:,:,1) .* 100; %! lab_img(:,:,2) = lab_img(:,:,2) .* 254 - 127; %! lab_img(:,:,3) = lab_img(:,:,3) .* 254 - 127; %! assert (rgb2lab (lab2rgb (lab_img)), lab_img, 5e-3); ## support sparse input %!assert (lab2rgb (sparse ([0 0 0])), [0 0 0], 1e-3) %!assert (lab2rgb (sparse ([100, 0.00, 0.00])), [1 1 1], 1e-3) ## conserve class of single input %!assert (class (lab2rgb (single([50 50 50]))), 'single') ## Test input validation %!error lab2rgb () %!error lab2rgb (1,2) %!error lab2rgb ({1}) %!error lab2rgb (ones (2,2)) ## Test ND input %!test %! lab = rand (16, 16, 3, 5); %! lab(:,:,1,:) = lab(:,:,1,:) .* 100; %! lab(:,:,2,:) = lab(:,:,2,:) .* 254 - 127; %! lab(:,:,3,:) = lab(:,:,3,:) .* 254 - 127; %! rgb = zeros (size (lab)); %! for i = 1:5 %! rgb(:,:,:,i) = lab2rgb (lab(:,:,:,i)); %! endfor %! assert (lab2rgb (lab), rgb) image-2.6.2/inst/PaxHeaders.16724/edgetaper.m0000644000000000000000000000013213201323063015427 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/edgetaper.m0000644000175000017500000001041113201323063020164 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} {} 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.6.2/inst/PaxHeaders.16724/lab2single.m0000644000000000000000000000013213201323063015511 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/lab2single.m0000644000175000017500000000765613201323063020267 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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} {} lab2double (@var{lab}) ## Convert L*a*b* data to single precision. ## ## @var{lab} must be a L*a*b* image or colormap, i.e., its dimensions ## must be MxNx3xK or Mx3. Its type must be double, single, uint16, ## or uint8. ## ## When converted to single, L* values range from 0 to 100, while a* and ## b* range from -128 to 127. When converting from uint16, the upper limit ## is 65280 (higher values will be converted above the range). ## ## @seealso{lab2double, lab2rgb, lab2single, lab2uint8, lab2uin16, lab2xyz} ## @end deftypefn function [lab] = lab2single (lab) if (nargin () != 1) print_usage (); endif lab = lab2cls (lab, "single"); endfunction ## Instead of testing the lab2single function here, we test the ## conversion from single type. The actual tests for lab2single, ## are spread all other lab2* functions. This makes the tests ## simpler. %!test %! l_max_f = 100 + (25500 / 65280); %! ab_max_f = 127 + (255 / 256); %! cm = [ %! -Inf %! Inf %! NaN %! l_max_f %! ab_max_f %! -200 %! -129 %! -128 %! -128+(255/65280)*(0.499) %! -128+(255/65280)*(0.500) %! -128+(255/65280)*(0.501) %! -127 %! -1 %! 0 %! (100/65280)*(0.499999) %! (100/65280)*(0.51) %! (100/65280)*(0.500001) %! 1 %! 99 %! 100 %! 101 %! 126 %! 127 %! 128 %! 254 %! 255 %! 256 %! 257]; %! cm = repmat (single (cm), [1 3]); %! im2d = reshape (cm, [7 4 3]); %! imnd = permute (im2d, [1 4 3 2]); %! %! cm_uint8 = uint8 ([ %! 0 0 0 %! 255 255 255 %! 255 255 255 %! 255 228 228 %! 255 255 255 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 1 1 %! 0 127 127 %! 0 128 128 %! 0 128 128 %! 0 128 128 %! 0 128 128 %! 3 129 129 %! 252 227 227 %! 255 228 228 %! 255 229 229 %! 255 254 254 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255]); %! %! assert (lab2uint8 (cm), cm_uint8) %! im2d_uint8 = reshape (cm_uint8, [7 4 3]); %! assert (lab2uint8 (im2d), im2d_uint8) %! assert (lab2uint8 (imnd), permute (im2d_uint8, [1 4 3 2])) %! %! cm_uint16 = uint16 ([ %! 0 0 0 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 58468 58468 %! 65535 65535 65535 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 1 1 %! 0 1 1 %! 0 256 256 %! 0 32512 32512 %! 0 32768 32768 %! 0 32768 32768 %! 1 32768 32768 %! 1 32768 32768 %! 653 33024 33024 %! 64627 58112 58112 %! 65280 58368 58368 %! 65535 58624 58624 %! 65535 65024 65024 %! 65535 65280 65280 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535]); %! %! assert (lab2uint16 (cm), cm_uint16) %! im2d_uint16 = reshape (cm_uint16, [7 4 3]); %! assert (lab2uint16 (im2d), im2d_uint16) %! assert (lab2uint16 (imnd), permute (im2d_uint16, [1 4 3 2])) %! %! assert (lab2double (cm), double (cm)) %! assert (lab2double (im2d), double (im2d)) %! assert (lab2double (imnd), double (imnd)) image-2.6.2/inst/PaxHeaders.16724/imbothat.m0000644000000000000000000000013213201323063015276 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imbothat.m0000644000175000017500000001574513201323063020052 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.6.2/inst/PaxHeaders.16724/imadd.m0000644000000000000000000000013213201323063014545 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imadd.m0000644000175000017500000000715113201323063017311 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.6.2/inst/PaxHeaders.16724/bwpropfilt.m0000644000000000000000000000013013201323063015655 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/bwpropfilt.m0000644000175000017500000001034713201323063020424 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 cc = bwconncomp (bw, conn); if (no_gray) stats = regionprops (cc, {"PixelIdxList", attrib}); else stats = regionprops (cc, 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.6.2/inst/PaxHeaders.16724/rgb2lab.m0000644000000000000000000000013213201323063015002 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/rgb2lab.m0000644000175000017500000001103613201323063017543 0ustar00carandraugcarandraug00000000000000## 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{lab} =} rgb2lab (@var{rgb}) ## @deftypefnx {Function File} {@var{lab_map} =} rgb2lab (@var{rgb_map}) ## Transform a colormap or image from sRGB to CIE L*a*b* color space. ## ## A color in the RGB space consists of red, green, and blue intensities. ## The input RGB values are interpreted as nonlinear sRGB values ## with the white point D65. This means the input values are assumed to ## be in the colorimetric (sRGB) colorspace. ## ## A color in the CIE L*a*b* (or CIE Lab) space consists of lightness L* and ## two color-opponent dimensions a* and b*. The whitepoint is taken as D65. ## The CIE L*a*b* colorspace is also a colorimetric colorspace. It is designed ## to incorporate the human perception of color differences. ## ## Input values of class double, single, uint8 or uint16 are accepted. ## Output class is generally of type double, only input type single will ## result in an output type of single. The shape of the input is ## conserved. ## ## note: This function returns slightly different values than the Matlab ## version. But it has a better "round trip accuracy" (<2e-5) ## for RGB -> Lab -> RGB. ## ## @seealso{lab2rgb, rgb2xyz, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function lab = rgb2lab (rgb) if (nargin != 1) print_usage (); endif [rgb, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("rgb2lab", "RGB", rgb, 0); ## transform from non-linear sRGB values to CIE XYZ values xyz = rgb2xyz (rgb); ## transform from CIE XYZ values to CIE L*a*b* values lab = xyz2lab (xyz); # always return values of type double for Matlab compatibility (exception: type single) lab = colorspace_conversion_revert (lab, cls, sz, is_im, is_nd, is_int, 1); endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (rgb2lab ([0 0 0]), [0, 0, 0], 1e-2) %!assert (rgb2lab ([1 0 0]), [53.24, 80.09, 67.20], 1e-2) %!assert (rgb2lab ([1 1 0]), [97.14, -21.55, 94.48], 1e-2) %!assert (rgb2lab ([0 1 0]), [87.74, -86.18, 83.18], 1e-2) %!assert (rgb2lab ([0 1 1]), [91.11, -48.09, -14.13], 1e-2) %!assert (rgb2lab ([0 0 1]), [32.30, 79.19, -107.86], 1e-2) %!assert (rgb2lab ([1 0 1]), [60.32, 98.24, -60.83], 1e-2) %!assert (rgb2lab ([1 1 1]), [100, 0.00, 0.00], 1e-2) %!assert (rgb2lab ([0.5 0.5 0.5]), [53.39, 0.00, 0.00], 1e-2) %!assert (rgb2lab ([0.75 0 0]), [39.77, 64.51, 54.13], 1e-2) %!assert (rgb2lab ([0.5 0 0]), [25.42, 47.91, 37.91], 1e-2) %!assert (rgb2lab ([0.25 0 0]), [9.66, 29.68, 15.24], 1e-2) %!assert (rgb2lab ([1 0.5 0.5]), [68.11, 48.39, 22.83], 1e-2) ## Test tolarant input checking on floats %!assert (rgb2lab ([1.5 1 1]), [111.47, 43.42, 17.98], 1e-2) %!test %! rgb_map = rand (64, 3); %! assert (lab2rgb (rgb2lab (rgb_map)), rgb_map, 2e-5); %!test %! rgb_img = rand (64, 64, 3); %! assert (lab2rgb (rgb2lab (rgb_img)), rgb_img, 2e-5); ## support sparse input %!assert (rgb2lab (sparse ([0 0 1])), sparse ([32.30, 79.19, -107.86]), 1e-2) %!assert (rgb2lab (sparse ([0 1 1])), sparse ([91.11, -48.09, -14.13]), 1e-2) %!assert (rgb2lab (sparse ([1 1 1])), sparse ([100, 0.00, 0.00]), 1e-2) ## support integer input (and double output) %!assert (rgb2lab (uint8([255 255 255])), [100, 0.00, 0.00], 1e-2) ## conserve class of single input %!assert (class (rgb2lab (single([1 1 1]))), 'single') ## Test input validation %!error rgb2lab () %!error rgb2lab (1,2) %!error rgb2lab ({1}) %!error rgb2lab (ones (2,2)) ## Test ND input %!test %! rgb = rand (16, 16, 3, 5); %! lab = zeros (size (rgb)); %! for i = 1:5 %! lab(:,:,:,i) = rgb2lab (rgb(:,:,:,i)); %! endfor %! assert (rgb2lab (rgb), lab) image-2.6.2/inst/PaxHeaders.16724/edge.m0000644000000000000000000000013213201323063014373 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/edge.m0000644000175000017500000007167613201323063017154 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999 Andy Adler ## Copyright (C) 2008 Søren Hauberg ## Copyright (C) 2015 Hartmut Gimpel ## 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} {[@var{bw}, @var{thresh}] =} edge (@var{im}, @var{method}, @dots{}) ## Find edges using various methods. ## ## The image @var{im} must be 2 dimensional and grayscale. The @var{method} ## must be a string with the string name. The other input arguments are ## dependent on @var{method}. ## ## @var{bw} is a binary image with the identified edges. @var{thresh} is ## the threshold value used to identify those edges. Note that @var{thresh} ## is used on a filtered image and not directly on @var{im}. ## ## @seealso{fspecial} ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Canny"}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Canny"}, @var{thresh}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Canny"}, @var{thresh}, @var{sigma}) ## Find edges using the Canny method. ## ## @var{thresh} is two element vector for the hysteresis thresholding. ## The lower and higher threshold values are the first and second elements ## respectively. If it is a scalar value, the lower value is set to ## @code{0.4 * @var{thresh}}. ## ## @var{sigma} is the standard deviation to be used on the Gaussian filter ## that is used to smooth the input image prior to estimating gradients. ## Defaults to @code{sqrt (2)}. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Kirsch"}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Kirsch"}, @var{thresh}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Kirsch"}, @var{thresh}, @var{direction}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Kirsch"}, @var{thresh}, @var{direction}, @var{thinning}) ## Find edges using the Kirsch approximation to the derivatives. ## ## Edge points are defined as points where the length of the gradient exceeds ## a threshold @var{thresh}. ## ## @var{thresh} is the threshold used and defaults to twice the square root of the ## mean of the gradient squared of @var{im}. ## ## @var{direction} is the direction of which the gradient is ## approximated and can be @qcode{"vertical"}, @qcode{"horizontal"}, ## or @qcode{"both"} (default). ## ## @var{thinning} can be the string @qcode{"thinning"} (default) or ## @qcode{"nothinning"}. This controls if a simple thinning procedure ## is applied to the edge image such that edge points also need to have ## a larger gradient than their neighbours. The resulting "thinned" ## edges are only one pixel wide. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Lindeberg"}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Lindeberg"}, @var{sigma}) ## Find edges using the the differential geometric single-scale edge ## detector by Tony Lindeberg. ## ## @var{sigma} is the scale (spread of Gaussian filter) at which the edges ## are computed. Defaults to @code{2}. ## ## This method does not use a threshold value and therefore does not return ## one. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"LoG"}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"LoG"}, @var{thresh}, @var{sigma}) ## Find edges by convolving with the Laplacian of Gaussian (LoG) filter, ## and finding zero crossings. ## ## Only zero crossings where the filter response is larger than @var{thresh} ## are retained. @var{thresh} is automatically computed as 0.75*@math{M}, ## where @math{M} is the mean of absolute value of LoG filter response. ## ## @var{sigma} sets the spread of the LoG filter. Default to @code{2}. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Prewitt"}, @dots{}) ## Find edges using the Prewitt approximation to the derivatives. ## ## This method is the same as Kirsch except a different approximation ## gradient is used. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Roberts"}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Roberts"}, @var{thresh}) ## @deftypefnx {Function File} {} edge (@var{im}, @qcode{"Roberts"}, @var{thresh}, @var{thinning}) ## Find edges using the Roberts approximation to the derivatives. ## ## This method is similar to Kirsch except a different approximation ## gradient is used, and the default @var{thresh} is multiplied by sqrt(1.5). ## In addition, there it does not accept the @var{direction} argument. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Sobel"}, @dots{}) ## Find edges using the Sobel approximation to the derivatives. ## ## This method is the same as Kirsch except a different approximation ## gradient is used. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"zerocross"}, @var{thresh}, @var{filter}) ## Find edges by convolving with a user-supplied filter and finding zero ## crossings. ## ## @end deftypefn ## @deftypefn {Function File} {} edge (@var{im}, @qcode{"Andy"}, @var{thresh}, @var{params}) ## Find edges by the original (Andy Adlers) @code{edge} algorithm. ## 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 deftypefn function [bw_out, thresh, varargout] = edge (im, method = "sobel", varargin) if (nargin < 1 || nargin > 5) print_usage (); endif if (! isgray (im)) error ("edge: IM must be a grayscale image"); endif method = tolower (method); switch (method) case {"sobel", "prewitt", "kirsch"} [bw, thresh] = edge_kirsch_prewitt_sobel (im, method, varargin{:}); case "roberts" [bw, thresh, varargout{1:2}] = edge_roberts (im, varargin{:}); case "log" [bw, thresh] = edge_log (im, varargin{:}); case "zerocross" [bw, thresh] = edge_zerocross (im, varargin{:}); case "canny" [bw, thresh] = edge_canny (im, varargin{:}); case "lindeberg" [bw] = edge_lindeberg (im, varargin{:}); case "andy" [bw, thresh] = edge_andy (im, varargin{:}); otherwise error ("edge: unsupported edge detector `%s'", method); endswitch if (nargout == 0) imshow (bw); else bw_out = bw; endif endfunction function [bw, thresh] = edge_kirsch_prewitt_sobel (im, method, varargin) if (numel (varargin) > 3) error ("edge: %s method takes at most 3 extra arguments", method); endif ## This supports thinning, direction, and thresh arguments in any ## order. Matlab madness I tell you. varargin = tolower (varargin); direction_mask = (strcmp (varargin, "both") | strcmp (varargin, "horizontal") | strcmp (varargin, "vertical")); thinning_mask = (strcmp (varargin, "thinning") | strcmp (varargin, "nothinning")); thresh_mask = cellfun (@(x) isnumeric (x) && (isscalar (x) || isempty (x)), varargin); if (! all (direction_mask | thinning_mask | thresh_mask)) error ("edge: %s method takes only THRESH, DIRECTION, and THINNING arguments", method); endif if (nnz (direction_mask) > 1) error ("edge: more than 1 direction argument defined"); elseif (any (direction_mask)) direction = varargin{direction_mask}; else direction = "both"; endif if (nnz (thinning_mask) > 1) error ("edge: more than 1 thinning argument defined"); elseif (any (thinning_mask) && strcmp (varargin{thinning_mask}, "nothinning")) thinning = false; else thinning = true; endif if (nnz (thresh_mask) > 1) error ("edge: more than 1 threshold argument defined"); elseif (any (thresh_mask)) thresh = varargin{thresh_mask}; else thresh = []; endif ## For better speed, the calculation is done with ## squared edge strenght values (strength2) and ## squared threshold values (thresh2). h1 = fspecial (method); h1 ./= sum (abs (h1(:))); # normalize h1 im = im2double (im); switch (direction) case "horizontal" strength2 = imfilter (im, h1, "replicate").^2; case "vertical" strength2 = imfilter (im, h1', "replicate").^2; case "both" strength2 = (imfilter (im, h1, "replicate").^2 + imfilter (im, h1', "replicate").^2); otherwise error ("edge: unknown DIRECTION `%s' for %s method", direction, method); endswitch if (isempty (thresh)) thresh2 = 4 * mean (strength2(:)); thresh = sqrt (thresh2); else thresh2 = thresh .^ 2; endif if (thinning) ## Keep edge strengths for use in non-maximum ## suppresion in the simple_thinning step. strength2(strength2<=thresh2) = 0; bw = simple_thinning (strength2); else bw = strength2 > thresh2; endif endfunction function [bw, thresh, g45, g135] = edge_roberts (im, varargin) if (numel (varargin) > 2) error ("edge: Roberts method takes at most 2 extra arguments"); endif ## This supports thinning, direction, and thresh arguments in any ## order. Matlab madness I tell you. varargin = tolower (varargin); thinning_mask = (strcmp (varargin, "thinning") | strcmp (varargin, "nothinning")); thresh_mask = cellfun (@(x) isnumeric (x) && (isscalar (x) || isempty (x)), varargin); if (! all (thinning_mask | thresh_mask)) error ("edge: roberts method takes only THRESH and THINNING arguments"); endif if (nnz (thinning_mask) > 1) error ("edge: more than 1 thinning argument defined"); elseif (any (thinning_mask) && strcmp (varargin{thinning_mask}, "nothinning")) thinning = false; else thinning = true; endif if (nnz (thresh_mask) > 1) error ("edge: more than 1 threshold argument defined"); elseif (any (thresh_mask)) thresh = varargin{thresh_mask}; else thresh = []; endif h1 = [1 0; 0 -1] ./ 2; h2 = [0 1; -1 0] ./ 2; g45 = imfilter (im, h1, "replicate"); g135 = imfilter (im, h2, "replicate"); strength2 = g45.^2 + g135.^2; if (isempty (thresh)) thresh2 = 6 * mean (strength2(:)); thresh = sqrt (thresh2); else thresh2 = thresh .^ 2; endif if (thinning) ## Keep edge strengths for use in non-maximum ## suppresion in the simple_thinning step. strength2(strength2<=thresh2) = 0; bw = simple_thinning (strength2); else bw = strength2 > thresh2; endif endfunction function [bw, thresh] = edge_log (im, thresh = [], sigma = 2) if (nargin > 1 && (! isnumeric (thresh) || all (numel (thresh) != [0 1]))) error ("edge: THRESH for LoG method must be a numeric scalar or empty"); endif if (nargin > 2 && (! isnumeric (sigma) || ! isscalar (sigma))) error ("edge: SIGMA for LoG method must be a numeric scalar"); endif f = fspecial ("log", (2 * ceil (3*sigma)) +1, sigma); g = conv2 (im, f, "same"); if (isempty (thresh)) thresh = 0.75*mean(abs(g(:))); endif bw = (abs (g) > thresh) & zerocrossings (g); endfunction function [bw, thresh] = edge_zerocross (im, thresh, f) ## because filter is a required argument, so is thresh if (nargin != 3) error ("edge: a FILTER and THRESH are required for the zerocross method"); elseif (! isnumeric (thresh) || all (numel (thresh) != [0 1])) error ("edge: THRESH for zerocross method must be a numeric scalar or empty"); elseif (! isnumeric (f)) error ("edge: FILTER for zerocross method must be numeric"); endif g = conv2 (im, f, "same"); if (isempty (thresh)) thresh = mean (abs (g(:))); endif bw = (abs (g) > thresh) & zerocrossings(g); endfunction function [bw, thresh] = edge_canny (im, thresh = [], sigma = sqrt (2)) if (nargin > 1 && (! isnumeric (thresh) || all (numel (thresh) != [0 1 2]))) error ("edge: THRESH for Canny method must have 0, 1, or 2 elements"); endif if (nargin > 2 && (! isnumeric (sigma) || ! isscalar (sigma))) error ("edge: SIGMA for Canny method must be a numeric scalar"); endif ## Gaussian filtering to change the edge scale. ## Treat each dimensions separately for performance. gauss = fspecial ("gaussian", [1 (8*ceil(sigma))], sigma); im = im2double (im); J = imfilter (im, gauss, "replicate"); J = imfilter (J, gauss', "replicate"); ## edge detection with Prewitt filter (treat dimensions separately) p = [1 0 -1]/2; Jx = imfilter (J, p, "replicate"); Jy = imfilter (J, p', "replicate"); Es = sqrt (Jx.^2 + Jy.^2); Es_max = max (Es(:)); if (Es_max > 0) Es ./= Es_max; endif Eo = pi - mod (atan2 (Jy, Jx) - pi, pi); if (isempty (thresh)) tmp = mean(abs(Es(:))); thresh = [0.4*tmp, tmp]; elseif (numel (thresh) == 1) thresh = [0.4*thresh thresh]; else thresh = thresh(:).'; # always return a row vector endif bw = nonmax_supress(Es, Eo, thresh(1), thresh(2)); endfunction function [bw] = edge_lindeberg (im, sigma = 2) if (nargin > 1 && (! isnumeric (sigma) || ! isscalar (sigma))) error ("edge: SIGMA for Lindeberg method must be a numeric scalar"); 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; endfunction ## The 'andy' edge detector that was present in older versions of 'edge'. function [imout, thresh] = edge_andy (im, 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<2 || 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>=3 # 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 ## 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 ## Test the madness of arbitrary order of input for prewitt, kirsch, ## and sobel methods. %!test %! im = [ %! 249 238 214 157 106 69 60 90 131 181 224 247 252 250 250 %! 250 242 221 165 112 73 62 91 133 183 225 248 252 250 251 %! 252 246 228 173 120 78 63 90 130 181 224 248 253 251 251 %! 253 248 232 185 132 87 62 80 116 170 217 244 253 251 252 %! 253 249 236 198 149 101 66 71 101 155 206 238 252 252 252 %! 254 250 240 210 164 115 73 69 92 143 196 232 252 253 252 %! 70 70 68 61 49 36 24 22 26 38 52 63 70 70 70 %! 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 %! 62 63 62 59 51 42 33 25 22 26 36 45 56 60 62 %! 252 253 252 246 221 190 157 114 90 90 118 157 203 235 248 %! 251 253 254 251 233 209 182 136 103 92 107 139 185 225 245 %! 251 253 254 253 243 227 206 163 128 108 110 133 175 217 242 %! 252 253 254 254 249 241 228 195 164 137 127 139 172 212 239 %! ] / 255; %! %! methods = {"kirsch", "prewitt", "sobel"}; %! for m_i = 1:numel (methods) %! method = methods{m_i}; %! %! bw = edge (im, method, 0.2, "both", "thinning"); %! assert (edge (im, method, 0.2), bw) %! %! args = perms ({0.2, "both", "thinning"}); %! for i = 1:rows (args) %! assert (edge (im, method, args{i,:}), bw) %! endfor %! %! bw = edge (im, method, 0.2, "vertical", "nothinning"); %! args = perms ({0.2, "vertical", "nothinning"}); %! for i = 1:rows (args) %! assert (edge (im, method, args{i,:}), bw) %! endfor %! %! bw = edge (im, method, 0.2, "vertical", "thinning"); %! args = perms ({0.2, "vertical"}); %! for i = 1:rows (args) %! assert (edge (im, method, args{i,:}), bw) %! endfor %! %! bw = edge (im, method, 0.2, "both", "nothinning"); %! args = perms ({0.2, "nothinning"}); %! for i = 1:rows (args) %! assert (edge (im, method, args{i,:}), bw) %! endfor %! endfor %!error %! bw = edge (rand (10), "sobel", 0.2, 0.4) %!error %! bw = edge (rand (10), "sobel", "thinning", "nothinning") %!error %! bw = edge (rand (10), "sobel", "both", "both") %!error %! bw = edge (rand (10), "sobel", [0.2 0.7], "both", "thinning") %!error %! bw = edge (rand (10), "kirsch", 0.2, 0.4) %!error %! bw = edge (rand (10), "kirsch", "thinning", "nothinning") %!error %! bw = edge (rand (10), "kirsch", "both", "both") %!error %! bw = edge (rand (10), "kirsch", [0.2 0.7], "both", "thinning") %!error %! bw = edge (rand (10), "prewitt", 0.2, 0.4) %!error %! bw = edge (rand (10), "prewitt", "thinning", "nothinning") %!error %! bw = edge (rand (10), "prewitt", "both", "both") %!error %! bw = edge (rand (10), "prewitt", [0.2 0.7], "both", "thinning") %!test %! im = [ %! 249 238 214 157 106 69 60 90 131 181 224 247 252 250 250 %! 250 242 221 165 112 73 62 91 133 183 225 248 252 250 251 %! 252 246 228 173 120 78 63 90 130 181 224 248 253 251 251 %! 253 248 232 185 132 87 62 80 116 170 217 244 253 251 252 %! 253 249 236 198 149 101 66 71 101 155 206 238 252 252 252 %! 254 250 240 210 164 115 73 69 92 143 196 232 252 253 252 %! 70 70 68 61 49 36 24 22 26 38 52 63 70 70 70 %! 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 %! 62 63 62 59 51 42 33 25 22 26 36 45 56 60 62 %! 252 253 252 246 221 190 157 114 90 90 118 157 203 235 248 %! 251 253 254 251 233 209 182 136 103 92 107 139 185 225 245 %! 251 253 254 253 243 227 206 163 128 108 110 133 175 217 242 %! 252 253 254 254 249 241 228 195 164 137 127 139 172 212 239 %! ] / 255; %! %! bw = edge (im, "roberts", .2, "thinning"); %! assert (edge (im, "roberts", 0.2), bw) %! assert (edge (im, "roberts", "thinning", 0.2), bw) %! %! bw = edge (im, "roberts", .2, "nothinning"); %! assert (edge (im, "roberts", "nothinning", 0.2), bw) %!error %! bw = edge (rand (10), "roberts", 0.2, 0.4) %!error %! bw = edge (rand (10), "roberts", "thinning", "nothinning") %!error %! bw = edge (rand (10), "roberts", "both", "thinning") ## test how canny threshold arguments are always a row vector %!test %! im = rand (10); %! [~, thresh] = edge (im, "canny"); %! assert (size (thresh), [1 2]) %! [~, thresh] = edge (im, "canny", [.2 .6]); %! assert (thresh, [.2 .6]) %! [~, thresh] = edge (im, "canny", [.2; .6]); %! assert (thresh, [.2 .6]) ## test SOBEL edge detector %!test %! in = zeros (5); %! in(3,3) = 1; %! %! E = logical ([ %! 0 0 0 0 0 %! 0 0 1 0 0 %! 0 1 0 1 0 %! 0 0 1 0 0 %! 0 0 0 0 0]); %! assert (edge (in), E) %! assert (edge (uint8 (in.*100)), E) %! assert (edge (in, "sobel"), E) %! assert (edge (in, "sobel", 0), E) %! assert (edge (in, "sobel", 1), false (5)) %! %! [E, auto_thresh] = edge (in); %! assert (auto_thresh, 0.2449, 1e-4) %! %! V = logical([ %! 0 0 0 0 0 %! 0 1 0 1 0 %! 0 1 0 1 0 %! 0 1 0 1 0 %! 0 0 0 0 0]); %! assert (edge (in, "sobel", 0, "vertical"), V) %! %! H = logical ([ %! 0 0 0 0 0 %! 0 1 1 1 0 %! 0 0 0 0 0 %! 0 1 1 1 0 %! 0 0 0 0 0]); %! assert (edge (in, "sobel", 0, "horizontal"), H) %! %! V = false (5); %! V(3,2) = true; %! V(3,4) = true; %! assert (edge (in, "sobel", [], "vertical"), V) %! %! H = false (5); %! H(2,3) = true; %! H(4,3) = true; %! assert (edge (in, "sobel", [], "horizontal"), H) %!test %! A = ones (5); %! A(3, 3) = 0; %! expected = logical ([ %! 0 0 0 0 0 %! 0 0 1 0 0 %! 0 1 0 1 0 %! 0 0 1 0 0 %! 0 0 0 0 0]); %! assert (edge (A), expected) ## test PREWITT edge detector %!test %! in = zeros (5); %! in(3, 3) = 1; %! %! E = logical ([ %! 0 0 0 0 0 %! 0 1 0 1 0 %! 0 0 0 0 0 %! 0 1 0 1 0 %! 0 0 0 0 0]); %! %! assert (edge (in, "prewitt"), E) %! %! [~, auto_thresh] = edge (in, "prewitt"); %! assert (auto_thresh, 0.2309, 1e-4) %! %! V = logical([ %! 0 0 0 0 0 %! 0 1 0 1 0 %! 0 1 0 1 0 %! 0 1 0 1 0 %! 0 0 0 0 0]); %! assert (edge (in, "prewitt", 0, "vertical"), V) %! %! H = logical ([ %! 0 0 0 0 0 %! 0 1 1 1 0 %! 0 0 0 0 0 %! 0 1 1 1 0 %! 0 0 0 0 0]); %! assert (edge (in, "prewitt", 0, "horizontal"), H) ## test ROBERTS edge detector %!test %! in = zeros (5); %! in(3,3) = 1; %! in(3,4) = 0.9; %! %! E = logical ([ %! 0 0 0 0 0 %! 0 0 1 0 0 %! 0 0 1 0 0 %! 0 0 0 0 0 %! 0 0 0 0 0]); %! %! assert (edge (in, "roberts"), E) %! %! [~, auto_thresh] = edge (in, "roberts"); %! assert (auto_thresh, 0.6591, 1e-4) %! %! E45 = [0 0 0 0 0 %! 0 -0.5 -0.45 0 0 %! 0 0 0.50 0.45 0 %! 0 0 0 0 0 %! 0 0 0 0 0]; %! E135 = [0 0 0 0 0 %! 0 0 -0.50 -0.45 0 %! 0 0.5 0.45 0 0 %! 0 0 0 0 0 %! 0 0 0 0 0]; %! %! [~, ~, erg45, erg135] = edge (in, "roberts"); %! assert (erg45, E45) %! assert (erg135, E135) ## test CANNY edge detector %!test %! in_8 = fspecial ("gaussian", [8 8], 2); %! in_8 /= in_8(4,4); %! in_8_uint8 = im2uint8 (in_8); %! %! ## this is the result from Matlab's old canny method (before 2011a) %! out_8_old = logical ([ %! 0 0 0 0 0 0 0 0 %! 0 0 0 1 1 0 0 0 %! 0 0 1 0 0 1 0 0 %! 0 1 0 0 0 0 1 0 %! 0 1 0 0 0 0 1 0 %! 0 0 1 0 0 1 0 0 %! 0 0 0 1 1 0 0 0 %! 0 0 0 0 0 0 0 0]); %! out_8 = logical ([ %! 0 0 0 0 0 0 0 0 %! 0 1 1 1 1 1 0 0 %! 0 1 0 0 0 1 0 0 %! 0 1 0 0 0 1 0 0 %! 0 1 0 0 0 1 0 0 %! 0 1 1 1 1 1 0 0 %! 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0]); %! out_thresh = [0.34375 0.859375]; %! %! [obs_edge, obs_thresh] = edge (in_8, "Canny"); %! assert (obs_edge, out_8) %! assert (obs_thresh, out_thresh) %! %! [obs_edge_givethresh, obs_thresh_givethresh] ... %! = edge (in_8, "Canny", out_thresh); %! assert (obs_edge_givethresh, out_8) %! assert (obs_thresh_givethresh, out_thresh) %! %! [obs_edge_uint8, obs_thresh_uint8] = edge (in_8_uint8, "Canny"); %! assert (obs_edge_uint8, out_8) %! assert (obs_thresh_uint8, out_thresh) %!test %! in_9 = fspecial ("gaussian", [9 9], 2); %! in_9 /= in_9(5,5); %! %! ## this is the result from Matlab's old canny method (before 2011a) %! out_9_old = logical ([ %! 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 1 0 0 0 1 0 0 %! 0 0 1 0 0 0 1 0 0 %! 0 0 1 0 0 0 1 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]); %! out_9 = logical ([ %! 0 0 0 0 0 0 0 0 0 %! 0 0 1 1 1 1 0 0 0 %! 0 1 1 0 0 1 1 0 0 %! 0 1 0 0 0 0 1 0 0 %! 0 1 0 0 0 0 1 0 0 %! 0 1 1 0 0 1 1 0 0 %! 0 0 1 1 1 1 0 0 0 %! 0 0 0 0 0 0 0 0 0 %! 0 0 0 0 0 0 0 0 0]); %! out_thresh = [0.35 0.875]; %! %! [obs_edge, obs_thresh] = edge (in_9, "Canny"); %! assert (obs_edge, out_9) %! assert (obs_thresh, out_thresh) %! %! [obs_edge_givethresh, obs_thresh_givethresh] ... %! = edge (in_9, "Canny", out_thresh); %! assert (obs_edge_givethresh, out_9) %! assert (obs_thresh_givethresh, out_thresh) image-2.6.2/inst/PaxHeaders.16724/bwselect.m0000644000000000000000000000013013201323063015275 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/bwselect.m0000644000175000017500000000263113201323063020041 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 = 8) [~, idx] = bwfill (! im, cols, rows, connect); imout = false (size (im)); imout(idx) = true; endfunction image-2.6.2/inst/PaxHeaders.16724/imregionalmin.m0000644000000000000000000000013213201323063016321 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/imregionalmin.m0000644000175000017500000000743013201323063021065 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.6.2/inst/PaxHeaders.16724/im2int16.m0000644000000000000000000000013213201323063015040 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2int16.m0000644000175000017500000000426513201323063017607 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.6.2/inst/PaxHeaders.16724/grayslice.m0000644000000000000000000000013213201323063015451 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/grayslice.m0000644000175000017500000000735613201323063020224 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)); sliced_tmp = lookup (v, 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.6.2/inst/PaxHeaders.16724/entropyfilt.m0000644000000000000000000000013213201323063016046 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/entropyfilt.m0000644000175000017500000000672113201323063020614 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.6.2/inst/PaxHeaders.16724/immse.m0000644000000000000000000000013213201323063014601 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/immse.m0000644000175000017500000000354413201323063017347 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.6.2/inst/PaxHeaders.16724/mean2.m0000644000000000000000000000013213201323063014471 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/mean2.m0000644000175000017500000000225013201323063017230 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.6.2/inst/PaxHeaders.16724/imabsdiff.m0000644000000000000000000000013213201323063015413 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/imabsdiff.m0000644000175000017500000000605213201323063020156 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.6.2/inst/PaxHeaders.16724/imgetfile.m0000644000000000000000000000013213201323063015434 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imgetfile.m0000644000175000017500000000632213201323063020177 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} {[@var{path}, @var{flag}] =} imgetfile () ## @deftypefnx {Function File} {[@dots{}] =} imgetfile (@var{options}, @dots{}) ## Open GUI dialogue to select image files. ## ## The GUI dialogue opened is exactly the same as @code{uigetfile} but uses ## recognized image file formats as file filter. All other options from ## @code{uigetfile} are accepted. ## ## The return value @var{path} is a string with the full filepath of the ## selected file. If the @qcode{"MultiSelect"} option is selected, then a ## cell array of strings is returned. ## ## @var{flag} is a logical value, true if there was any issue with file ## selection such as the user closing or cancelling the dialogue with selecting ## a file. It has a value of false otherwise. ## ## @example ## [filepath, flag] = imgetfile (); ## if (flag) ## error ("A file must be selected"); ## endif ## @end example ## ## There is no guarantee that @code{imread} will be capable to read all ## files selected via this dialogue. Possible reasons for this are: ## ## @itemize @bullet ## @item ## the filter uses all the extensions as obtained from @code{imformats}. ## This only means that a format with such extensions is registered, not ## necessarily that read or write support has been implemented; ## ## @item ## the dialogue also has a "All files (*)" filter, so a user is actually ## able to select any file; ## ## @item ## the file may be corrupt; ## ## @item ## it is the file content, and not the file extension, that defines the file ## format. A file may have a file extension that is equal to an image file ## format and not actually be an image file. ## ## @end itemize ## ## The opposite is also true. @code{imread} is able to guess the file ## format even when the file extension is incorrect (or even in the absence ## of a file extension). A file that is filtered out may still be readable ## by @code{imread} or @code{imfinfo}. ## ## @seealso{imformats, uigetfile} ## @end deftypefn function [filepath, flag] = imgetfile (varargin) ext = strcat ("*.", [imformats().ext]); im_filter = strjoin (ext, ";"); [fname, fpath] = uigetfile ({im_filter, "Image files"}, varargin{:}); if (isequal (fname, 0)) flag = true; m = strcmpi (varargin, "MultiSelect"); if (any (m) && strcmpi (varargin{find (m) +1}, "on")) filepath = {}; else filepath = ""; endif else flag = false; filepath = fullfile (fpath, fname); endif endfunction ## Remove from test statistics. No real tests possible. %!assert (1) image-2.6.2/inst/PaxHeaders.16724/applylut.m0000644000000000000000000000013213201323063015341 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/applylut.m0000644000175000017500000000420313201323063020100 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.6.2/inst/PaxHeaders.16724/tforminv.m0000644000000000000000000000013213201323063015333 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/tforminv.m0000644000175000017500000000433513201323063020100 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}] =} tforminv (@var{T}, @var{X}, @var{Y}) ## ## ## Given a transform structure @var{T}, transform coordinates @var{XY} ## in the output space into coordinates @var{UV} in the input space. ## ## Input and output coordinates may be given/retrieved either as a ## n-by-2 array, or as two n-by-1 vectors. ## ## The function makes use of the "inverse_fcn" field of the transform ## structure @var{T}, which should thus be defined. ## @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.6.2/inst/PaxHeaders.16724/bwmorph.m0000644000000000000000000000012613201323063015150 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bwmorph.m0000644000175000017500000010565213201323063017716 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-lantuejoul ## 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.6.2/inst/PaxHeaders.16724/im2uint8.m0000644000000000000000000000013213201323063015146 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2uint8.m0000644000175000017500000000616413201323063017715 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.6.2/inst/PaxHeaders.16724/ordfilt2.m0000644000000000000000000000013013201323063015212 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/ordfilt2.m0000644000175000017500000000304513201323063017756 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.6.2/inst/PaxHeaders.16724/imnoise.m0000644000000000000000000000013213201323063015132 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/imnoise.m0000644000175000017500000001233113201323063017672 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.6.2/inst/PaxHeaders.16724/im2single.m0000644000000000000000000000013213201323063015360 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2single.m0000644000175000017500000000552313201323063020125 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.6.2/inst/PaxHeaders.16724/checkerboard.m0000644000000000000000000000013013201323063016101 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/checkerboard.m0000644000175000017500000001603713201323063020652 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012-2016 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} {} checkerboard () ## @deftypefnx {Function File} {} checkerboard (@var{side}) ## @deftypefnx {Function File} {} checkerboard (@var{side}, @var{size}) ## @deftypefnx {Function File} {} checkerboard (@var{side}, @var{M}, @var{N}) ## @deftypefnx {Function File} {} checkerboard (@var{side}, @var{M}, @var{N}, @var{P}, @dots{}) ## Create checkerboard. ## ## The checkerboard is created by repeating a tile pattern and creating ## a block matrix of size @var{size}, or @var{M}x@var{N}. The tile pattern ## itself is made of four squares of @var{side} pixels wide. Note how the ## number of squares is twice of @var{size}. ## ## The tile pattern is white on black on the right side, and grey on black ## on the left side of the matrix. ## ## At the simplest case, a 2 by 2 pattern with squares of 1 pixel side. ## ## @example ## checkerboard (1, [2 2]) ## @result{} ## 0.0 1.0 0.0 0.7 ## 1.0 0.0 0.7 0.0 ## 0.0 1.0 0.0 0.7 ## 1.0 0.0 0.7 0.0 ## @end example ## ## Defaults to 4x4 tiles 10 pixels wide. ## ## N-Dimensional checkerboards are supported with @var{size} of any length ## or specifying dimension length arguments, i.e., @var{M}, @var{N}, @var{P}, ## @dots{}. ## ## @seealso{ndgrid, repmat} ## @end deftypefn function [board] = checkerboard (side = 10, varargin) if (nargin > 0 && ! (isscalar (side) && isnumeric (side) && side == fix (side) && side >= 0)) error ("checkerboard: SIDE must be a non-negative integer") endif if (numel (varargin) == 0) nd = 2; lengths = [4 4]; else if (any (! cellfun ("isnumeric", varargin))) error ("checkerboard: SIZE or MxNx... list must be numeric"); endif first_var = varargin{1}; if (numel (varargin) == 1) if (isscalar (first_var)) # checkerboard (SIDE, M) lengths = [first_var first_var]; else # checkerboard (SIDE, [M N P ...]) lengths = first_var; endif else # checkerboard (SIDE, M, N, P, ...) if (any (cellfun ("numel", varargin) > 1)) error ("checkerboard: M, N, P, ... must be numeric scalars") endif lengths = cell2mat (varargin); endif endif if (! isvector (lengths) || any (lengths < 0) || any (lengths != fix (lengths))) error ("checkerboard: SIZE or MxNx... list must be non-negative integer") endif nd = numel (lengths); ## Before Octave 4.2, linspace() with N 0 would return the end value. ## We need it to return empty (for the case of side == 0). ## FIXME remove this special case once we are dependent on 4.2 or later if (side == 0) board = reshape ([], zeros (1, nd)); return endif grids = nthargout (1:nd, @ndgrid, linspace (-1, 1, 2*side)); tile = grids{1}; for d = 2:nd tile .*= grids{d}; endfor tile = tile < 0; board = double (repmat (tile, lengths)); ## Set left side of checkerboard to grey on black (0.7 instead of 1). ## ## ideally we would have an option to specify the dimension to do this ## (instead of dimension two - left and right). However, then we can't ## easily differentiate between length of last dimension and the number ## of dimension to do this, so leave it up to the user to permute the ## dimensions after. left_idx = repmat ({":"}, 1, nd); nc = columns (board); left_idx{2} = (nc/2 +1):nc; board(left_idx{:}) *= 0.7; endfunction %!demo %! ## Simplest case, default checkerboard size: %! ## 8 by 8 checkerboard, with squares 10 pixel wide %! board = checkerboard (); %! imshow (board) %!demo %! ## Simplest case, default checkerboard size: %! ## 8 by 16 checkerboard, with squares 5 pixel wide %! board = checkerboard (5, 4, 8); %! imshow (board) ## Special case of "SIZE == 0" still respects number of dimensions. %!assert (checkerboard (0), zeros (0, 0)) %!assert (checkerboard (0, 3), zeros (0, 0)) %!assert (checkerboard (0, 2, 4), zeros (0, 0)) %!assert (checkerboard (0, 2, 4, 3), zeros (0, 0, 0)) %!assert (checkerboard (0, 2, 4, 3, 2), zeros (0, 0, 0, 0)) ## Other special cases that leads to empty checkerboards. %!assert (checkerboard (1, 4, 2, 3, 0), zeros (8, 4, 6, 0)) %!assert (checkerboard (1, 4, 0, 3, 2), zeros (8, 0, 6, 4)) %!assert (checkerboard (2, 4, 0, 3, 2), zeros (16, 0, 12, 8)) %!test %! out = zeros (80); %! i1 = ((1:20:80) .+ (0:9)')(:); %! i2 = ((11:20:80) .+ (0:9)')(:); %! out(i1, i2) = 1; %! out(i2, i1) = 1; %! i1r = ((41:20:80) .+ (0:9)')(:); %! i2r = ((51:20:80) .+ (0:9)')(:); %! out(i2, i1r) = 0.7; %! out(i1, i2r) = 0.7; %! assert (checkerboard (), out) %! assert (checkerboard (10, 4, 4), out) %! assert (checkerboard (10, [4 4]), out) %! assert (checkerboard (10, [4; 4]), out) %!test %! out = zeros (8); %! out(2:2:8, 1:2:8) = 1; %! out(1:2:8, 2:2:8) = 1; %! out(1:2:8, 6:2:8) = 0.7; %! out(2:2:8, 5:2:8) = 0.7; %! assert (checkerboard (1), out) %! assert (checkerboard (1, 4), out) %! assert (checkerboard (1, 4, 4), out) %! assert (checkerboard (1, [4 4]), out) %!test %! out = zeros (10); %! out(2:2:10, 1:2:10) = 1; %! out(1:2:10, 2:2:10) = 1; %! out(1:2:10, 6:2:10) = 0.7; %! out(2:2:10, 7:2:10) = 0.7; %! assert (checkerboard (1, 5), out) %! assert (checkerboard (1, 5, 5), out) %! assert (checkerboard (1, [5 5]), out) %!test %! out = zeros (20); %! out([1:4:20 2:4:20], [3:4:20 4:4:20]) = 1; %! out([3:4:20 4:4:20], [1:4:20 2:4:20]) = 1; %! out([1:4:20 2:4:20], [11:4:20 12:4:20]) = 0.7; %! out([3:4:20 4:4:20], [13:4:20 14:4:20]) = 0.7; %! assert (checkerboard (2, 5), out) %! assert (checkerboard (2, 5, 5), out) %! assert (checkerboard (2, [5 5]), out) %!test %! out = zeros (4, 4, 4); %! out([1 3], 1, [1 3]) = 1; %! out([2 4], 2, [1 3]) = 1; %! out([1 3], 2, [2 4]) = 1; %! out([2 4], 1, [2 4]) = 1; %! out([1 3], 3, [1 3]) = 0.7; %! out([2 4], 4, [1 3]) = 0.7; %! out([1 3], 4, [2 4]) = 0.7; %! out([2 4], 3, [2 4]) = 0.7; %! assert (checkerboard (1, [2 2 2]), out) %! assert (checkerboard (1, 2, 2, 2), out) %!test %! out = zeros (8, 8, 8); %! out([1 2 5 6], [1 2], [1 2 5 6]) = 1; %! out([3 4 7 8], [3 4], [1 2 5 6]) = 1; %! out([1 2 5 6], [3 4], [3 4 7 8]) = 1; %! out([3 4 7 8], [1 2], [3 4 7 8]) = 1; %! out([1 2 5 6], [5 6], [1 2 5 6]) = 0.7; %! out([3 4 7 8], [7 8], [1 2 5 6]) = 0.7; %! out([1 2 5 6], [7 8], [3 4 7 8]) = 0.7; %! out([3 4 7 8], [5 6], [3 4 7 8]) = 0.7; %! assert (checkerboard (2, [2 2 2]), out) %! assert (checkerboard (2, 2, 2, 2), out) image-2.6.2/inst/PaxHeaders.16724/imsmooth.m0000644000000000000000000000013213201323063015326 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imsmooth.m0000644000175000017500000004502613201323063020075 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.6.2/inst/PaxHeaders.16724/colfilt.m0000644000000000000000000000013013201323063015121 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/colfilt.m0000644000175000017500000001544413201323063017673 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.6.2/inst/PaxHeaders.16724/imcrop.m0000644000000000000000000000013213201323063014760 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imcrop.m0000644000175000017500000002075013201323063017524 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2014-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} {} 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. 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) hax = get (h, "currentaxes"); himage = findobj (hax, "type", "image"); if (! isempty (himage)) himage = himage(1); else error ("imcrop: expect the current axes to contain an image") endif cdata = get (himage, "cdata"); xdata = get (himage, "xdata"); ydata = get (himage, "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); if (x(2) < x(1)) [x(1), x(2)] = deal (x(2), x(1)); endif if (y(2) < y(1)) [y(1), y(2)] = deal (y(2), y(1)); endif 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.6.2/inst/PaxHeaders.16724/lab2uint8.m0000644000000000000000000000013213201323063015277 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/lab2uint8.m0000644000175000017500000000525413201323063020045 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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} {} lab2double (@var{lab}) ## Convert L*a*b* data to uint8 precision. ## ## @var{lab} must be a L*a*b* image or colormap, i.e., its dimensions ## must be MxNx3xK or Mx3. Its type must be double, single, uint16, ## or uint8. ## ## When converted from double or single, L* values must range from 0 to ## 100, while a* and b* range from -128 to 127. Values outside this range ## will be capped. ## ## @seealso{lab2double, lab2rgb, lab2single, lab2uint8, lab2uin16, lab2xyz} ## @end deftypefn function [lab] = lab2uint8 (lab) if (nargin () != 1) print_usage (); endif lab = lab2cls (lab, "uint8"); endfunction ## Instead of testing the lab2uint8 function here, we test the ## conversion from uint8 type. The actual tests for lab2uint8, ## are spread all other lab2* functions. This makes the tests ## simpler. %!test %! cm_uint8 = uint8 ([0 1 2 3 4 127 128 200 254 255]); %! cm_uint8 = repmat (cm_uint8(:), [1 3]); %! im2d_uint8 = reshape (cm_uint8, [5 2 3]); %! imnd_uint8 = permute (im2d_uint8, [1 4 3 2]); %! %! cm_uint16 = uint16 ([0 256 512 768 1024 32512 32768 51200 65024 65280]); %! cm_uint16 = repmat (cm_uint16(:), [1 3]); %! assert (lab2uint16 (cm_uint8), cm_uint16) %! im2d_uint16 = reshape (cm_uint16, [5 2 3]); %! assert (lab2uint16 (im2d_uint8), im2d_uint16) %! assert (lab2uint16 (imnd_uint8), permute (im2d_uint16, [1 4 3 2])) %! %! l1 = 100/255; %! cm = [ %! 0 -128 -128 %! l1 -127 -127 %! 2*l1 -126 -126 %! 3*l1 -125 -125 %! 4*l1 -124 -124 %! 127*l1 -1 -1 %! 128*l1 0 0 %! 200*l1 72 72 %! 254*l1 126 126 %! 100 127 127]; %! im2d = reshape (cm, [5 2 3]); %! imnd = permute (im2d, [1 4 3 2]); %! %! assert (lab2double (cm_uint8), cm) %! assert (lab2double (im2d_uint8), im2d) %! assert (lab2double (imnd_uint8), imnd) %! %! assert (lab2single (cm_uint8), single (cm)) %! assert (lab2single (im2d_uint8), single (im2d)) %! assert (lab2single (imnd_uint8), single (imnd)) image-2.6.2/inst/PaxHeaders.16724/imfilter.m0000644000000000000000000000013213201323063015302 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imfilter.m0000644000175000017500000001543313201323063020050 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) 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(2:end, :, :); endif if (mod(fcols,2) == 0) im = im(:, 2:end, :); 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 %!test %! img = [ %! 8 2 6 7 4 3 7 8 4 1 %! 9 9 1 1 4 7 3 3 8 1 %! 2 9 8 3 7 6 5 8 6 5 %! 9 5 9 1 8 2 7 3 5 8 %! 6 8 7 1 2 2 9 9 9 9 %! 1 2 7 8 5 5 9 4 3 2 %! 3 4 7 7 5 9 5 2 7 6 %! 5 9 4 3 6 4 2 3 7 5 %! 9 8 6 9 7 6 2 6 4 1 %! 9 9 2 1 7 3 3 5 6 4]; %! %! expected_corr = [ %! 46 53 30 34 44 42 40 51 42 19 %! 48 66 57 42 46 50 59 58 49 34 %! 48 67 55 54 44 58 50 50 64 39 %! 44 77 52 43 28 55 57 75 70 50 %! 29 51 65 51 42 50 60 62 55 42 %! 23 44 58 59 63 59 55 57 50 36 %! 36 50 52 56 56 47 48 45 47 39 %! 51 64 70 62 56 50 40 38 41 31 %! 58 72 50 49 58 45 41 42 49 28 %! 27 37 27 21 19 26 16 23 24 17]; %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2]), expected_corr) %! %! ## test order of options (and matching with defaults) %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2], 0), expected_corr) %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2], "corr"), expected_corr) %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2], "corr", 0), expected_corr) %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2], 0, "corr"), expected_corr) %! %! expected_conv = [ %! 21 31 23 22 21 28 29 26 22 6 %! 47 55 43 43 51 44 49 64 44 24 %! 56 69 53 34 47 50 57 48 52 37 %! 38 70 60 56 41 57 54 61 66 44 %! 46 67 53 48 32 54 59 65 63 46 %! 28 56 63 50 36 54 58 66 63 47 %! 20 43 55 62 67 57 52 53 44 28 %! 42 51 54 61 57 53 44 46 48 39 %! 53 70 63 50 57 42 38 38 43 33 %! 53 62 50 54 52 44 38 40 40 20]; %! assert (imfilter (img, [0 1 0; 2 1 1; 1 2 2], "conv"), expected_conv) %! %! ## alternative class %! assert (imfilter (single (img), [0 1 0; 2 1 1; 1 2 2]), %! single (expected_corr)) %! assert (imfilter (int8 (img), [0 1 0; 2 1 1; 1 2 2]), %! int8 (expected_corr)) %! assert (imfilter (uint8 (img), [0 1 0; 2 1 1; 1 2 2]), %! uint8 (expected_corr)) %! %! assert (imfilter (single (img), [0 1 0; 2 1 1; 1 2 2], "conv"), %! single (expected_conv)) %! assert (imfilter (int8 (img), [0 1 0; 2 1 1; 1 2 2], "conv"), %! int8 (expected_conv)) %! assert (imfilter (uint8 (img), [0 1 0; 2 1 1; 1 2 2], "conv"), %! uint8 (expected_conv)) %! ## test padding with even sized filters (bug #45568) %!test %! I = zeros (6); %! I(2:3,2:3) = 1; %! F = zeros (4); %! F(2,2:3) = 1; %! result = [0 0 0 0 0 0 %! 1 2 1 0 0 0 %! 1 2 1 0 0 0 %! 0 0 0 0 0 0 %! 0 0 0 0 0 0 %! 0 0 0 0 0 0]; %! assert (imfilter (I, F), result) image-2.6.2/inst/PaxHeaders.16724/hough_circle.m0000644000000000000000000000013213201323063016122 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/hough_circle.m0000644000175000017500000000632213201323063020665 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.6.2/inst/PaxHeaders.16724/immaximas.m0000644000000000000000000000013213201323063015454 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/immaximas.m0000644000175000017500000001117313201323063020217 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.6.2/inst/PaxHeaders.16724/phantom.m0000644000000000000000000000013213201323063015135 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/phantom.m0000644000175000017500000002075013201323063017701 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.6.2/inst/PaxHeaders.16724/otf2psf.m0000644000000000000000000000013013201323063015050 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/otf2psf.m0000644000175000017500000000753513201323063017624 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.6.2/inst/PaxHeaders.16724/iradon.m0000644000000000000000000000013213201323063014743 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/iradon.m0000644000175000017500000001351513201323063017510 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.6.2/inst/PaxHeaders.16724/imdither.m0000644000000000000000000000013213201323063015274 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imdither.m0000644000175000017500000000557613201323063020051 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.6.2/inst/PaxHeaders.16724/impyramid.m0000644000000000000000000000013213201323063015462 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/impyramid.m0000644000175000017500000002445313201323063020232 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2015 Avinoam Kalma ## 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} {} impyramid (@var{im}, @var{direction}) ## Compute gaussian pyramid expansion or reduction. ## ## Create image which is one level up or down in the Gaussian ## pyramid. @var{direction} must be @qcode{"reduce"} or ## @qcode{"expand"}. These operations are only done in the first ## two dimensions, so that even if @var{im} is a N dimensional ## array, only the number of rows and columns will change. ## ## The @qcode{"reduce"} stage is done by low-pass filtering and ## subsampling of 1:2 in each axis. If the size of the original ## image is [M N], the size of the reduced image is ## @qcode{[ceil((M+1)/2) ceil((N+1)/2)]}. ## ## The @qcode{"expand"} stage is done by upsampling the image ## (2:1 in each axis), and then low-pass filtering. If the size ## of the original image is [M N], the size of the expanded image ## is @code{[2M-1 2N-1]}. ## ## Note that image processing pyramids are upside down, so ## @qcode{"reduce"} is going one level @emph{down} in the pyramid, ## while @qcode{"expand"} is going one level @emph{up} in the pyramid. ## ## @example ## @group ## impyramid (im, "reduce"); # return reduced image (one level down) ## impyramid (im, "expand"); # return expanded image (one level up) ## @end group ## @end example ## ## The low-pass filter is defined according to Burt & Adelson [1] ## @code{W(i,j) = w(i)w(j)} where ## @code{w = [0.25-alpha/2 0.25 alpha 0.25 0.25-alpha/2]} with ## @code{alpha = 0.375} ## ## [1] Peter J. Burt and Edward H. Adelson (1983). The Laplacian Pyramid ## as a Compact Image Code. IEEE Transactions on Communications, ## vol. COM-31(4), 532-540. ## ## @seealso{imresize, imfilter} ## @end deftypefn ## Author: Avinoam Kalma function imp = impyramid (im, direction) if (nargin != 2) print_usage (); elseif (! isnumeric (im) && ! isbool (im)) error ("impyramid: IM must be numeric or logical") endif ## low pass filters to be used alpha = 0.375; filt_horz = [(0.25-alpha/2) 0.25 alpha 0.25 (0.25-alpha/2)]; filt_vert = filt_horz.'; nd = ndims (im); sz = size (im); cl = class (im); switch (tolower (direction)) case "reduce" ## vertical low pass filtering im = padarray (im, floor (size (filt_vert) /2), "replicate"); im = convn (im, filt_vert, "valid"); ## horizontal low pass filtering im = padarray (im, floor (size (filt_horz) /2), "replicate"); im = convn (im, filt_horz, "valid"); im = cast (im, cl); ## subsampling idx = repmat ({":"}, 1, nd); idx([1 2]) = {1:2:sz(1), 1:2:sz(2)}; imp = im(idx{:}); case "expand" ## Create image, twice the size (rows and columns only), ## with the original image on the odd pixels. imp_sz = sz .* postpad ([2 2], nd, 1); imp_sz([1 2]) -= 1; imp = zeros (imp_sz, cl); idx = repmat ({":"}, 1, nd); idx([1 2]) = {1:2:imp_sz(1), 1:2:imp_sz(2)}; imp(idx{:}) = im; ## horizontal low pass filtering imp = padarray (imp, floor (size (filt_horz) /2)); imp = convn (imp, filt_horz, "valid"); imp *= 2; ## vertical low pass filtering imp = padarray (imp, floor (size (filt_vert) /2)); imp = convn (imp, filt_vert, "valid"); imp *= 2; imp = cast (imp, cl); otherwise error ("impyramid: DIRECTION must be 'reduce' or 'expand'") endswitch endfunction ## Note that there are small differences, 1 and 2 gray levels, between ## the results here (the ones we get in Octave), and the ones we should ## have for Matlab compatibility. This is specially true for elements ## in the border, and worse when expanding. %!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]; %! %! reduced = [ %! 114 139 131 103 111 %! 97 122 141 110 99 %! 103 123 112 123 121 %! 47 107 134 153 94]; %! %! ## this is what we should return if we were Matlab compatible %! reduced_matlab = [ %! 114 139 131 103 111 %! 97 122 141 111 100 %! 103 123 112 123 122 %! 47 107 134 153 94]; %! %! expanded = [ %! 88 132 160 154 132 108 94 102 120 138 138 100 66 74 96 112 116 104 78 %! 62 98 128 142 146 154 154 140 126 126 122 86 54 58 82 114 132 112 74 %! 36 54 74 100 130 168 184 156 118 104 92 64 40 44 66 100 122 104 66 %! 66 68 64 76 98 130 154 148 132 122 108 80 60 78 104 106 98 98 86 %! 104 106 88 78 78 96 122 144 154 154 140 112 98 124 144 110 74 92 106 %! 102 130 134 120 108 126 154 174 180 172 156 142 138 146 140 96 60 84 106 %! 88 140 170 158 140 156 180 188 180 164 152 154 156 140 112 82 66 84 96 %! 90 136 164 154 134 132 138 136 130 122 120 130 134 108 82 86 100 104 92 %! 92 126 142 136 116 96 80 74 72 82 94 106 106 88 78 108 138 132 102 %! 80 116 140 138 122 96 68 52 52 80 110 114 112 118 128 148 164 164 140 %! 58 98 132 140 130 110 82 62 62 102 142 144 138 154 168 164 156 170 162 %! 36 68 100 120 130 122 106 92 96 134 174 182 172 156 136 116 104 122 124 %! 16 34 58 86 108 114 110 106 112 138 170 184 172 126 74 48 44 60 68]; %! %! ## this is what we should return if we were Matlab compatible %! expanded_matlab = [ %! 115 154 185 178 150 122 105 116 138 159 158 117 78 86 112 129 133 120 103 %! 69 98 128 141 146 152 152 139 125 127 121 87 55 58 81 113 131 112 84 %! 40 54 74 100 131 167 184 157 119 104 92 64 41 44 66 100 121 103 74 %! 76 69 65 75 97 130 153 148 131 122 108 80 61 79 103 105 98 97 98 %! 120 105 88 77 78 96 121 143 155 154 140 112 98 124 143 109 74 91 123 %! 117 129 134 119 107 125 153 173 180 172 156 143 138 146 140 96 60 83 122 %! 99 139 170 157 139 156 181 188 180 164 151 154 156 140 112 81 65 84 110 %! 101 136 163 153 133 132 138 136 130 122 120 130 133 108 82 86 99 104 104 %! 103 126 143 136 116 97 81 73 73 82 94 105 105 87 78 108 138 133 116 %! 90 116 139 139 122 96 69 52 53 80 109 114 111 116 128 148 163 164 160 %! 66 99 131 140 131 109 83 62 62 102 142 144 138 154 169 164 157 169 184 %! 41 68 99 121 130 122 107 92 95 133 173 182 172 156 135 114 105 121 142 %! 21 38 64 98 124 131 127 123 129 160 194 212 199 144 82 52 48 65 85]; %! %! assert (impyramid (uint8 (in), "reduce"), uint8 (reduced)) %! assert (impyramid (uint8 (in), "expand"), uint8 (expanded)) ## Test that that reduction and expansion are done in the ## first 2 dimensions only. %!test %! in = randi ([0 255], [40 39 3 5], "uint8"); %! red = impyramid (in, "reduce"); %! for p = 1:3 %! for n = 1:5 %! assert (red(:,:,p,n), impyramid (in(:,:,p,n), "reduce")) %! endfor %! endfor %! %! exp = impyramid (in, "expand"); %! for p = 1:3 %! for n = 1:5 %! assert (exp(:,:,p,n), impyramid (in(:,:,p,n), "expand")) %! endfor %! endfor %!test %! in = repmat (uint8 (255), [10 10]); %! assert (impyramid (in, "reduce"), repmat (uint8 (255), [5 5])) %! assert (impyramid (in, "expand"), repmat (uint8 (255), [19 19])) ## This test is failing because it uses the expected Matlab results %!test %! in = logical ([ %! 1 0 1 1 0 0 1 1 0 0 %! 1 1 0 0 0 1 0 0 1 0 %! 0 1 1 0 1 1 1 1 1 1 %! 1 0 1 0 1 0 1 0 1 1 %! 1 1 1 0 0 0 1 1 1 1 %! 0 0 1 1 0 0 1 0 0 0 %! 0 0 1 1 0 1 1 0 1 1 %! 1 1 0 0 1 0 0 0 1 0 %! 1 1 1 1 1 1 0 1 0 0 %! 1 1 0 0 1 0 0 0 1 0]); %! %! reduced = logical ([ %! 1 1 0 1 0 %! 1 1 0 1 1 %! 1 1 0 1 1 %! 0 1 0 0 0 %! 1 1 1 0 0]); %! %! expanded = logical ([ %! 1 1 0 0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 %! 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 %! 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 1 1 0 0 %! 1 1 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 %! 0 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 %! 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 %! 1 1 0 1 1 0 0 0 1 0 0 1 1 1 0 1 1 1 1 %! 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 %! 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 %! 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 %! 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 %! 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 0 0 0 %! 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 %! 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 %! 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 %! 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 %! 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 %! 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 %! 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0]); %! %! assert (impyramid (in, "reduce"), reduced) %! assert (impyramid (in, "expand"), expanded) image-2.6.2/inst/PaxHeaders.16724/imgradient.m0000644000000000000000000000013213201323063015612 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imgradient.m0000644000175000017500000000673313201323063020363 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.6.2/inst/PaxHeaders.16724/imshear.m0000644000000000000000000000013213201323063015117 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imshear.m0000644000175000017500000001020713201323063017657 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.6.2/inst/PaxHeaders.16724/getrangefromclass.m0000644000000000000000000000013213201323063017175 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/getrangefromclass.m0000644000175000017500000000530513201323063021740 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.6.2/inst/PaxHeaders.16724/iptcheckmap.m0000644000000000000000000000013213201323063015757 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/iptcheckmap.m0000644000175000017500000000454613201323063020530 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.6.2/inst/PaxHeaders.16724/qtdecomp.m0000644000000000000000000000013213201323063015303 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/qtdecomp.m0000644000175000017500000002315713201323063020053 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)) error ("imresize: IM must be an 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)) ## Do not enforce floating point images to be in the [0 1] range (bug #43846) %!assert (imresize (repmat (5, [3 3]), 2), repmat (5, [6 6]), eps*100) ## Similarly, do not enforce images to have specific dimensions and only ## expand on the first 2 dimensions. %!assert (imresize (repmat (5, [3 3 2]), 2), repmat (5, [6 6 2]), eps*100) ## 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.6.2/inst/PaxHeaders.16724/bweuler.m0000644000000000000000000000012613201323063015137 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bweuler.m0000644000175000017500000000645213201323063017703 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"); elseif (ndims (BW) != 2) error ("bweuler: BW must have 2 dimensions"); 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 = false (size (BW) +1); BWaux(2:end,2:end) = BW; 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); %!error <2 dimensions> bweuler (true (5, 5, 1, 5)) image-2.6.2/inst/PaxHeaders.16724/entropy.m0000644000000000000000000000013213201323063015167 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/entropy.m0000644000175000017500000000404013201323063017725 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.6.2/inst/PaxHeaders.16724/fspecial.m0000644000000000000000000000013213201323063015255 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/fspecial.m0000644000175000017500000004723213201323063020025 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2005 Søren Hauberg ## 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} {} fspecial (@var{type}, @dots{}) ## Create spatial filters for image processing. ## ## @var{type} is a string specifying the filter name. The input arguments ## that follow are type specific. The return value is a correlation kernel, ## often to be used by @code{imfilter}. ## ## @seealso{conv2, convn, filter2, imfilter} ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("average") ## @deftypefnx {Function File} {} fspecial ("average", @var{lengths}) ## Rectangular averaging filter. ## ## The optional argument @var{lengths} controls the size of the filter. ## If @var{lengths} 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. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("disk") ## @deftypefnx {Function File} {} fspecial ("disk", @var{radius}) ## Circular averaging filter. ## ## The optional argument @var{radius} controls the ## radius of the filter. If @var{radius} 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 centred at the middle of the element @var{R}+1,@var{R}+1. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("gaussian") ## @deftypefnx {Function File} {} fspecial ("gaussian", @var{lengths}) ## @deftypefnx {Function File} {} fspecial ("gaussian", @var{lengths}, @var{sigma}) ## Create Gaussian filter. ## ## Returns a N dimensional Gaussian distribution with standard ## deviation @var{sigma} and centred in an array of size @var{lengths}. ## ## @var{lengths} defaults to @code{[3 3]} and @var{sigma} to 0.5. ## If @var{lengths} is a scalar, it returns a square matrix of side ## @var{lengths}, .i.e., its value defines both the number of rows and ## columns. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("log") ## @deftypefnx {Function File} {} fspecial ("log", @var{lengths}) ## @deftypefnx {Function File} {} fspecial ("log", @var{lengths}, @var{std}) ## Laplacian of Gaussian. ## ## The optional argument @var{lengths} controls the size of the ## filter. If @var{lengths} 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{std} sets spread of the filter. By default ## a spread of @math{0.5} is used. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("laplacian") ## @deftypefnx {Function File} {} fspecial ("laplacian", @var{alpha}) ## 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. By default it is @math{0.2}. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("unsharp") ## @deftypefnx {Function File} {} fspecial ("unsharp", @var{alpha}) ## 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. By default it is @math{0.2}. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("motion") ## @deftypefnx {Function File} {} fspecial ("motion", @var{lengths}) ## @deftypefnx {Function File} {} fspecial ("motion", @var{lengths}, @var{angle}) ## Motion blur filter of width 1 pixel. ## ## The optional input argument @var{lengths} ## controls the length of the filter, which by default is 9. The argument @var{angle} ## controls the angle of the filter, which by default is 0 degrees. ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("sobel") ## Horizontal Sobel edge filter. ## ## The following filter is returned ## ## @example ## [ 1 2 1 ## 0 0 0 ## -1 -2 -1 ] ## @end example ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("prewitt") ## Horizontal Prewitt edge filter. ## ## The following filter is returned ## ## @example ## [ 1 1 1 ## 0 0 0 ## -1 -1 -1 ] ## @end example ## ## @end deftypefn ## ## @deftypefn {Function File} {} fspecial ("kirsch") ## Horizontal Kirsch edge filter. ## ## The following filter is returned ## ## @example ## [ 3 3 3 ## 3 0 3 ## -5 -5 -5 ] ## @end example ## ## @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 (); 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" ## fspecial ("gaussian", lengths = [3 3], sigma = 0.5) if (nargin < 2) lengths = [3 3]; else validateattributes (arg1, {"numeric"}, {">", 0, "integer"}, "fspecial (\"gaussian\")", "LENGTHS"); if (isempty (arg1)) error ("fspecial (\"gaussian\"): LENGTHS must not be empty"); elseif (numel (arg1) == 1) lengths = [arg1 arg1]; else lengths = arg1(:).'; endif endif if (nargin < 3) sigma = 0.5; else ## TODO add support for different sigmas for each dimension validateattributes (arg2, {"numeric"}, {">", 0, "scalar"}, "fspecial (\"gaussian\")", "SIGMA"); sigma = arg2; endif lengths -= 1; lengths /= 2; pos = arrayfun ("colon", -lengths, lengths, "uniformoutput", false); dist = 0; for d = 1:numel(lengths) dist = dist .+ (vec (pos{d}, d) .^2); # broadcasting with '.+=' does not work endfor f = exp (- (dist) / (2 * (sigma.^2))); f /= sum (f(:)); 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 ## ## Tests for disk shape ## ## 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 ## ## Tests for gaussian shape ## %!error %! fspecial ("gaussian", 0) %!error %! fspecial ("gaussian", 3.9) %!assert (fspecial ("gaussian"), fspecial ("gaussian", 3, 0.5)) %!assert (fspecial ("gaussian"), fspecial ("gaussian", [3 3], 0.5)) %!test %! c = ([-1:1].^2) .+ ([-1:1]'.^2); %! gauss = exp (- (c ./ (2 * (0.5 .^ 2)))); %! f = gauss / sum (gauss(:)); %! assert (fspecial ("gaussian"), f) %! %! expected = [ %! 0.01134373655849507 0.08381950580221061 0.01134373655849507 %! 0.08381950580221061 0.61934703055717721 0.08381950580221061 %! 0.01134373655849507 0.08381950580221061 0.01134373655849507]; %! assert (f, expected, eps) ## An implementation of the function for 2d, we must also check it ## against some of the values. Note that hsize is (radius -1) and ## only works for odd lengths. %!function f = f_gaussian_2d (hsize, sigma) %! c = ([(-hsize(1)):(hsize(1))]'.^2) .+ ([(-hsize(2)):(hsize(2))].^2); %! gauss = exp (- (c ./ (2 * (sigma .^ 2)))); %! f = gauss ./ sum (gauss(:)); %!endfunction %!test %! f = fspecial ("gaussian"); %! assert (f, f_gaussian_2d ([1 1], .5)) %! expected = [ %! 0.01134373655849507 0.08381950580221061 0.01134373655849507 %! 0.08381950580221061 0.61934703055717721 0.08381950580221061 %! 0.01134373655849507 0.08381950580221061 0.01134373655849507]; %! assert (f, expected, eps) %!test %! f = fspecial ("gaussian", 7, 2); %! assert (f, f_gaussian_2d ([3 3], 2)) %! expected = [ %! 0.00492233115934352 %! 0.00919612528958620 %! 0.01338028334410124 %! 0.01516184737296414 %! 0.01338028334410124 %! 0.00919612528958620 %! 0.00492233115934352 %! 0.00919612528958620 %! 0.01718062389630964 %! 0.02499766026691484 %! 0.02832606006174462 %! 0.02499766026691484 %! 0.01718062389630964 %! 0.00919612528958620 %! 0.01338028334410124 %! 0.02499766026691484 %! 0.03637138107390363 %! 0.04121417419979795 %! 0.03637138107390363 %! 0.02499766026691484 %! 0.01338028334410124 %! 0.01516184737296414 %! 0.02832606006174462 %! 0.04121417419979795 %! 0.04670177773892775]; %! expected = reshape ([expected; expected((end-1):-1:1)], [7 7]); %! assert (f, expected, eps) %!test %! f = fspecial ("gaussian", [7 5], 2); %! assert (f, f_gaussian_2d ([3 2], 2)) %! expected = [ %! 0.01069713252648568 %! 0.01998487459872362 %! 0.02907782096336423 %! 0.03294948784319031 %! 0.02907782096336423 %! 0.01998487459872362 %! 0.01069713252648568 %! 0.01556423598706978 %! 0.02907782096336423 %! 0.04230797985750011 %! 0.04794122192790870 %! 0.04230797985750011 %! 0.02907782096336423 %! 0.01556423598706978 %! 0.01763658993191515 %! 0.03294948784319031 %! 0.04794122192790870 %! 0.05432452146574315]; %! expected = reshape ([expected; expected((end-1):-1:1)], [7 5]); %! assert (f, expected, eps) %!test %! f = fspecial ("gaussian", [4 2], 2); %! expected = [0.10945587477855045 0.14054412522144952]; %! expected = expected([1 1; 2 2; 2 2; 1 1]); %! assert (f, expected, eps) %!test %! expected =[0.04792235409415088 0.06153352068439959 0.07901060453704994]; %! expected = expected([1 2 2 1; 2 3 3 2; 2 3 3 2; 1 2 2 1]); %! assert (fspecial ("gaussian", 4, 2), expected) %!function f = f_gaussian_3d (lengths, sigma) %! [x, y, z] = ndgrid (-lengths(1):lengths(1), -lengths(2):lengths(2), %! -lengths(3):lengths(3)); %! sig_22 = 2 * (sigma.^2); %! f = exp (-((x.^2)/sig_22 + (y.^2)/sig_22 + (z.^2)/sig_22)); %! f = f / sum (f(:)); %!endfunction %!test %! obs = fspecial ("gaussian", [5 5 5]); %! assert (obs, f_gaussian_3d ([2 2 2], .5)) %! %! u_values = [ %! 0.00000000001837155 %! 0.00000000741161178 %! 0.00000005476481523 %! 0.00000299005759843 %! 0.00002209370333384 %! 0.00016325161336690 %! 0.00120627532940896 %! 0.00891323607975882 %! 0.06586040141635063 %! 0.48664620076350640]; %! expected = zeros (5, 5, 5); %! expected([1 5 21 25 101 105 121 125]) = u_values(1); %! expected([2 4 6 10 16 20 22 24 26 30 46 50 76 80 96 100 102 104 106 110 116 120 122 124]) = u_values(2); %! expected([3 11 15 23 51 55 71 75 103 111 115 123]) = u_values(3); %! expected([7 9 17 19 27 29 31 35 41 45 47 49 77 79 81 85 91 95 97 99 107 109 117 119]) = u_values(4); %! expected([8 12 14 18 28 36 40 48 52 54 56 60 66 70 72 74 78 86 90 98 108 112 114 118]) = u_values(5); %! expected([13 53 61 65 73 113]) = u_values(6); %! expected([32 34 42 44 82 84 92 94]) = u_values(7); %! expected([33 37 39 43 57 59 67 69 83 87 89 93]) = u_values(8); %! expected([38 58 62 64 68 88]) = u_values(9); %! expected([63]) = u_values(10); %! assert (obs, expected, 4 * eps) %!test %! obs = fspecial ("gaussian", [5 5 5], 1); %! assert (obs, f_gaussian_3d ([2 2 2], 1)) %! %! u_values = [ %! 0.00016177781678373 %! 0.00072503787330278 %! 0.00119538536377748 %! 0.00324939431236223 %! 0.00535734551968363 %! 0.00883276951279243 %! 0.01456277497493249 %! 0.02400995686159072 %! 0.03958572658629712 %! 0.06526582943894763]; %! expected = zeros (5, 5, 5); %! expected([1 5 21 25 101 105 121 125]) = u_values(1); %! expected([2 4 6 10 16 20 22 24 26 30 46 50 76 80 96 100 102 104 106 110 116 120 122 124]) = u_values(2); %! expected([3 11 15 23 51 55 71 75 103 111 115 123]) = u_values(3); %! expected([7 9 17 19 27 29 31 35 41 45 47 49 77 79 81 85 91 95 97 99 107 109 117 119]) = u_values(4); %! expected([8 12 14 18 28 36 40 48 52 54 56 60 66 70 72 74 78 86 90 98 108 112 114 118]) = u_values(5); %! expected([13 53 61 65 73 113]) = u_values(6); %! expected([32 34 42 44 82 84 92 94]) = u_values(7); %! expected([33 37 39 43 57 59 67 69 83 87 89 93]) = u_values(8); %! expected([38 58 62 64 68 88]) = u_values(9); %! expected([63]) = u_values(10); %! assert (obs, expected, eps) %!test %! obs = fspecial ("gaussian", [3 4 1 5], 3); %! assert (find (obs == max (obs(:))), [29; 32]) %! assert (size (obs), [3 4 1 5]) %! assert (obs(:)(1:30), obs(:)(end:-1:31)) image-2.6.2/inst/PaxHeaders.16724/findbounds.m0000644000000000000000000000013213201323063015622 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/findbounds.m0000644000175000017500000000541013201323063020362 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.6.2/inst/PaxHeaders.16724/rgb2xyz.m0000644000000000000000000000013213201323063015076 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/rgb2xyz.m0000644000175000017500000001210513201323063017635 0ustar00carandraugcarandraug00000000000000## 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{xyz} =} rgb2xyz (@var{rgb}) ## @deftypefnx {Function File} {@var{xyz_map} =} rgb2xyz (@var{rgb_map}) ## Transform a colormap or image from sRGB to CIE XYZ color space. ## ## A color in the RGB space consists of red, green, and blue intensities. ## The input RGB values are interpreted as nonlinear sRGB values ## with the white point D65. This means the input values are assumed to ## be in the colorimetric (sRGB) colorspace. ## ## A color in the CIE XYZ color space consists of three values X, Y and Z. ## Those values are designed to be colorimetric, meaning that their values ## do not depend on the display device hardware. ## ## Input values of class double, single, uint8 or uint16 are accepted. ## Output class is generally of type double, only input type single will ## result in an output type of single. The shape of the input is ## conserved. ## ## note: This function returns slightly different values than the Matlab ## version. But it has a better "round trip accuracy" (<2e-5) ## for RGB -> XYZ -> RGB. ## ## @seealso{xyz2rgb, rgb2lab, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function xyz = rgb2xyz (rgb) if (nargin != 1) print_usage (); endif [rgb, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("rgb2xyz", "RGB", rgb, 0); ## transform from non-linear sRGB values to linear sRGB values ## (inverse modified gamma transform) rgb_lin = rgb; mask = rgb <= 0.04045; rgb_lin(mask) = rgb(mask) ./ 12.92; rgb_lin(! mask) = ((rgb(! mask) + 0.055) ./ 1.055) .^2.4; ## transform from linear sRGB values to CIE XYZ with whitepoint D65 ## (source of this matrix: book of Burger) matrix_rgb2xyz_D65 = ... [0.412453, 0.357580, 0.180423; 0.212671, 0.715160, 0.072169; 0.019334, 0.119193, 0.950227]; # Matlab uses the following slightly different conversion matrix. # matrix_rgb2xyz_D65 = ... # [0.4124, 0.3576, 0.1805; # 0.2126, 0.7152, 0.0722; # 0.0193, 0.1192, 0.9505]; # open source of this transformation matrix: # https://de.wikipedia.org/wiki/CIE-Normvalenzsystem#Umrechnung_der_Farbr.C3.A4ume # on July 30, 2015 xyz = rgb_lin * matrix_rgb2xyz_D65'; # always return values of type double for Matlab compatibility (exception: type single) xyz = colorspace_conversion_revert (xyz, cls, sz, is_im, is_nd, is_int, 1); endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (rgb2xyz ([0 0 0]), [0, 0, 0], 1e-3) %!assert (rgb2xyz ([1 0 0]), [0.4125, 0.2127, 0.0193], 1e-3) %!assert (rgb2xyz ([1 1 0]), [0.7700, 0.9278, 0.1385], 1e-3) %!assert (rgb2xyz ([0 1 0]), [0.3576, 0.7152, 0.1192], 1e-3) %!assert (rgb2xyz ([0 1 1]), [0.5380, 0.7873, 1.0694], 1e-3) %!assert (rgb2xyz ([0 0 1]), [0.1804, 0.0722, 0.9502], 1e-3) %!assert (rgb2xyz ([1 0 1]), [0.5929, 0.2848, 0.9696], 1e-3) %!assert (rgb2xyz ([1 1 1]), [0.9505, 1.0000, 1.0888], 1e-3) %!assert (rgb2xyz ([0.5 0.5 0.5]), [0.2034, 0.2140, 0.2330], 1e-3) %!assert (rgb2xyz ([0.75 0 0]), [0.2155, 0.1111, 0.0101], 1e-3) %!assert (rgb2xyz ([0.5 0 0]), [0.0883, 0.0455, 0.0041], 1e-3) %!assert (rgb2xyz ([0.25 0 0]), [0.0210, 0.0108, 0.0010], 1e-3) %!assert (rgb2xyz ([1 0.5 0.5]), [0.5276, 0.3812, 0.2482], 1e-3) ## Test tolarant input checking on floats %!assert (rgb2xyz ([1.5 1 1]), [1.5845, 1.3269, 1.1185], 1e-3) %!test %! rgb_map = rand (64, 3); %! assert (xyz2rgb (rgb2xyz (rgb_map)), rgb_map, 2e-5); %!test %! rgb_img = rand (64, 64, 3); %! assert (xyz2rgb (rgb2xyz (rgb_img)), rgb_img, 2e-5); ## support sparse input %!assert (rgb2xyz (sparse ([0 0 0])), [0 0 0], 1e-3) %!assert (rgb2xyz (sparse ([0 0 1])), [0.1804, 0.0722, 0.9502], 1e-3) ## support integer input (and double output) %!assert (rgb2xyz (uint8([255 255 255])), [0.9505, 1.0000, 1.0888], 1e-3) ## conserve class of single input %!assert (class (rgb2xyz (single([1 1 1]))), 'single') ## Test input validation %!error rgb2xyz () %!error rgb2xyz (1,2) %!error rgb2xyz ({1}) %!error rgb2xyz (ones (2,2)) ## Test ND input %!test %! rgb = rand (16, 16, 3, 5); %! xyz = zeros (size (rgb)); %! for i = 1:5 %! xyz(:,:,:,i) = rgb2xyz (rgb(:,:,:,i)); %! endfor %! assert (rgb2xyz (rgb), xyz) image-2.6.2/inst/PaxHeaders.16724/imrotate.m0000644000000000000000000000013213201323063015313 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/imrotate.m0000644000175000017500000003241013201323063020053 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.6.2/inst/PaxHeaders.16724/rangefilt.m0000644000000000000000000000013213201323063015442 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/rangefilt.m0000644000175000017500000000507713201323063020213 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.6.2/inst/PaxHeaders.16724/qtsetblk.m0000644000000000000000000000013213201323063015320 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/qtsetblk.m0000644000175000017500000000505113201323063020061 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.6.2/inst/PaxHeaders.16724/roicolor.m0000644000000000000000000000013213201323063015317 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/roicolor.m0000644000175000017500000000414313201323063020061 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.6.2/inst/PaxHeaders.16724/bwarea.m0000644000000000000000000000012613201323063014733 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bwarea.m0000644000175000017500000000351613201323063017475 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.6.2/inst/PaxHeaders.16724/imcomplement.m0000644000000000000000000000013213201323063016160 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imcomplement.m0000644000175000017500000000542313201323063020724 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.6.2/inst/PaxHeaders.16724/cp2tform.m0000644000000000000000000000013213201323063015223 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/cp2tform.m0000644000175000017500000002610613201323063017770 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{in_cp}, @var{out_cp}, @var{ttype}) ## @deftypefnx {Function File} {@var{T} =} cp2tform (@dots{}, @var{opt}) ## Return a transformation structure @var{T} (see "help maketform" ## for the form of the structure) that can be further used to ## transform coordinates between an input space and an ouput space. ## ## The transform is inferred from two n-by-2 arrays, @var{in_cp} and ## @var{out_cp}, 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{ttype}: ## ## @table @asis ## @item "affine" ## Return both forward (input space to output space) and inverse 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{in_cp} = [@var{out_cp} ones(rows (out_cp,1))] * Tinv ## @var{out_cp} = [@var{in_cp} ones(rows (in_cp,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 (input space to output space) and inverse 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{out_cp} ones(rows (out_cp,1))] * Tinv ## @var{in_cp} = [u./w, v./w]; ## [x y z] = [@var{in_cp} ones(rows (in_cp,1))] * T ## @var{out_cp} = [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 or 15. Only the inverse transform ## (output space to input space) is included in the structure @var{T}. ## Denoting x and y the output space coordinate vector and u, v the ## the input space coordinates. Inverse transform coefficients are ## stored in a (6,10 or 15)-by-2 matrix which can be used as follows: ## ## @example ## @group ## Second order: ## [u v] = [1 x y x*y x^2 y^2] * Tinv ## @end group ## @group ## Third order: ## [u v] = [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: ## [u v] = [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 TTYPE %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.6.2/inst/PaxHeaders.16724/psnr.m0000644000000000000000000000013213201323063014451 xustar0030 mtime=1510319667.151947563 30 atime=1510319667.151947563 30 ctime=1510319668.283933657 image-2.6.2/inst/psnr.m0000644000175000017500000000415513201323063017216 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.6.2/inst/PaxHeaders.16724/tiff_tag_read.m0000644000000000000000000000013213201323063016245 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/tiff_tag_read.m0000644000175000017500000003326613201323063021017 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.6.2/inst/PaxHeaders.16724/histeq.m0000644000000000000000000000013213201323063014764 xustar0030 mtime=1510319667.103948152 30 atime=1510319667.103948152 30 ctime=1510319668.283933657 image-2.6.2/inst/histeq.m0000644000175000017500000000673513201323063017537 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.6.2/inst/PaxHeaders.16724/imhist.m0000644000000000000000000000013213201323063014764 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/imhist.m0000644000175000017500000001561613201323063017535 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.6.2/inst/PaxHeaders.16724/immultiply.m0000644000000000000000000000013213201323063015674 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/immultiply.m0000644000175000017500000000532013201323063020434 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.6.2/inst/PaxHeaders.16724/colorgradient.m0000644000000000000000000000013013201323063016321 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/colorgradient.m0000644000175000017500000000300713201323063021063 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.6.2/inst/PaxHeaders.16724/bwperim.m0000644000000000000000000000013013201323063015132 xustar0029 mtime=1510319667.09594825 29 atime=1510319667.09594825 30 ctime=1510319668.283933657 image-2.6.2/inst/bwperim.m0000644000175000017500000002150613201323063017700 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 %!test %! 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) %!test %! 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 %!test %! 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) ## This is not a bug. Since connectivity defaults to maximum for the ## number of dimensions, a single slice will be displayed completely ## (this is obvious but very easy to forget) %!test %! a = false (8, 8, 5); %! a(4:5,4:5,2:4) = true; %! a(2:7,2:7,3) = true; %! assert (bwperim (a, 26), a) %! %! ## It is easy to forget that is correct %! b = a; %! b(4:5, 4:5, 3) = false; %! assert (bwperim (a), b) %! %! c = a; %! c(3:6,3:6,3) = false; %! assert (bwperim (a, 4), c) image-2.6.2/inst/PaxHeaders.16724/imgradientxy.m0000644000000000000000000000013213201323063016173 xustar0030 mtime=1510319667.115948005 30 atime=1510319667.115948005 30 ctime=1510319668.283933657 image-2.6.2/inst/imgradientxy.m0000644000175000017500000000770013201323063020737 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.6.2/inst/PaxHeaders.16724/imadjust.m0000644000000000000000000000013213201323063015307 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imadjust.m0000644000175000017500000004443513201323063020061 0ustar00carandraugcarandraug00000000000000## Copyright (C) 1999,2000 Kai Habel ## Copyright (C) 2004 Josep Monés i Teixidor ## Copyright (C) 2015 Carnë Draug ## 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} {} imadjust (@var{I}) ## @deftypefnx {Function File} {} imadjust (@var{I}, [@var{low_in}; @var{high_in}]) ## @deftypefnx {Function File} {} imadjust (@var{I}, [@var{low_in}; @var{high_in}],[@var{low_out}; @var{high_out}]) ## @deftypefnx {Function File} {} imadjust (@dots{}, @var{gamma}) ## @deftypefnx {Function File} {} imadjust (@var{cmap}, @dots{}) ## @deftypefnx {Function File} {} imadjust (@var{RGB}, @dots{}) ## Adjust image or colormap intensity (values). ## ## Returns an image of equal dimensions to @var{I}, @var{cmap}, or ## @var{RGB}, with its intensity values adjusted, usually for the ## purpose of increasing the image contrast. ## ## The values are rescaled according to the input and output limits, ## @var{low_in} and @var{high_in}, and @var{low_out} and @var{high_out} ## respectively. The first pair sets the lower and upper limits ## on the input image, values above and below them being clipped. ## The second pair sets the lower and upper limits for the output ## image, the interval to which the image will be scaled after ## clipping the input limits. ## ## For example: ## ## @example ## imadjust (img, [0.2; 0.9], [0; 1]) ## @end example ## ## will clip all values in @var{img} outside the range [0.2 0.9], ## and then rescale them linearly into the range [0 1]. ## ## The input and output limits must be defined as arrays of 2 rows ## with values in the [0 1] range. Each 2 rows column corresponds ## to a single plane in the input image (or each column of a ## colormap), thus supporting images with any number of dimensions. ## If the limits have only 2 elements, the same limits are on all planes. ## This format is matched to @code{stretchlim} which is designed ## to create the input limits for @code{imadjust}. ## ## By default, the limits are adjusted to maximize the contrast, using ## the whole range of values in the image class; and cause a 2% ## saturation (1% on the lower and upper end of the image). It is ## equivalent to: ## ## @example ## imadjust (@var{I}, stretchlim (@var{I}, 0.01), [0; 1]) ## @end example ## ## A common usage is to maximize the display range without saturation: ## ## @example ## imadjust (img, stretchlim (img, 0)) # adjustment performed per plane ## imadjust (img, stretchlim (img(:), 0)) # equal adjustment to all planes ## @end example ## ## For sake of @sc{Matab} compatibility, an empty array in any of ## the limits is interpreted as @code{[0; 1]}. ## ## If @var{low_out} is higher than @var{high_out}, the output image ## will be reversed (image negative or complement). ## ## The @var{gamma} value shapes the mapping curve between the input ## and output elements. It defaults to 1, a linear mapping. Higher ## values of @var{gamma} will curve the mapping downwards and to the right, ## increasing the contrast in the brighter (higher) values of the ## input image. Lower values of @var{gamma} will curve the mapping ## upwards and to the left, increasing the contrast in the darker (lower) ## values of the input image. ## ## As with the limits, @var{gamma} can have different values for each ## plane, a 1 row column per plane, thus supporting input images with ## any number of dimensions. If only a scalar, the same value is used ## in all planes. ## ## The formula used to perform the mapping (omitting saturation) is: ## ## @example ## low_out + (high_out - low_out) .* ((I - low_in) / (high_in - low_in)) .^ gamma ## @end example ## ## @seealso{brighten, contrast, histeq, stretchlim} ## @end deftypefn function adj = imadjust (img, in, out = [0; 1], gamma = 1) if (nargin () < 1 || nargin () > 4) print_usage (); endif if (! isimage (img)) error ("imadjust: I, RGB, or CMAP must be an image or a colormap"); elseif (! isnumeric (img)) ## isimage() allows for boolean images which imadjust should not error ("imadjust: I, RGB, or CMAP must be numeric"); endif sz = size (img); if (iscolormap (img)) was_colormap = true; img = reshape (img, [sz(1) 1 sz(2)]); sz = size (img); else was_colormap = false; endif n_planes = prod (sz(3:end)); if (nargin () < 2) in = stretchlim (img, 0.01); else in = parse_limits (in, sz); endif out = parse_limits (out, sz); if (! isfloat (gamma) || any (gamma < 0)) error ("imadjust: GAMMA must be a non-negative floating point") elseif (isscalar (gamma)) gamma = repmat (gamma, [1 n_planes]); elseif (! isequal (size (gamma)(2:end), sz(3:end))) error ("imadjust: GAMMA must be a scalar or 1 row per plane") endif if (isfloat (img)) ## To make the computations in N dimensions, we make heavy use of ## broadcasting so reshape to have a single value per plane. in = reshape (in, [2 1 sz(3:end)]); out = reshape (out, [2 1 sz(3:end)]); gamma = reshape (gamma, [1 1 sz(3:end)]); adj = imadjust_direct (img, in, out, gamma); else # must be integer ## We create a LUT and use intlut instead of a simply converting the ## whole image to single or double. This is mainly for memory ## efficiency but also less computationally intensive. Do not ## forget that in scientific images, 500MB uint8 images are not ## uncommon so we don't want to convert them to double. cls = class(img); lut = linspace (0, 1, double (intmax (cls)) - double (intmin (cls)) + 1); ## If there's a single plane or the adjustment are all the same, ## we only need to create one LUT. if (n_planes == 1 || (all ((in(:,:) == in(:,1))(:)) && all ((out(:,:) == out(:,1))(:)) && all (gamma == gamma(1)))) lut = imadjust_direct (lut, in(:,1), out(:,1), gamma(1)); adj = intlut (img, imcast (lut, cls)); else ## Seems like we have different adjustments for each plane. We could ## be smarter than loop over each plane. We could check the unique ## adjustment configurations and loop over them instead. However, ## I'll guess that if the adjustments are not all equal, they are ## likely all different too so this is simpler. adj = zeros (size (img), cls); for i = 1:n_planes lut_adj = imadjust (lut, in(:,i), out(:,i), gamma(i)); adj(:,:,i) = intlut (img(:,:,i), imcast (lut_adj, cls)); endfor endif endif if (was_colormap) adj = reshape (adj, [sz(1) sz(3)]); endif endfunction function limits = parse_limits (limits, sz) if (isempty (limits)) limits = repmat ([0; 1], [1 sz(3:end)]); else if (! isfloat (limits)) error ("imadjust: IN and OUT must be numeric floating-point arrays"); elseif (min (limits(:)) < 0 || max (limits(:)) > 1) error ("imadjust: IN and OUT must be on the range [0 1]"); endif ## Only reshape back into 2 row column for a single plane. ## Require the correct format otherwise. if (numel (limits) == 2) limits = repmat (limits(:), [1 sz(3:end)]); elseif (rows (limits) != 2 || ! isequal (sz(3:end), size (limits)(2:end))) error ("imadjust: IN and OUT must be a 2 row column per plane"); endif endif endfunction ## The code that actually does imadjust without any input checking and ## reshaping. So we can call it from imadjust when we know things are good. function adj = imadjust_direct (img, in, out, gamma) max_scale = all ((out == [0; 1])(:)); max_scale_complement = all ((out == [1; 0])(:)); lo_idx = [1 repmat({":"}, 1, ndims (in))]; hi_idx = [2 repmat({":"}, 1, ndims (in))]; li = in(lo_idx{:}); hi = in(hi_idx{:}); if (max_scale) ## This is the most common case. Used to stretch all the values ## into the [0 1], which can be computed much more efficiently. adj = ((img .- li) ./ (hi - li)) .^ gamma; adj(adj > 1) = 1; adj(adj < 0) = 0; elseif (max_scale_complement) adj = ((img .- li) ./ (hi - li)) .^ gamma; adj = 1 - adj; adj(adj > 1) = 1; adj(adj < 0) = 0; else # this covers all cases but may be slower than needed lo = out(lo_idx{:}); ho = out(hi_idx{:}); ## Image negative is computed if ho < lo although nothing special is ## needed, since formula automatically handles it. adj = (img < li) .* lo; adj += (img >= li & img < hi) .* (lo + (ho - lo) .* ((img - li) ./ (hi - li)) .^ gamma); adj += (img >= hi) .* ho; endif endfunction %!error imadjust ("bad argument"); %!error imadjust ([1:100], "bad argument", [], 1); %!error <2 row column per plane> imadjust ([1:100], [0 1 1], [], 1); %!error <2 row column per plane> imadjust ([1:100], [], [0 1 1], 1); %!error imadjust ([1:100], [], [], [0; 1]); %!error imadjust (rand (5, 5, 3), [], [], [0 1]); %!error imadjust ([1:100], [0; 1], [], -1); %!error imadjust ([1:100], [0; 5], []); %!error imadjust ([1:100], [-2; 1], []); %!error imadjust ([1:100], [], [0; 4]); %!error imadjust ([1:100], [], [-2; 1]); %!error imadjust (rand (5) > .5); ## Test default values to 1% on each end saturated and [] as [0; 1] %!test %! im = [0.01:0.01:1]; %! assert (imadjust (im), [0 linspace(0, 1, 98) 1], eps) %! assert (imadjust (im), imadjust (im, stretchlim (im, 0.01), [0; 1], 1)) %! assert (imadjust (im, []), imadjust (im, [0; 1], [0; 1], 1)) %! assert (imadjust (im, [], []), imadjust (im, [0; 1], [0; 1], 1)) %! assert (imadjust (im, [], [.25 .75]), imadjust (im, [0; 1], [.25; .75], 1)) %! assert (imadjust (im, [.25; .75], []), imadjust (im, [.25; .75], [0; 1], 1)) %!assert (imadjust (linspace (0, 1), [], [.25 .75]), linspace (.25, .75, 100), eps) ## test with only input arg %!assert (imadjust (linspace (0, 1, 100),[1/99; 98/99]), %! [0 linspace(0, 1, 98) 1], eps) %!shared cm %! cm = [[0:8]' [1:9]' [2:10]'] / 10; ## a colormap %!assert (imadjust (cm, [0; 1], [0.5; 1]), (cm /2) + .5) ## with params in row %!assert (imadjust (cm, [0 1], [0.5 1]), (cm /2) + .5) ## a colormap, different output adjustment on each channel %!assert (imadjust (cm, [0; 1], [.1 .2 .3; .7 .8 .9]), %! (cm*.6) .+ [.1 .2 .3], eps) ## a colormap, different input adjustment on each channel %!assert (imadjust (cm, [.2 .4 .6; .7 .8 .9], [0; 1]), %! [[0 0 linspace(0, 1, 6) 1]' ... %! [0 0 0 linspace(0, 1, 5) 1]' ... %! [0 0 0 0 linspace(0, 1, 4) 1]'], eps) ### a colormap, different input and output on each %!assert (imadjust (cm, [.2 .4 .6; .7 .8 .9], [0 .1 .2; .8 .9 1]), %! [[0 0 linspace(0, .8, 6) .8]' ... %! [.1 .1 .1 linspace(.1, .9, 5) .9]' ... %! [.2 .2 .2 .2 linspace(.2, 1, 4) 1]'], eps) ## a colormap, different gamma, input and output on each %!assert (imadjust (cm, [.2 .4 .6; .7 .8 .9], [0 .1 .2; .8 .9 1], [0.5 1 2]), %! [[0 0 0 (((([.3 .4 .5 .6]-.2)/.5).^.5)*.8) .8 .8]' ... %! [.1 .1 .1 linspace(.1, .9, 5) .9]' ... %! [.2 .2 .2 .2 .2 ((((([.7 .8]-.6)/.3).^2).*.8)+.2) 1 1]'], eps*10) ## Handling values outside the [0 1] range %!test %! im = [-0.4:.1:0.8 %! 0.0:.1:1.2 %! 0.1:.1:1.3 %! -0.4:.2:2.0]; %! %! ## just clipping %! assert (imadjust (im, [0; 1], [0; 1]), %! [0 0 0 0 (0:.1:.8) %! (0:.1:1) 1 1 %! (.1:.1:1) 1 1 1 %! 0 0 (0:.2:1) 1 1 1 1 1], eps) %! %! ## clipping and invert %! assert (imadjust (im, [0; 1], [1; 0]), %! [1 1 1 1 (1:-.1:.2) %! (1:-.1:0) 0 0 %! (.9:-.1:0) 0 0 0 %! 1 1 (1:-.2:0) 0 0 0 0 0], eps) %! %! ## rescale %! assert (imadjust (im, [.2; .7], [.1; .9]), %! [1 1 1 1 1 1 1 2.6 4.2 5.8 7.4 9 9 %! 1 1 1 2.6 4.2 5.8 7.4 9 9 9 9 9 9 %! 1 1 2.6 4.2 5.8 7.4 9 9 9 9 9 9 9 %! 1 1 1 1 4.2 7.4 9 9 9 9 9 9 9]/10, eps) %! %! ## rescale and invert %! assert (imadjust (im, [.2; .7], [.9; .1]), %! [9 9 9 9 9 9 9 7.4 5.8 4.2 2.6 1 1 %! 9 9 9 7.4 5.8 4.2 2.6 1 1 1 1 1 1 %! 9 9 7.4 5.8 4.2 2.6 1 1 1 1 1 1 1 %! 9 9 9 9 5.8 2.6 1 1 1 1 1 1 1]/10, eps) ## adjusting only the gamma and nothing else %!assert (imadjust (linspace (0, 1), [], [], 2), linspace (0, 1) .^ 2) %!shared oRGB %! oRGB = zeros (10, 1, 3); %! oRGB(:,:,1) = [0 linspace(0,1,6) 1 1 1]'; %! oRGB(:,:,2) = [0 0 linspace(0,1,6) 1 1]'; %! oRGB(:,:,3) = [0 0 0 linspace(0,1,6) 1]'; %!assert (imadjust (oRGB, [0; 1], [0; 1]), oRGB) %!assert (imadjust (oRGB, [.2; .8], [0; 1]), %! reshape ([[0 0 0 1/3 2/3 1 1 1 1 1]' %! [0 0 0 0 1/3 2/3 1 1 1 1]' %! [0 0 0 0 0 1/3 2/3 1 1 1]'], [10 1 3]), eps) %!assert (imadjust (oRGB, [.2; .8], [.1; .9]), %! reshape ([[.1 .1 .1 (1/3)+(.1/3) (2/3)-(.1/3) .9 .9 .9 .9 .9]' %! [.1 .1 .1 .1 (1/3)+(.1/3) (2/3)-(.1/3) .9 .9 .9 .9]' %! [.1 .1 .1 .1 .1 (1/3)+(.1/3) (2/3)-(.1/3) .9 .9 .9]'], %! [10 1 3]), eps) %!assert (imadjust (oRGB, [.2; .8], [.2; .8]), %! reshape ([[2 2 2 4 6 8 8 8 8 8]' %! [2 2 2 2 4 6 8 8 8 8]' %! [2 2 2 2 2 4 6 8 8 8]']/10, [10 1 3]), eps) ## aRGB, different output for each channel %!assert (imadjust (oRGB, [0; 1], [.1 .2 .3; .9 .8 .7]), %! reshape ([[1 1 2.6 4.2 5.8 7.4 9 9 9 9]' %! [2 2 2 3.2 4.4 5.6 6.8 8 8 8]' %! [3 3 3 3 3.8 4.6 5.4 6.2 7 7]']/10, [10 1 3]), eps) ## a RGB, different input for each channel %!assert (imadjust (oRGB, [.1 .2 .3; .9 .8 .7], [0; 1]), %! reshape ([[0 0 .125 .375 .625 .875 1 1 1 1]' %! [0 0 0 0 1/3 2/3 1 1 1 1]' %! [0 0 0 0 0 .25 .75 1 1 1]'], [10 1 3]), eps*10) ## a RGB, different input and output on each %!assert (imadjust (oRGB, [.1 .2 .3; .9 .8 .7], [.2 0 .4; .5 1 .7 ]), %! reshape ([[.2 .2 .2375 .3125 .3875 .4625 .5 .5 .5 .5]' %! [0 0 0 0 1/3 2/3 1 1 1 1]' %! [.4 .4 .4 .4 .4 .475 .625 .7 .7 .7]'], [10 1 3]), eps) ## Test for ND dimensional images %!test %! img = rand (4, 4, 2, 3, 4); %! adj = zeros (4, 4, 2, 3, 4); %! for p = 1:2 %! for q = 1:3 %! for r = 1:4 %! adj(:,:,p,q,r) = imadjust (img(:,:,p,q,r)); %! endfor %! endfor %! endfor %! assert (imadjust (img), adj) ## Test for ND dimensional images with N dimensional arguments %!test %! img = rand (4, 4, 2, 3, 2); %! adj = zeros (4, 4, 2, 3, 2); %! in = reshape ([ 3 5 7 9 11 13 15 17 19 21 23 25; %! 97 95 93 91 89 87 85 83 81 79 77 75] / 100, [2 2 3 2]); %! out = reshape ([ 5 7 9 11 14 15 17 19 21 23 25 27; %! 95 93 91 89 87 85 83 81 79 77 75 73] / 100, [2 2 3 2]); %! gamma = reshape (0.6:.1:1.7, [1 2 3 2]); %! for p = 1:2 %! for q = 1:3 %! for r = 1:2 %! adj(:,:,p,q,r) = imadjust (img(:,:,p,q,r), in(:,p,q,r), %! out(:,p,q,r), gamma(1,p,q,r)); %! endfor %! endfor %! endfor %! assert (imadjust (img, in, out, gamma), adj) ## Test how empty matrix is not really the default value %!test %! in = int16 (1:6); %! assert (imadjust (in), int16 ([-32768 -19661 -6554 6553 19660 32767])) %! assert (imadjust (in, []), in) ## ## Test images of integer class ## %!test %! in = uint8([ %! 35 1 6 26 19 24 %! 3 32 7 21 23 25 %! 31 9 2 22 27 20 %! 8 28 33 17 10 15 %! 30 5 34 12 14 16 %! 4 36 29 13 18 11]); %! out = uint8([ %! 12 0 0 1 0 0 %! 0 8 0 0 0 0 %! 7 0 0 0 2 0 %! 0 3 9 0 0 0 %! 6 0 11 0 0 0 %! 0 13 4 0 0 0]); %! assert (imadjust (in, [.1 .9], [0 1]), out); %!test %! in = uint8([ %! 140 4 24 104 76 96 %! 12 128 28 84 92 100 %! 124 36 8 88 108 80 %! 32 112 132 68 40 60 %! 120 20 136 48 56 64 %! 16 144 116 52 72 44]); %! out = uint8([ %! 143 0 0 98 63 88 %! 0 128 3 73 83 93 %! 123 13 0 78 103 68 %! 8 108 133 53 18 43 %! 118 0 138 28 38 48 %! 0 148 113 33 58 23]); %! assert (imadjust (in, [.1 .9], [0 1]), out); %!test %! in_u8 = randi ([0 255], 5, 5, 2, 3, "uint8"); %! in_u16 = randi ([0 65535], 5, 5, 2, 3, "uint16"); %! in_i16 = randi ([-32768 32767], 5, 5, 2, 3, "int16"); %! in_u8_d = im2double (in_u8); %! in_u16_d = im2double (in_u16); %! in_i16_d = im2double (in_i16); %! %! ## default values %! assert (imadjust (in_u8), im2uint8 (imadjust (in_u8_d))) %! assert (imadjust (in_u16), im2uint16 (imadjust (in_u16_d))) %! assert (imadjust (in_i16), im2int16 (imadjust (in_i16_d))) %! %! ## single adjustment for all planes %! args = {[.3; .7], [.1; .9], [1.5]}; %! assert (imadjust (in_u8, args{:}), im2uint8 (imadjust (in_u8_d, args{:}))) %! assert (imadjust (in_u16, args{:}), im2uint16 (imadjust (in_u16_d, args{:}))) %! assert (imadjust (in_i16, args{:}), im2int16 (imadjust (in_i16_d, args{:}))) %! %! ## single adjustment for all planes (mixed with some complement) %! args = {reshape([.2 .3 .25 .1 0 .1; .9 .7 .85 .9 1 .8], [2 2 3]), %! reshape([.1 .2 .05 .9 1 .3; .9 .85 .7 .1 0 .9], [2 2 3]), %! reshape([1 .75 1 1.2 1.5 2], [1 2 3])}; %! assert (imadjust (in_u8, args{:}), im2uint8 (imadjust (in_u8_d, args{:}))) %! assert (imadjust (in_u16, args{:}), im2uint16 (imadjust (in_u16_d, args{:}))) %! assert (imadjust (in_i16, args{:}), im2int16 (imadjust (in_i16_d, args{:}))) %! %! ## test use of [] as limit and negative %! args = {[], [.95; 0], 1.25}; %! assert (imadjust (in_u8, args{:}), im2uint8 (imadjust (in_u8_d, args{:}))) %! assert (imadjust (in_u16, args{:}), im2uint16 (imadjust (in_u16_d, args{:}))) %! assert (imadjust (in_i16, args{:}), im2int16 (imadjust (in_i16_d, args{:}))) image-2.6.2/inst/PaxHeaders.16724/stdfilt.m0000644000000000000000000000013213201323063015140 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/stdfilt.m0000644000175000017500000000536213201323063017706 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{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.6.2/inst/PaxHeaders.16724/imtransform.m0000644000000000000000000000013213201323063016030 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imtransform.m0000644000175000017500000003466613201323063020607 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{IM_OUT} =} imtransform (@var{IM_IN}, @var{T}) ## @deftypefnx {Function File} {@var{IM_OUT} =} imtransform (@var{IM_IN}, @var{T}, @var{interp}) ## @deftypefnx {Function File} {@var{IM_OUT} =} imtransform (@dots{}, @var{prop}, @var{val}) ## @deftypefnx {Function File} {[@var{IM_OUT}, @var{xdata}, @var{ydata}] =} imtransform (@dots{}) ## Transform image. ## ## Given an image @var{IM_IN}, return an image @var{IM_OUT} ## resulting from the forward transform defined in the transformation ## structure @var{T}. An additional input argument @var{interp}, ## 'bicubic', 'bilinear' (default) or 'nearest', ## specifies the interpolation method to be used. Finally, the ## transform can be tuned using @var{prop}/@var{val} pairs. The ## following properties @var{prop} are supported: ## ## @table @asis ## @item "udata" ## Specifies the input space horizontal limits. @var{val} must be a two ## elements vector [minval maxval]. Default: [1 columns(@var{IM_IN})] ## ## @item "vdata" ## Specifies the input space vertical limits. @var{val} must be a two ## elements vector [minval maxval]. Default: [1 rows(@var{IM_IN})] ## ## @item "xdata" ## Specifies the required output space horizontal limits. @var{val} 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. @var{val} must ## be a two elements vector [minval maxval]. Default: estimated using ## udata, vdata and findbounds function. ## ## @item "xyscale" ## Specifies the size of pixels in the output space. 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 width and height of the output pixels. The default is ## to use the width and height of input pixels provided ## that it does not lead to a too large output image. ## ## @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 is possible, e.g. when ## coordinates 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 = zeros (1, imdepth); 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 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)) nx = columns (im); ny = rows (im); xyscale = [(diff (udata) / (nx - 1)), ... (diff (vdata) / (ny - 1))]; endif xscale = xyscale(1); yscale = xyscale(2); xsize = ceil (diff (xdata) / xscale) + 1; ysize = ceil (diff (ydata) / yscale) + 1; ## xyscale takes precedence: recompute x/ydata considering roundoff errors xdata(2) = xdata(1) + (xsize - 1) * xscale; ydata(2) = ydata(1) + (ysize - 1) * 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 != 0) 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", "xdata", [1 800], "ydata", [1 2000]); %! 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] = imtransform (im, T); %! nu = columns(im); %! nv = rows(im); %! nx = xdata(2); %! diag = sqrt (nu^2 + nv^2); %! ang = atan (nv / nu); %! assert (nx, diag * abs (cos (theta - ang)), %! diag * 1 / size (im2, 2)) ## Test default fillvalues %!test %! im = rand (2); %! tmat = [eye(2); 0 0]; %! T = maketform ("affine", tmat); %! im2 = imtransform (im, T, "xdata", [1 3]); %! assert (im2(:,3), zeros (2,1)) ## Test image size when forcing x/ydata %!test %! im = rand (2); %! tmat = [eye(2); 0 0]; %! T = maketform ('affine', tmat); %! im2 = imtransform (im, T, "xdata", [1 3]); %! assert (size (im2), [2 3]) ## Test image size when forcing xyscale %!test %! im = rand (2); %! tmat = [eye(2); 0 0]; %! T = maketform ('affine', tmat); %! im2 = imtransform (im, T, "xyscale", [0.5 0.5]); %! assert (size (im2), [3 3]) image-2.6.2/inst/PaxHeaders.16724/rgb2gray.m0000644000000000000000000000013213201323063015206 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/rgb2gray.m0000644000175000017500000000461213201323063017751 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.6.2/inst/PaxHeaders.16724/bwboundaries.m0000644000000000000000000000012613201323063016156 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bwboundaries.m0000644000175000017500000000733513201323063020723 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.6.2/inst/PaxHeaders.16724/analyze75read.m0000644000000000000000000000013213201323063016142 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/analyze75read.m0000644000175000017500000000502313201323063020702 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.6.2/inst/PaxHeaders.16724/lab2double.m0000644000000000000000000000013213201323063015502 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/lab2double.m0000644000175000017500000000773013201323063020251 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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} {} lab2double (@var{lab}) ## Convert L*a*b* data to double precision. ## ## @var{lab} must be a L*a*b* image or colormap, i.e., its dimensions ## must be MxNx3xK or Mx3. Its type must be double, single, uint16, ## or uint8. ## ## When converted to double, L* values range from 0 to 100, while a* and ## b* range from -128 to 127. When converting from uint16, the upper limit ## is 65280 (higher values will be converted above the range). ## ## @seealso{lab2double, lab2rgb, lab2single, lab2uint8, lab2uin16, lab2xyz} ## @end deftypefn function [lab] = lab2double (lab) if (nargin () != 1) print_usage (); endif lab = lab2cls (lab, "double"); endfunction ## Instead of testing the lab2double function here, we test the ## conversion from double type. The actual tests for lab2double, ## are spread all other lab2* functions. This makes the tests ## simpler. %!test %! l_max_f = 100 + (25500 / 65280); %! ab_max_f = 127 + (255 / 256); %! cm = [ %! -Inf %! Inf %! NaN %! l_max_f %! ab_max_f %! -200 %! -129 %! -128 %! -128+(255/65280)*(0.499999) %! -128+(255/65280)*(0.500001) # should be 0.5, but float rounding error %! -128+(255/65280)*(0.500002) %! -127 %! -1 %! 0 %! (100/65280)*(0.499999) %! (100/65280)*(0.51) %! (100/65280)*(0.500001) %! 1 %! 99 %! 100 %! 101 %! 126 %! 127 %! 128 %! 254 %! 255 %! 256 %! 257]; %! cm = repmat (cm, [1 3]); %! im2d = reshape (cm, [7 4 3]); %! imnd = permute (im2d, [1 4 3 2]); %! %! cm_uint8 = uint8 ([ %! 0 0 0 %! 255 255 255 %! 255 255 255 %! 255 228 228 %! 255 255 255 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 1 1 %! 0 127 127 %! 0 128 128 %! 0 128 128 %! 0 128 128 %! 0 128 128 %! 3 129 129 %! 252 227 227 %! 255 228 228 %! 255 229 229 %! 255 254 254 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255 %! 255 255 255]); %! %! assert (lab2uint8 (cm), cm_uint8) %! im2d_uint8 = reshape (cm_uint8, [7 4 3]); %! assert (lab2uint8 (im2d), im2d_uint8) %! assert (lab2uint8 (imnd), permute (im2d_uint8, [1 4 3 2])) %! %! cm_uint16 = uint16 ([ %! 0 0 0 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 58468 58468 %! 65535 65535 65535 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 0 0 %! 0 1 1 %! 0 1 1 %! 0 256 256 %! 0 32512 32512 %! 0 32768 32768 %! 0 32768 32768 %! 1 32768 32768 %! 1 32768 32768 %! 653 33024 33024 %! 64627 58112 58112 %! 65280 58368 58368 %! 65535 58624 58624 %! 65535 65024 65024 %! 65535 65280 65280 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535 %! 65535 65535 65535]); %! %! assert (lab2uint16 (cm), cm_uint16) %! im2d_uint16 = reshape (cm_uint16, [7 4 3]); %! assert (lab2uint16 (im2d), im2d_uint16) %! assert (lab2uint16 (imnd), permute (im2d_uint16, [1 4 3 2])) %! %! assert (lab2single (cm), single (cm)) %! assert (lab2single (im2d), single (im2d)) %! assert (lab2single (imnd), single (imnd)) image-2.6.2/inst/PaxHeaders.16724/bestblk.m0000644000000000000000000000013213201323063015115 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/bestblk.m0000644000175000017500000000654313201323063017665 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.6.2/inst/PaxHeaders.16724/impixel.m0000644000000000000000000000013213201323063015136 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/impixel.m0000644000175000017500000001501013201323063017673 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.6.2/inst/PaxHeaders.16724/imperspectivewarp.m0000644000000000000000000000013213201323063017240 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/imperspectivewarp.m0000644000175000017500000001272013201323063022002 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.6.2/inst/PaxHeaders.16724/makelut.m0000644000000000000000000000013213201323063015131 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/makelut.m0000644000175000017500000000525613201323063017701 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.6.2/inst/PaxHeaders.16724/private0000644000000000000000000000013213201323063014706 xustar0030 mtime=1510319667.147947612 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/inst/private/0000755000175000017500000000000013201323063017523 5ustar00carandraugcarandraug00000000000000image-2.6.2/inst/private/PaxHeaders.16724/interp_method.m0000644000000000000000000000013213201323063020002 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/interp_method.m0000644000175000017500000000254713201323063022552 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.6.2/inst/private/PaxHeaders.16724/colorspace_conversion_revert.m0000644000000000000000000000013213201323063023127 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/colorspace_conversion_revert.m0000644000175000017500000000275113201323063025674 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 ## . ## Private function for functions that convert between color spaces, i.e., ## rgb2xyz, xyz2rgb, xyz2lab, lab2xyz, rgb2lab and lab2rgb. This reverts ## a colormap type into the same shape and class as it was in the input. ## (But setting the keep_class flag to 1 tells this function to not change ## the class back.) The other flags are meant to come from complementary ## private function colorspace_conversion_input_check() ## ## adapted by: Hartmut Gimpel, 2015 function rv = colorspace_conversion_revert (rv, cls, sz, is_im, is_nd, is_int, keep_class) if (is_im) if (is_nd) rv = reshape (rv, [sz(1:2) sz(4) sz(3)]); rv = permute (rv, [1 2 4 3]); else rv = reshape (rv, sz); endif endif if (is_int && ~keep_class) rv *= intmax (cls); endif endfunction image-2.6.2/inst/private/PaxHeaders.16724/colorspace_conversion_input_check.m0000644000000000000000000000013213201323063024114 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/colorspace_conversion_input_check.m0000644000175000017500000000610413201323063026655 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 ## . ## Private function for functions that convert between color spaces, i.e., ## rgb2xyz, xyz2rgb, xyz2lab, lab2xyz, rgb2lab and lab2rgb. All of these ## functions need to handle input in the same way. The returned flags ## are meant to be handled by the complementary private function ## colorspace_conversion_revert() ## Setting the only_foats flag to 1 tells this function to only accept single ## and double input types, otherwise it will also accept uint8 and uint16 ## input values. ## ## adapted by: Hartmut Gimpel, 2015 function [in_arg, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check (func, arg_name, in_arg, only_floats) cls = class (in_arg); sz = size (in_arg); ## If we have an image convert it into a color map. if (! iscolormap (in_arg)) if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"}))) error ("%s: %s of invalid data type '%s'", func, arg_name, cls); elseif (only_floats && ! any (strcmp (cls, {"single", "double"}))) error ("%s: %s of invalid data type '%s'", func, arg_name, cls); elseif (size (in_arg, 3) != 3 && !(size (in_arg) == [1, 3] || size (in_arg) == [3, 1])) error ("%s: %s must be a colormap or %s image", func, arg_name, arg_name); elseif (! isreal (in_arg) || ! isnumeric (in_arg)) error ("%s: %s must be numeric and real", func, arg_name); endif is_im = true; ## Some floating point values (like R, G, B values) should be in the [0 1] range, ## otherwise they don't make any sense. We accept those values ## anyways because we must return something for Matlab compatibility. ## User case is when a function returns an RGB image just slightly outside ## the range due to floating point rounding errors. ## Allow for ND images, i.e., multiple images on the 4th dimension. nd = ndims (in_arg); if (nd == 2 || nd == 3) is_nd = false; elseif (nd == 4) is_nd = true; in_arg = permute (in_arg, [1 2 4 3]); elseif (nd > 4) error ("%s: invalid %s with more than 4 dimensions", func, arg_name); endif in_arg = reshape (in_arg, [numel(in_arg)/3 3]); else is_im = false; is_nd = false; endif ## Convert to floating point (remember to leave class single alone) if (isinteger (in_arg)) in_arg = double (in_arg) / double (intmax (cls)); is_int = true; else is_int = false; endif endfunction image-2.6.2/inst/private/PaxHeaders.16724/is_float_image.m0000644000000000000000000000013213201323063020103 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/is_float_image.m0000644000175000017500000000164413201323063022650 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_float_image (img) bool = min (img(:)) >= 0 && max (img(:)) <= 1; endfunction image-2.6.2/inst/private/PaxHeaders.16724/prepare_strel.m0000644000000000000000000000013213201323063020010 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/prepare_strel.m0000644000175000017500000000272313201323063022554 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.6.2/inst/private/PaxHeaders.16724/handle_colorspec.m0000644000000000000000000000013213201323063020445 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/handle_colorspec.m0000644000175000017500000000274413201323063023214 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.6.2/inst/private/PaxHeaders.16724/lab2cls.m0000644000000000000000000000013213201323063016463 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/lab2cls.m0000644000175000017500000000636213201323063021232 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2016 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 . ## Internal function that does all the work of lab2uint8, lab2uin16, ## and lab2double functions. function [lab] = lab2cls (lab, out_cls) nd = ndims (lab); sz = size (lab); ## We want to minimize operations on the input but we also want to ## have the same code for colormap and ND images. So we reshape into ## a colormap with other images on the 3rd dimension. The actual ## conversion is broadcasted, and then we reshape back at the end. was_image = false; if (nd == 2 && sz(2) == 3) # colormap shape ## Do nothing, we already have it shaped like we want. elseif (nd == 3 && sz(3) == 3) # MxNx3 image was_image = true; lab = reshape (lab, [sz(1)*sz(2) 3]); elseif (nd == 4 && sz(3) == 3) # MxNx3xK image was_image = true; lab = reshape (lab, [sz(1)*sz(2) 3 sz(4)]); else error ("lab2%s: LAB must be Mx3, MxNx3, or MxNx3xK size", out_cls); endif in_cls = class (lab); switch (out_cls) case {"double", "single"} lab = cast (lab, out_cls); switch (in_cls) case "uint8" lab(:, 1, :) .*= (100 / 255); lab(:, [2 3], :) .-= 128; case "uint16" lab(:, 1, :) .*= (100 / 65280); lab(:, [2 3], :) .*= (255 / 65280); lab(:, [2 3], :) .-= 128; case {"double", "single"} ## Do nothing, we already casted to the other type. otherwise error ("lab2%s: invalid class '%s' for LAB", out_cls, in_cls); endswitch case "uint8" switch (in_cls) case {"double", "single"} lab(:, 1, :) .*= (255 / 100); lab(:, [2 3], :) .+= 128; lab(isnan (lab)) = 255; # for Matlab compatibility lab = uint8 (lab); case "uint16" lab /= 256; lab = uint8 (lab); case "uint8" ## Do nothing. otherwise error ("lab2uint8: invalid class '%s' for LAB", in_cls); endswitch case "uint16" switch (in_cls) case {"double", "single"} lab(:, 1, :) .*= (65280 / 100); lab(:, [2 3], :) .+= 128; lab(:, [2 3], :) .*= (65280 / 255); lab(isnan (lab)) = 65535; # for Matlab compatibility lab = uint16 (lab); case "uint8" lab = uint16 (lab) * 256; case "uint16" ## Do nothing. otherwise error ("lab2uint16: invalid class '%s' for LAB", in_cls); endswitch otherwise error ("lab2%s: non-supported conversion (internal error)", out_cls); endswitch if (was_image) lab = reshape (lab, sz); endif endfunction image-2.6.2/inst/private/PaxHeaders.16724/ispart.m0000644000000000000000000000013213201323063016443 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/ispart.m0000644000175000017500000000211613201323063021203 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.6.2/inst/private/PaxHeaders.16724/imarithmetics.m0000644000000000000000000000013213201323063020003 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/imarithmetics.m0000644000175000017500000000716713201323063022556 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.6.2/inst/private/PaxHeaders.16724/isimage.m0000644000000000000000000000013213201323063016557 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/isimage.m0000644000175000017500000000175713201323063021331 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.6.2/inst/private/PaxHeaders.16724/analyze75filename.m0000644000000000000000000000013213201323063020461 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/analyze75filename.m0000644000175000017500000000325013201323063023221 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.6.2/inst/private/PaxHeaders.16724/im2col_check.m0000644000000000000000000000013213201323063017463 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/private/im2col_check.m0000644000175000017500000000373113201323063022227 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.6.2/inst/private/PaxHeaders.16724/pad_for_sliding_filter.m0000644000000000000000000000013213201323063021631 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/pad_for_sliding_filter.m0000644000175000017500000000316313201323063024374 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.6.2/inst/private/PaxHeaders.16724/ycbcrfunc.m0000644000000000000000000000013213201323063017117 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/ycbcrfunc.m0000644000175000017500000000746513201323063021673 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.6.2/inst/private/PaxHeaders.16724/istform.m0000644000000000000000000000013213201323063016624 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/istform.m0000644000175000017500000000241213201323063021363 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.6.2/inst/private/PaxHeaders.16724/iscolormap.m0000644000000000000000000000013213201323063017311 xustar0030 mtime=1510319667.147947612 30 atime=1510319667.147947612 30 ctime=1510319668.283933657 image-2.6.2/inst/private/iscolormap.m0000644000175000017500000000272113201323063022053 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2012-2015 Carnë Draug ## ## This file is part of Octave. ## ## Octave 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. ## ## Octave 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 ## . ## FIXME: remove once the image package is dependent on Octave 4.2 or ## later. We need a version of iscolormap that accepts values ## outside [0 1] for colourspace conversion, see patch #8713. ## So we copied this from Octave core (cset 31b4b614ed55). ## Author: Carnë Draug function retval = iscolormap (cmap) if (nargin != 1) print_usage; endif retval = (isnumeric (cmap) && isreal (cmap) && ndims (cmap) == 2 && columns (cmap) == 3 && isfloat (cmap)); endfunction %!assert (iscolormap (jet (64))) %!assert (iscolormap ({0 1 0}), false) %!assert (iscolormap ([0 1i 0]), false) %!assert (iscolormap (ones (3,3,3)), false) %!assert (iscolormap (ones (3,4)), false) image-2.6.2/inst/PaxHeaders.16724/imlincomb.m0000644000000000000000000000013213201323063015440 xustar0030 mtime=1510319667.119947955 30 atime=1510319667.119947955 30 ctime=1510319668.283933657 image-2.6.2/inst/imlincomb.m0000644000175000017500000000747713201323063020217 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.6.2/inst/PaxHeaders.16724/xyz2lab.m0000644000000000000000000000013213201323063015062 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/inst/xyz2lab.m0000644000175000017500000001152613201323063017627 0ustar00carandraugcarandraug00000000000000## 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{lab} =} xyz2lab (@var{xyz}) ## @deftypefnx {Function File} {@var{lab_map} =} xyz2lab (@var{xyz_map}) ## Transform a colormap or image from CIE XYZ to CIE L*a*b* color space. ## ## A color in the CIE XYZ color space consists of three values X, Y and Z. ## Those values are designed to be colorimetric, meaning that their values ## do not depend on the display device hardware. ## ## A color in the CIE L*a*b* (or CIE Lab) space consists of lightness L* and ## two color-opponent dimensions a* and b*. The whitepoint is taken as D65. ## The CIE L*a*b* colorspace is also a colorimetric colorspace. It is designed ## to incorporate the human perception of color differences. ## ## Input values of class single and double are accepted. ## The shape and the class of the input are conserved. ## ## The return values of L* are normally in the inteval [0, 100] ## and the values of a* and b* in the interval [-127, 127] ## ## @seealso{lab2xyz, rgb2lab, rgb2hsv, rgb2ind, rgb2ntsc} ## @end deftypefn ## Author: Hartmut Gimpel ## algorithm taken from the following book: ## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) function lab = xyz2lab (xyz) if (nargin != 1) print_usage (); endif [xyz, cls, sz, is_im, is_nd, is_int] ... = colorspace_conversion_input_check ("xyz2lab", "XYZ", xyz, 1); # only accept single and double inputs because valid xyz values can be >1 ## normalize with the whitepoint D65 ## (reference: en.wikipedia.org/wiki/Illuminant_D65) D65 = [0.95047, 1, 1.08883]; xyz_D65 = xyz ./ D65; # Matlab truncates to D65_Matlab = [0.9504, 1.0000, 1.0888]; ## transformation xyz -> xyz' epsilon = (6/29)^3; kappa = 1/116 * (29/3)^3; xyz_prime = xyz_D65; mask = xyz_D65 <= epsilon; xyz_prime(mask) = kappa .* xyz_D65(mask) + 16/116; xyz_prime(! mask) = xyz_D65(! mask) .^(1/3); x_prime = xyz_prime(:,1); y_prime = xyz_prime(:,2); z_prime = xyz_prime(:,3); ## transformation xyz' -> lab L = 116 .* y_prime - 16; a = 500 .* (x_prime - y_prime); b = 200 .* (y_prime - z_prime); lab = [L, a, b]; # always return values of type double for Matlab compatibility (exception: type single) lab = colorspace_conversion_revert (lab, cls, sz, is_im, is_nd, is_int, 1); endfunction ## Test pure colors, gray and some other colors ## (This set of test values is taken from the book by Burger.) %!assert (xyz2lab ([0, 0, 0]), [0 0 0], 5e-2) %!assert (xyz2lab ([0.4125, 0.2127, 0.0193]), [53.24, 80.09, 67.20], 5e-2) %!assert (xyz2lab ([0.7700, 0.9278, 0.1385]), [97.14, -21.55, 94.48], 5e-2) %!assert (xyz2lab ([0.3576, 0.7152, 0.1192]), [87.74, -86.18, 83.18], 5e-2) %!assert (xyz2lab ([0.5380, 0.7873, 1.0694]), [91.11, -48.09, -14.13], 5e-2) %!assert (xyz2lab ([0.1804, 0.07217, 0.9502]), [32.30, 79.19, -107.86], 5e-2) %!assert (xyz2lab ([0.5929, 0.28484, 0.9696]), [60.32, 98.24, -60.83], 5e-2) %!assert (xyz2lab ([0.9505, 1.0000, 1.0888]), [100, 0.00, 0.00], 5e-2) %!assert (xyz2lab ([0.2034, 0.2140, 0.2330]), [53.39, 0.00, 0.00], 5e-2) %!assert (xyz2lab ([0.2155, 0.1111, 0.0101]), [39.77, 64.51, 54.13], 5e-2) %!assert (xyz2lab ([0.0883, 0.0455, 0.0041]), [25.42, 47.91, 37.91], 5e-2) %!assert (xyz2lab ([0.02094, 0.0108, 0.00098]), [9.66, 29.68, 15.24], 5e-2) %!assert (xyz2lab ([0.5276, 0.3812, 0.2482]), [68.11, 48.39, 22.83], 5e-2) ## Test tolarant input checking on floats %!assert (xyz2lab ([1.5 1 1]), [100, 82.15, 5.60], 5e-2) %! xyz_map = rand (64, 3); %! assert (lab2xyz (xyz2lab (xyz_map)), xyz_map, 1e-5); %!test %! xyz_img = rand (64, 64, 3); %! assert (lab2xyz (xyz2lab (xyz_img)), xyz_img, 1e-5); ## support sparse input (the only useful xyz value with zeros is black) %!assert (xyz2lab (sparse ([0 0 0])), [0 0 0], 5e-2) ## conserve class of single input %!assert (class (xyz2lab (single([0.5 0.5 0.5]))), 'single') ## Test input validation %!error xyz2lab () %!error xyz2lab (1,2) %!error xyz2lab ({1}) %!error xyz2lab (ones (2,2)) ## Test ND input %!test %! xyz = rand (16, 16, 3, 5); %! lab = zeros (size (xyz)); %! for i = 1:5 %! lab(:,:,:,i) = xyz2lab (xyz(:,:,:,i)); %! endfor %! assert (xyz2lab (xyz), lab) image-2.6.2/inst/PaxHeaders.16724/imtophat.m0000644000000000000000000000013213201323063015314 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imtophat.m0000644000175000017500000001530713201323063020062 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.6.2/inst/PaxHeaders.16724/analyze75info.m0000644000000000000000000000013213201323063016162 xustar0030 mtime=1510319667.087948349 30 atime=1510319667.087948349 30 ctime=1510319668.283933657 image-2.6.2/inst/analyze75info.m0000644000175000017500000001441513201323063020727 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.6.2/inst/PaxHeaders.16724/labelmatrix.m0000644000000000000000000000013213201323063015773 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/labelmatrix.m0000644000175000017500000000411513201323063020534 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.6.2/inst/PaxHeaders.16724/imclearborder.m0000644000000000000000000000013213201323063016301 xustar0030 mtime=1510319667.111948054 30 atime=1510319667.111948054 30 ctime=1510319668.283933657 image-2.6.2/inst/imclearborder.m0000644000175000017500000001150713201323063021045 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.6.2/inst/PaxHeaders.16724/maketform.m0000644000000000000000000000013213201323063015454 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/maketform.m0000644000175000017500000001571413201323063020224 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 a transform structure @var{T} to be used for spatial ## transformations between an input space and an output space. ## ## The fields of the transform structure are: ## ## @table @asis ## @item @qcode{"ndims_in"}, @qcode{"ndims_out"}: the number of ## dimensions of the input and output space. ## ## @item @qcode{"forward_fcn"}, @qcode{"inverse_fcn"}: the callback ## functions that are called for forward (input to output) and inverse ## transform. ## ## @item @qcode{"tdata"}: an inverse transform matrix or a structure ## containing forward and inverse transform matrices. ## @end table ## ## The content of each field depends on the requested transform type ## @var{ttype}: ## ## @table @asis ## @item "projective" ## A ndims_in = ndims_out = N projective transform structure ## is returned. ## If a second input argument @var{tmat} is provided, it must be a ## (N+1)-by-(N+1) inverse transformation matrix. The (N+1)th column must ## contain projection coefficients. As an example a two ## dimensional inverse transform from [x y] coordinates to [u v] coordinates ## is represented by an inverse 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 quadrilateral (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 ## ndims_in = ndims_out = N affine transformation structure is ## returned. ## If a second input argument @var{tmat} is provided, it 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 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 ## @code{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.6.2/inst/PaxHeaders.16724/mmgradm.m0000644000000000000000000000013013201323063015111 xustar0029 mtime=1510319667.13994771 29 atime=1510319667.13994771 30 ctime=1510319668.283933657 image-2.6.2/inst/mmgradm.m0000644000175000017500000000532513201323063017660 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.6.2/inst/PaxHeaders.16724/label2rgb.m0000644000000000000000000000013213201323063015323 xustar0030 mtime=1510319667.135947758 30 atime=1510319667.135947758 30 ctime=1510319668.283933657 image-2.6.2/inst/label2rgb.m0000644000175000017500000001430513201323063020066 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.6.2/inst/PaxHeaders.16724/padarray.m0000644000000000000000000000013213201323063015272 xustar0030 mtime=1510319667.143947661 30 atime=1510319667.143947661 30 ctime=1510319668.283933657 image-2.6.2/inst/padarray.m0000644000175000017500000006132013201323063020034 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.6.2/inst/PaxHeaders.16724/imremap.m0000644000000000000000000000013213201323063015121 xustar0030 mtime=1510319667.123947906 30 atime=1510319667.123947906 30 ctime=1510319668.283933657 image-2.6.2/inst/imremap.m0000644000175000017500000001643613201323063017673 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 sz = size (im); n_planes = prod (sz(3:end)); for i = 1:n_planes warped(:,:,i) = grayinterp (im(:,:,i), XI, YI, interp, 0); endfor 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.6.2/inst/PaxHeaders.16724/imsubtract.m0000644000000000000000000000013213201323063015644 xustar0030 mtime=1510319667.127947858 30 atime=1510319667.127947858 30 ctime=1510319668.283933657 image-2.6.2/inst/imsubtract.m0000644000175000017500000001022113201323063020400 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 ## input need to have same class %!error imsubtract (uint8 ([23 250]), uint16 ([23 250])); ## signed integers kinda work (not in matlab) %!warning imsubtract (uint8 ([23 250]), uint8 ([24 255]), "int8"); %!test %! warning ("off", "all"); %! assert (imsubtract (uint8 ([23 250]), uint8 ([24 255]), "int8"), %! int8 ([-1 0])) image-2.6.2/inst/PaxHeaders.16724/bwareafilt.m0000644000000000000000000000012613201323063015612 xustar0028 mtime=1510319667.0919483 28 atime=1510319667.0919483 30 ctime=1510319668.283933657 image-2.6.2/inst/bwareafilt.m0000644000175000017500000002451213201323063020353 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.6.2/inst/PaxHeaders.16724/std2.m0000644000000000000000000000013213201323063014343 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/std2.m0000644000175000017500000000206313201323063017104 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.6.2/inst/PaxHeaders.16724/rho_filter.m0000644000000000000000000000013213201323063015624 xustar0030 mtime=1510319667.155947513 30 atime=1510319667.155947513 30 ctime=1510319668.283933657 image-2.6.2/inst/rho_filter.m0000644000175000017500000001312513201323063020366 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.6.2/inst/PaxHeaders.16724/isbw.m0000644000000000000000000000013213201323063014433 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/isbw.m0000644000175000017500000000674313201323063017205 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011, 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} {} 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, real array of size @nospell{MxNx1xK}, and, ## depending on the value of @var{logic}: ## ## @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 ## ## @emph{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; a grayscale image may have ## values outside the range [0 1]. 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 %!shared img %! img = round (rand (10)); %!assert (isbw (img, "non-logical"), true); %!assert (isbw (img, "logical"), false); %!assert (isbw (logical (img), "logical"), true); %!assert (isbw (logical (img), "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 %!test %! img(1, 1) = 2; %! assert (isbw (img, "non-logical"), false); %!test %! a( 1, 1) = 1; %! a(50, 50) = 2; %! assert (isbw (a, "non-logical"), false); %!assert (isbw (rand (5, 5, 1, 4) > 0.5), true) %!assert (isbw (rand (5, 5, 3, 4) > 0.5), false) %!assert (isbw (rand (5, 5, 3) > 0.5), false) %!assert (isbw (rand (5, 5, 1, 3, 4) > 0.5), false) %!assert (isbw (randi ([0 1], 5, 5, 1, 4), "non-logical"), true) %!assert (isbw (randi ([0 1], 5, 5, 3, 4), "non-logical"), false) %!assert (isbw (randi ([0 1], 5, 5, 3), "non-logical"), false) %!assert (isbw (randi ([0 1], 5, 5, 1, 3, 4), "non-logical"), false) %!assert (isbw (single ([0 0 1]), "non-logical"), true) %!assert (isbw ([0 NaN 1], "non-logical"), false) image-2.6.2/inst/PaxHeaders.16724/im2col.m0000644000000000000000000000013213201323063014654 xustar0030 mtime=1510319667.107948103 30 atime=1510319667.107948103 30 ctime=1510319668.283933657 image-2.6.2/inst/im2col.m0000644000175000017500000002137213201323063017421 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"); 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) ## We need to use bsxfun here because of ## https://savannah.gnu.org/bugs/?47085 ind = bsxfun (@plus, 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), [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])); ## Corner case for Matlab compatibility -- bug #46774 %!assert (im2col (1:8, [2 1]), zeros (2, 0)) image-2.6.2/inst/PaxHeaders.16724/isgray.m0000644000000000000000000000013213201323063014765 xustar0030 mtime=1510319667.131947808 30 atime=1510319667.131947808 30 ctime=1510319668.283933657 image-2.6.2/inst/isgray.m0000644000175000017500000000554113201323063017532 0ustar00carandraugcarandraug00000000000000## Copyright (C) 2000 Kai Habel ## Copyright (C) 2011, 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} {} isgray (@var{img}) ## Return true if @var{img} is a grayscale image. ## ## A variable can be considered a grayscale image if it is a non-sparse, ## real array of size @nospell{MxNx1xK}, and: ## ## @itemize @bullet ## @item of floating point class with values in the [0 1] range or NaN; ## @item of class uint8, uint16, or int16. ## @end itemize ## ## @emph{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; a grayscale image may have ## values outside the range [0 1]. 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) if (isfloat (img)) bool = ispart (@is_float_image, img); elseif (any (isa (img, {"uint8", "uint16", "int16"}))) bool = true; endif endif endfunction %!assert (isgray ([0 0 1; 1 0 1]), true) %!assert (isgray (zeros (3)), true) %!assert (isgray (ones (3)), true) %!test %! a = rand (10); %! assert (isgray (a), true); %! a(5, 5) = 2; %! assert (isgray (a), false); %!test %! a = uint8 (randi (255, 10)); %! assert (isgray (a), true); %! a = int8 (a); %! assert (isgray (a), false); %!test %! a = rand (10); %! a(50) = 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); %!assert (isgray (rand (5, "single")), true) ## While having some NaN is ok, having all NaN is not %!assert (isgray ([.1 .2 .3; .4 NaN .6; .7 .8 .9]), true) %!assert (isgray ([.1 .2 .3; NA NaN .6; .7 .8 .9]), true) %!assert (isgray ([.1 .2 .3; NA .5 .6; .7 .8 .9]), true) %!assert (isgray (NaN (5)), false) %!assert (isgray (NA (5)), false) image-2.6.2/inst/PaxHeaders.16724/fftconvn.m0000644000000000000000000000013213201323063015312 xustar0030 mtime=1510319667.099948201 30 atime=1510319667.099948201 30 ctime=1510319668.283933657 image-2.6.2/inst/fftconvn.m0000644000175000017500000001374313201323063020062 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.6.2/PaxHeaders.16724/octave-image.metainfo.xml0000644000000000000000000000013213201323063017220 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/octave-image.metainfo.xml0000644000175000017500000000302113201323063021754 0ustar00carandraugcarandraug00000000000000 octave-image www.octave.org-octave.desktop Image Image processing, feature extraction, transformations, morphological operations, filters, and more

Provides functions for processing images, such as feature extraction, image statistics, spatial and geometric transformations, morphological operations, linear filtering, and much more.

image processing feature extraction spatial transform geometric transform morphological operation linear filter convolution bwregion regionprops http://octave.sourceforge.net/image https://savannah.gnu.org/bugs/?func=additem&group=octave GPL-3.0+ Octave-Forge Community octave-maintainers@gnu.org FSFAP
image-2.6.2/PaxHeaders.16724/DESCRIPTION0000644000000000000000000000013213201323063014042 xustar0030 mtime=1510319667.079948446 30 atime=1510319667.079948446 30 ctime=1510319668.283933657 image-2.6.2/DESCRIPTION0000644000175000017500000000073413201323063016606 0ustar00carandraugcarandraug00000000000000Name: image Version: 2.6.2 Date: 2017-11-09 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+ Url: http://octave.sf.net image-2.6.2/PaxHeaders.16724/INDEX0000644000000000000000000000013213201323063013126 xustar0030 mtime=1510319667.079948446 30 atime=1510319667.079948446 30 ctime=1510319668.283933657 image-2.6.2/INDEX0000644000175000017500000000405413201323063015671 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 imfill imopen imreconstruct imregionalmax imregionalmin imtophat mmgradm @strel/getheight @strel/getneighbors @strel/getnhood @strel/getsequence @strel/isflat @strel/reflect @strel/strel @strel/translate watershed 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 impyramid imremap imresize imrotate imshear imtranslate maketform rotate_scale tformfwd tforminv Types and Type conversions grayslice graythresh im2bw im2double im2int16 im2single im2uint8 im2uint16 imcast imdither imquantize isbw isgray isind isrgb lab2double lab2rgb lab2single lab2uint16 lab2uint8 lab2xyz label2rgb mat2gray rgb2gray rgb2lab rgb2xyz xyz2lab xyz2rgb Utilities checkerboard edgetaper getrangefromclass imattributes imgetfile iptcheckconn iptcheckmap iptnum2ordinal otf2psf padarray phantom psf2otf image-2.6.2/PaxHeaders.16724/COPYING0000644000000000000000000000013213201323063013367 xustar0030 mtime=1510319667.079948446 30 atime=1510319667.079948446 30 ctime=1510319668.283933657 image-2.6.2/COPYING0000644000175000017500000010451313201323063016133 0ustar00carandraugcarandraug00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . image-2.6.2/PaxHeaders.16724/src0000644000000000000000000000013213201323064013047 xustar0030 mtime=1510319668.279933706 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/src/0000755000175000017500000000000013201323064015664 5ustar00carandraugcarandraug00000000000000image-2.6.2/src/PaxHeaders.16724/bwlabeln.cc0000644000000000000000000000013213201323063015220 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/bwlabeln.cc0000644000175000017500000006704013201323063017767 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 belongs to object number 1, 2 that\n\ the pixel belongs 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 belongs to object number 1, 2 that the pixel\n\ belongs to object number 2, etc.\n\ The total number of objects is @var{num}.\n\ \n\ Two pixels belong to the same object if they 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}, which 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.6.2/src/PaxHeaders.16724/graycomatrix.cc0000644000000000000000000000013213201323063016143 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/graycomatrix.cc0000644000175000017500000001207113201323063020704 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.numel(); dim(3) = th.numel(); 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.numel(); d_idx++) { int d_val = (int)d(d_idx); for (int th_idx = 0; th_idx < th.numel(); 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.6.2/src/PaxHeaders.16724/configure.ac0000644000000000000000000000013213201323063015411 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.295945794 30 ctime=1510319668.283933657 image-2.6.2/src/configure.ac0000644000175000017500000000766013201323063020162 0ustar00carandraugcarandraug00000000000000AC_PREREQ([2.67]) AC_INIT([Octave-Forge image package], [2.6.2]) AC_CONFIG_HEADERS([config.h]) AC_PROG_SED AC_PATH_PROG([OCTAVE], [octave]) if test -z "$OCTAVE"; then AC_MSG_ERROR([*** 'octave' not found.]) fi AC_PATH_PROG([MKOCTFILE], [mkoctfile]) if test -z "$MKOCTFILE"; then AC_MSG_ERROR([*** 'mkoctfile' not found.]) fi dnl CXX is the compiler including options such as -std=c++11. dnl CXXFLAGS are flags for CXX coming from the environment. dnl XTRA_CXXFLAGS are extra flags that we want to set ourselves. dnl We will not actually use CXX in the build, we only use mkoctfile dnl which picks up the dnl CXX environment variable and defaults to what dnl was used to build Octave. However, that may not be enough for our dnl C++11 dependency (Octave 4.0 did not require C++11) so we set CXX dnl ourselves, check if any extra flag was needed, and then use that dnl on MKOCTFILE. CXX=`${MKOCTFILE} -p CXX` image_save_CXX="$CXX" AC_PROG_CXX if test "x$ac_prog_cxx_stdcxx" != "xcxx11"; then AC_MSG_ERROR([** could not find a C++11 compiler]) fi CXX11_SWITCH=$(echo "$CXX" | $SED "s,^$image_save_CXX,,") MKOCTFILE="$MKOCTFILE $CXX11_SWITCH" CXX="$image_save_CXX" dnl Pick up any warnings as soon as possible. XTRA_CXXFLAGS="-Wall" AC_LANG(C++) ## Octave 4.2 moved functions that clashed with C functions into its own ## namespace while deprecated the old ones prefixed with "x". We want to ## be compatible with Octave 4.0 but we also want to avoid scaring the ## users with deprecated warnings. Remove this once we no longer support ## Octave 4.0.X image_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -I`$MKOCTFILE -p OCTINCLUDEDIR`" AC_CACHE_CHECK( [whether xmin is in the octave::math namespace], [octave_image_cv_xmin_in_octave_math_namespace], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([#include ], [octave::math::min (2.0, 3.0)])], [octave_image_cv_xmin_in_octave_math_namespace=yes], [octave_image_cv_xmin_in_octave_math_namespace=no])]) if test "$octave_image_cv_xmin_in_octave_math_namespace" = yes; then AC_DEFINE([HAVE_MIN_IN_OCTAVE_MATH_NAMESPACE], [1], [Define if octave::math::min exists as replacement to xmin.]) fi AC_CACHE_CHECK( [whether feval is in the octave namespace], [octave_image_cv_feval_in_octave_namespace], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([#include ], [octave::feval ("eye")])], [octave_image_cv_feval_in_octave_namespace=yes], [octave_image_cv_feval_in_octave_namespace=no])]) if test "$octave_image_cv_feval_in_octave_namespace" = yes; then AC_DEFINE([HAVE_FEVAL_IN_OCTAVE_NAMESPACE], [1], [Define if octave::feval exists as replacement to feval.]) fi CXXFLAGS="$image_save_CXXFLAGS" ## 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_WARN([ 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 ## Starting with Octave 4.2 (and some 4.1.X versions), the function ## im2double has been moved to Octave core. HAS_IM2DOUBLE=`$OCTAVE -qf --eval "printf ('%i', exist ('im2double'))"` if test "$HAS_IM2DOUBLE" == 0; then AC_CONFIG_FILES([im2double.m]) fi AC_SUBST([XTRA_CXXFLAGS]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT image-2.6.2/src/PaxHeaders.16724/bwconncomp.cc0000644000000000000000000000013213201323063015577 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/bwconncomp.cc0000644000175000017500000003426413201323063020350 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) ## PixelIdxList is a row vector, even when there's zero objects %!assert (bwconncomp (false (5)), struct ("ImageSize", [5 5], "NumObjects", 0, %! "PixelIdxList", {cell(1, 0)}, %! "Connectivity", 8)) */ // 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.6.2/src/PaxHeaders.16724/bwdist.cc0000644000000000000000000000013213201323063014726 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/bwdist.cc0000644000175000017500000005506513201323063017501 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 #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 (); std::vector xdist (numel); std::vector ydist (numel); FloatMatrix dist; if (method == "euclidean") { dist = calc_distances (euclidean, bw, xdist.data (), ydist.data ()); 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.data (), ydist.data ()); else if (method == "cityblock") dist = calc_distances (cityblock, bw, xdist.data (), ydist.data ()); else if (method == "quasi-euclidean") dist = calc_distances (quasi_euclidean, bw, xdist.data (), ydist.data ()); 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.data (), ydist.data ()); else retval(1) = calc_index (bw, xdist.data (), ydist.data ()); } 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.6.2/src/PaxHeaders.16724/__spatial_filtering__.cc0000644000000000000000000000013213201323063017726 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/__spatial_filtering__.cc0000644000175000017500000007330313201323063022474 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 * std::log2 (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.6.2/src/PaxHeaders.16724/connectivity.h0000644000000000000000000000013213201323063016012 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/connectivity.h0000644000175000017500000001412513201323063020555 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 // XXX We need to include this first so it works with Octave 4.0.0. #include #include #include #include #include #include // octave_Inf #include namespace octave { namespace image { class connectivity { public: connectivity () = default; //! Will throw if val is bad explicit connectivity (const octave_value& val); explicit connectivity (const boolNDArray& mask_arg); explicit 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; //! Return a logical mask of elements that are part of the padding. static boolNDArray padding_mask (const dim_vector& size, const dim_vector& padded_size); //! Set the padding elements to a specific value. template static void set_padding (const dim_vector& size, const dim_vector& padded_size, T& im, const P& val); 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); } template void octave::image::connectivity::set_padding (const dim_vector& size, const dim_vector& padded_size, T& im, const P& val) { P* im_v = im.fortran_vec (); const Array lengths = padding_lengths (size, padded_size); const octave_idx_type* lengths_v = lengths.fortran_vec (); const octave_idx_type* strides_v = size.to_jit (); const octave_idx_type row_stride = strides_v[0]; std::function fill; fill = [&] (const octave_idx_type dim) -> void { for (octave_idx_type i = 0; i < lengths_v[dim]; i++, im_v++) *im_v = val; if (dim == 0) im_v += row_stride; else for (octave_idx_type i = 0; i < strides_v[dim]; i++) fill (dim -1); for (octave_idx_type i = 0; i < lengths_v[dim]; i++, im_v++) *im_v = val; }; fill (im.ndims () -1); } #endif image-2.6.2/src/PaxHeaders.16724/aclocal.m40000644000000000000000000000013113201323063014762 xustar0029 mtime=1510319667.92793803 30 atime=1510319668.155935229 30 ctime=1510319668.283933657 image-2.6.2/src/aclocal.m40000644000175000017500000000127013201323063017523 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/std-gnu11.m4]) image-2.6.2/src/PaxHeaders.16724/config.h.in0000644000000000000000000000013213201323063015146 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/config.h.in0000644000175000017500000000031713201323063017707 0ustar00carandraugcarandraug00000000000000/* Define if octave::math::min exists as replacement to xmin. */ #undef HAVE_MIN_IN_OCTAVE_MATH_NAMESPACE /* Define if octave::feval exists as replacement to feval. */ #undef HAVE_FEVAL_IN_OCTAVE_NAMESPACE image-2.6.2/src/PaxHeaders.16724/im2double.m.in0000644000000000000000000000013213201323063015570 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/im2double.m.in0000644000175000017500000000551513201323063020336 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.6.2/src/PaxHeaders.16724/Makefile.in0000644000000000000000000000013213201323063015170 xustar0030 mtime=1510319667.159947464 30 atime=1510319667.159947464 30 ctime=1510319668.283933657 image-2.6.2/src/Makefile.in0000644000175000017500000000207013201323063017727 0ustar00carandraugcarandraug00000000000000FLAGGED_MKOCTFILE = @MKOCTFILE@ @XTRA_CXXFLAGS@ @CXXFLAGS@ ## 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 \ watershed.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 \ intlut.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 *.oct *.m octave-core octave-workspace *~ image-2.6.2/src/PaxHeaders.16724/union-find.h0000644000000000000000000000013213201323063015342 xustar0030 mtime=1510319667.175947267 30 atime=1510319667.175947267 30 ctime=1510319668.283933657 image-2.6.2/src/union-find.h0000644000175000017500000000460113201323063020103 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: explicit 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.6.2/src/PaxHeaders.16724/m40000644000000000000000000000013213201323063013366 xustar0030 mtime=1510319667.171947317 30 atime=1510319668.283933657 30 ctime=1510319668.283933657 image-2.6.2/src/m4/0000755000175000017500000000000013201323063016203 5ustar00carandraugcarandraug00000000000000image-2.6.2/src/m4/PaxHeaders.16724/std-gnu11.m40000644000000000000000000000013213201323063015430 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.295945794 30 ctime=1510319668.283933657 image-2.6.2/src/m4/std-gnu11.m40000644000175000017500000005762513201323063020207 0ustar00carandraugcarandraug00000000000000# Prefer GNU C11 and C++11 to earlier versions. -*- coding: utf-8 -*- # This implementation is taken from GNU Autoconf lib/autoconf/c.m4 # commit 017d5ddd82854911f0119691d91ea8a1438824d6 # dated Sun Apr 3 13:57:17 2016 -0700 # This implementation will be obsolete once we can assume Autoconf 2.70 # or later is installed everywhere a Gnulib program might be developed. # Copyright (C) 2001-2016 Free Software Foundation, Inc. # 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 . # Written by David MacKenzie, with help from # Akim Demaille, Paul Eggert, # François Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor, # Roland McGrath, Noah Friedman, david d zuhn, and many others. # AC_PROG_CC([COMPILER ...]) # -------------------------- # COMPILER ... is a space separated list of C compilers to search for. # This just gives the user an opportunity to specify an alternative # search list for the C compiler. AC_DEFUN_ONCE([AC_PROG_CC], [AC_LANG_PUSH(C)dnl AC_ARG_VAR([CC], [C compiler command])dnl AC_ARG_VAR([CFLAGS], [C compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl _AC_ARG_VAR_LIBS()dnl _AC_ARG_VAR_CPPFLAGS()dnl m4_ifval([$1], [AC_CHECK_TOOLS(CC, [$1])], [AC_CHECK_TOOL(CC, gcc) if test -z "$CC"; then dnl Here we want: dnl AC_CHECK_TOOL(CC, cc) dnl but without the check for a tool without the prefix. dnl Until the check is removed from there, copy the code: if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(CC, [${ac_tool_prefix}cc], [${ac_tool_prefix}cc]) fi fi if test -z "$CC"; then AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) fi if test -z "$CC"; then AC_CHECK_TOOLS(CC, cl.exe) fi if test -z "$CC"; then AC_CHECK_TOOL(CC, clang) fi ]) test -z "$CC" && AC_MSG_FAILURE([no acceptable C compiler found in \$PATH]) # Provide some information about the compiler. _AS_ECHO_LOG([checking for _AC_LANG compiler version]) set X $ac_compile ac_compiler=$[2] for ac_option in --version -v -V -qversion -version; do _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) done m4_expand_once([_AC_COMPILER_EXEEXT])[]dnl m4_expand_once([_AC_COMPILER_OBJEXT])[]dnl _AC_LANG_COMPILER_GNU if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi _AC_PROG_CC_G dnl dnl Set ac_prog_cc_stdc to the supported C version. dnl Also set the documented variable ac_cv_prog_cc_stdc; dnl its name was chosen when it was cached, but it is no longer cached. _AC_PROG_CC_C11([ac_prog_cc_stdc=c11 ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11], [_AC_PROG_CC_C99([ac_prog_cc_stdc=c99 ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99], [_AC_PROG_CC_C89([ac_prog_cc_stdc=c89 ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89], [ac_prog_cc_stdc=no ac_cv_prog_cc_stdc=no])])]) dnl AC_LANG_POP(C)dnl ])# AC_PROG_CC # AC_PROG_CXX([LIST-OF-COMPILERS]) # -------------------------------- # LIST-OF-COMPILERS is a space separated list of C++ compilers to search # for (if not specified, a default list is used). This just gives the # user an opportunity to specify an alternative search list for the C++ # compiler. # aCC HP-UX C++ compiler much better than `CC', so test before. # FCC Fujitsu C++ compiler # KCC KAI C++ compiler # RCC Rational C++ # xlC_r AIX C Set++ (with support for reentrant code) # xlC AIX C Set++ AC_DEFUN([AC_PROG_CXX], [AC_LANG_PUSH(C++)dnl AC_ARG_VAR([CXX], [C++ compiler command])dnl AC_ARG_VAR([CXXFLAGS], [C++ compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl _AC_ARG_VAR_LIBS()dnl _AC_ARG_VAR_CPPFLAGS()dnl _AC_ARG_VAR_PRECIOUS([CCC])dnl if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else AC_CHECK_TOOLS(CXX, [m4_default([$1], [g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++])], g++) fi fi # Provide some information about the compiler. _AS_ECHO_LOG([checking for _AC_LANG compiler version]) set X $ac_compile ac_compiler=$[2] for ac_option in --version -v -V -qversion; do _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD]) done m4_expand_once([_AC_COMPILER_EXEEXT])[]dnl m4_expand_once([_AC_COMPILER_OBJEXT])[]dnl _AC_LANG_COMPILER_GNU if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi _AC_PROG_CXX_G _AC_PROG_CXX_CXX11([ac_prog_cxx_stdcxx=cxx11 ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_cv_prog_cxx_cxx98=$ac_cv_prog_cxx_cxx11], [_AC_PROG_CXX_CXX98([ac_prog_cxx_stdcxx=cxx98 ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98], [ac_prog_cxx_stdcxx=no ac_cv_prog_cxx_stdcxx=no])]) AC_LANG_POP(C++)dnl ])# AC_PROG_CXX # _AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST, # ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE) # -------------------------------------------------------------- # Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99') # by trying to compile a program of TEST-PROLOGUE and TEST-BODY. If this fails, # try again with each compiler option in the space-separated OPTION-LIST; if one # helps, append it to CC. If eventually successful, run ACTION-IF-AVAILABLE, # else ACTION-IF-UNAVAILABLE. AC_DEFUN([_AC_C_STD_TRY], [AC_MSG_CHECKING([for $CC option to enable ]m4_translit($1, [c], [C])[ features]) AC_CACHE_VAL(ac_cv_prog_cc_$1, [ac_cv_prog_cc_$1=no ac_save_CC=$CC AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])]) for ac_arg in '' $4 do CC="$ac_save_CC $ac_arg" _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg]) test "x$ac_cv_prog_cc_$1" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ])# AC_CACHE_VAL ac_prog_cc_stdc_options= case "x$ac_cv_prog_cc_$1" in x) AC_MSG_RESULT([none needed]) ;; xno) AC_MSG_RESULT([unsupported]) ;; *) ac_prog_cc_stdc_options=" $ac_cv_prog_cc_$1" CC=$CC$ac_prog_cc_stdc_options AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;; esac AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6]) ])# _AC_C_STD_TRY # _AC_C_C99_TEST_HEADER # --------------------- # A C header suitable for testing for C99. AC_DEFUN([_AC_C_C99_TEST_HEADER], [[#include #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; }]])# _AC_C_C99_TEST_HEADER # _AC_C_C99_TEST_BODY # ------------------- # A C body suitable for testing for C99, assuming the corresponding header. AC_DEFUN([_AC_C_C99_TEST_BODY], [[ // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ]]) # _AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) # ---------------------------------------------------------------- # If the C compiler is not in ISO C99 mode by default, try to add an # option to output variable CC to make it so. This macro tries # various options that select ISO C99 on some system or another. It # considers the compiler to be in ISO C99 mode if it handles _Bool, # // comments, flexible array members, inline, long long int, mixed # code and declarations, named initialization of structs, restrict, # va_copy, varargs macros, variable declarations in for loops and # variable length arrays. AC_DEFUN([_AC_PROG_CC_C99], [_AC_C_STD_TRY([c99], [_AC_C_C99_TEST_HEADER], [_AC_C_C99_TEST_BODY], dnl Try dnl GCC -std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999) dnl IBM XL C -qlanglvl=extc1x (V12.1; does not pass C11 test) dnl IBM XL C -qlanglvl=extc99 dnl (pre-V12.1; unused restrictive mode: -qlanglvl=stdc99) dnl HP cc -AC99 dnl Intel ICC -std=c99, -c99 (deprecated) dnl IRIX -c99 dnl Solaris -D_STDC_C99= dnl cc's -xc99 option uses linker magic to define the external dnl symbol __xpg4 as if by "int __xpg4 = 1;", which enables C99 dnl behavior for C library functions. This is not wanted here, dnl because it means that a single module compiled with -xc99 dnl alters C runtime behavior for the entire program, not for dnl just the module. Instead, define the (private) symbol dnl _STDC_C99, which suppresses a bogus failure in . dnl The resulting compiler passes the test case here, and that's dnl good enough. For more, please see the thread starting at: dnl http://lists.gnu.org/archive/html/autoconf/2010-12/msg00059.html dnl Tru64 -c99 dnl with extended modes being tried first. [[-std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc1x -qlanglvl=extc99]], [$1], [$2])[]dnl ])# _AC_PROG_CC_C99 # _AC_PROG_CC_C11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) # ---------------------------------------------------------------- # If the C compiler is not in ISO C11 mode by default, try to add an # option to output variable CC to make it so. This macro tries # various options that select ISO C11 on some system or another. It # considers the compiler to be in ISO C11 mode if it handles _Alignas, # _Alignof, _Noreturn, _Static_assert, UTF-8 string literals, # duplicate typedefs, and anonymous structures and unions. AC_DEFUN([_AC_PROG_CC_C11], [_AC_C_STD_TRY([c11], [_AC_C_C99_TEST_HEADER[ // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ]], [_AC_C_C99_TEST_BODY[ v1.i = 2; v1.w.k = 5; _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); ]], dnl Try dnl GCC -std=gnu11 (unused restrictive mode: -std=c11) dnl with extended modes being tried first. dnl dnl Do not try -qlanglvl=extc1x, because IBM XL C V12.1 (the latest version as dnl of September 2012) does not pass the C11 test. For now, try extc1x when dnl compiling the C99 test instead, since it enables _Static_assert and dnl _Noreturn, which is a win. If -qlanglvl=extc11 or -qlanglvl=extc1x passes dnl the C11 test in some future version of IBM XL C, we'll add it here, dnl preferably extc11. [[-std=gnu11]], [$1], [$2])[]dnl ])# _AC_PROG_CC_C11 # AC_PROG_CC_C89 # -------------- # Do not use AU_ALIAS here and in AC_PROG_CC_C99 and AC_PROG_CC_STDC, # as that'd be incompatible with how Automake redefines AC_PROG_CC. See # . AU_DEFUN([AC_PROG_CC_C89], [AC_REQUIRE([AC_PROG_CC])], [$0 is obsolete; use AC_PROG_CC] ) # AC_PROG_CC_C99 # -------------- AU_DEFUN([AC_PROG_CC_C99], [AC_REQUIRE([AC_PROG_CC])], [$0 is obsolete; use AC_PROG_CC] ) # AC_PROG_CC_STDC # --------------- AU_DEFUN([AC_PROG_CC_STDC], [AC_REQUIRE([AC_PROG_CC])], [$0 is obsolete; use AC_PROG_CC] ) # AC_C_PROTOTYPES # --------------- # Check if the C compiler supports prototypes, included if it needs # options. AC_DEFUN([AC_C_PROTOTYPES], [AC_REQUIRE([AC_PROG_CC])dnl if test "$ac_prog_cc_stdc" != no; then AC_DEFINE(PROTOTYPES, 1, [Define to 1 if the C compiler supports function prototypes.]) AC_DEFINE(__PROTOTYPES, 1, [Define like PROTOTYPES; this can be used by system headers.]) fi ])# AC_C_PROTOTYPES # _AC_CXX_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST, # ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE) # ---------------------------------------------------------------- # Check whether the C++ compiler accepts features of STANDARD (e.g # `cxx98', `cxx11') by trying to compile a program of TEST-PROLOGUE # and TEST-BODY. If this fails, try again with each compiler option # in the space-separated OPTION-LIST; if one helps, append it to CXX. # If eventually successful, run ACTION-IF-AVAILABLE, else # ACTION-IF-UNAVAILABLE. AC_DEFUN([_AC_CXX_STD_TRY], [AC_MSG_CHECKING([for $CXX option to enable ]m4_translit(m4_translit($1, [x], [+]), [a-z], [A-Z])[ features]) AC_LANG_PUSH(C++)dnl AC_CACHE_VAL(ac_cv_prog_cxx_$1, [ac_cv_prog_cxx_$1=no ac_save_CXX=$CXX AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])]) for ac_arg in '' $4 do CXX="$ac_save_CXX $ac_arg" _AC_COMPILE_IFELSE([], [ac_cv_prog_cxx_$1=$ac_arg]) test "x$ac_cv_prog_cxx_$1" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX ])# AC_CACHE_VAL ac_prog_cxx_stdcxx_options= case "x$ac_cv_prog_cxx_$1" in x) AC_MSG_RESULT([none needed]) ;; xno) AC_MSG_RESULT([unsupported]) ;; *) ac_prog_cxx_stdcxx_options=" $ac_cv_prog_cxx_$1" CXX=$CXX$ac_prog_cxx_stdcxx_options AC_MSG_RESULT([$ac_cv_prog_cxx_$1]) ;; esac AC_LANG_POP(C++)dnl AS_IF([test "x$ac_cv_prog_cxx_$1" != xno], [$5], [$6]) ])# _AC_CXX_STD_TRY # _AC_CXX_CXX98_TEST_HEADER # ------------------------- # A C++ header suitable for testing for CXX98. AC_DEFUN([_AC_CXX_CXX98_TEST_HEADER], [[ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace test { typedef std::vector string_vec; typedef std::pair map_value; typedef std::map map_type; typedef std::set set_type; template class printer { public: printer(std::ostringstream& os): os(os) {} void operator() (T elem) { os << elem << std::endl; } private: std::ostringstream& os; }; } ]])# _AC_CXX_CXX98_TEST_HEADER # _AC_CXX_CXX98_TEST_BODY # ----------------------- # A C++ body suitable for testing for CXX98, assuming the corresponding header. AC_DEFUN([_AC_CXX_CXX98_TEST_BODY], [[ try { // Basic string. std::string teststr("ASCII text"); teststr += " string"; // Simple vector. test::string_vec testvec; testvec.push_back(teststr); testvec.push_back("foo"); testvec.push_back("bar"); if (testvec.size() != 3) { throw std::runtime_error("vector size is not 1"); } // Dump vector into stringstream and obtain string. std::ostringstream os; for (test::string_vec::const_iterator i = testvec.begin(); i != testvec.end(); ++i) { if (i + 1 != testvec.end()) { os << teststr << '\n'; } } // Check algorithms work. std::for_each(testvec.begin(), testvec.end(), test::printer(os)); std::string os_out = os.str(); // Test pair and map. test::map_type testmap; testmap.insert(std::make_pair(std::string("key"), std::make_pair(53,false))); // Test set. int values[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; test::set_type testset(values, values + sizeof(values)/sizeof(values[0])); std::list testlist(testset.begin(), testset.end()); std::copy(testset.begin(), testset.end(), std::back_inserter(testlist)); } catch (const std::exception& e) { std::cerr << "Caught exception: " << e.what() << std::endl; // Test fstream std::ofstream of("test.txt"); of << "Test ASCII text\n" << std::flush; of << "N= " << std::hex << std::setw(8) << std::left << 534 << std::endl; of.close(); } std::exit(0); ]]) # _AC_CXX_CXX11_TEST_HEADER # ------------------------- # A C++ header suitable for testing for CXX11. AC_DEFUN([_AC_CXX_CXX11_TEST_HEADER], [[ #include #include #include #include #include #include #include namespace cxx11test { typedef std::shared_ptr sptr; typedef std::weak_ptr wptr; typedef std::tuple tp; typedef std::array int_array; constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; } ]])# _AC_CXX_CXX11_TEST_HEADER # _AC_CXX_CXX11_TEST_BODY # ----------------------- # A C++ body suitable for testing for CXX11, assuming the corresponding header. AC_DEFUN([_AC_CXX_CXX11_TEST_BODY], [[ { // Test auto and decltype std::deque d; d.push_front(43); d.push_front(484); d.push_front(3); d.push_front(844); int total = 0; for (auto i = d.begin(); i != d.end(); ++i) { total += *i; } auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for and lambda cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (int &x : array) { x += 23; } std::for_each(array.begin(), array.end(), [](int v1){ std::cout << v1; }); } { using cxx11test::sptr; using cxx11test::wptr; sptr sp(new std::string("ASCII string")); wptr wp(sp); sptr sp2(wp); } { cxx11test::tp tuple("test", 54, 45.53434); double d = std::get<2>(tuple); std::string s; int i; std::tie(s,i,d) = tuple; } { static std::regex filename_regex("^_?([a-z0-9_.]+-)+[a-z0-9]+$"); std::string testmatch("Test if this string matches"); bool match = std::regex_search(testmatch, filename_regex); } { cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; cxx11test::int_array::size_type size = array.size(); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets std::vector> v1; } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ]]) # _AC_PROG_CXX_CXX98 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) # ------------------------------------------------------------------- # If the C++ compiler is not in ISO C++98 mode by default, try to add # an option to output variable CXX to make it so. This macro tries # various options that select ISO C++98 on some system or another. It # considers the compiler to be in ISO C++98 mode if it handles basic # features of the std namespace including: string, containers (list, # map, set, vector), streams (fstreams, iostreams, stringstreams, # iomanip), pair, exceptions and algorithms. AC_DEFUN([_AC_PROG_CXX_CXX98], [_AC_CXX_STD_TRY([cxx98], [_AC_CXX_CXX98_TEST_HEADER], [_AC_CXX_CXX98_TEST_BODY], dnl Try dnl GCC -std=gnu++98 (unused restrictive mode: -std=c++98) dnl IBM XL C -qlanglvl=extended dnl HP aC++ -AA dnl Intel ICC -std=gnu++98 dnl Solaris N/A (default) dnl Tru64 N/A (default, but -std gnu could be used) dnl with extended modes being tried first. [[-std=gnu++98 -std=c++98 -qlanglvl=extended -AA]], [$1], [$2])[]dnl ])# _AC_PROG_CXX_CXX98 # _AC_PROG_CXX_CXX11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) # ------------------------------------------------------------------- # If the C++ compiler is not in ISO CXX11 mode by default, try to add # an option to output variable CXX to make it so. This macro tries # various options that select ISO C++11 on some system or another. It # considers the compiler to be in ISO C++11 mode if it handles all the # tests from the C++98 checks, plus the following: Language features # (auto, constexpr, decltype, default/deleted constructors, delegate # constructors, final, initializer lists, lambda functions, nullptr, # override, range-based for loops, template brackets without spaces, # unicode literals) and library features (array, memory (shared_ptr, # weak_ptr), regex and tuple types). AC_DEFUN([_AC_PROG_CXX_CXX11], [_AC_CXX_STD_TRY([cxx11], [_AC_CXX_CXX11_TEST_HEADER _AC_CXX_CXX98_TEST_HEADER], [_AC_CXX_CXX11_TEST_BODY _AC_CXX_CXX98_TEST_BODY], dnl Try dnl GCC -std=gnu++11 (unused restrictive mode: -std=c++11) [and 0x variants] dnl IBM XL C -qlanglvl=extended0x dnl (pre-V12.1; unused restrictive mode: -qlanglvl=stdcxx11) dnl HP aC++ -AA dnl Intel ICC -std=c++11 -std=c++0x dnl Solaris N/A (no support) dnl Tru64 N/A (no support) dnl with extended modes being tried first. [[-std=gnu++11 -std=c++11 -std=gnu++0x -std=c++0x -qlanglvl=extended0x -AA]], [$1], [$2])[]dnl ])# _AC_PROG_CXX_CXX11 image-2.6.2/src/PaxHeaders.16724/__custom_gaussian_smoothing__.cc0000644000000000000000000000013213201323063021521 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/__custom_gaussian_smoothing__.cc0000644000175000017500000002053713201323063024270 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.6.2/src/PaxHeaders.16724/strel.h0000644000000000000000000000013213201323063014425 xustar0030 mtime=1510319667.175947267 30 atime=1510319667.175947267 30 ctime=1510319668.283933657 image-2.6.2/src/strel.h0000644000175000017500000001057313201323063017173 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 // XXX We need to include this first so it works with Octave 4.0.0. #include #include #include #include #include #include namespace octave { namespace image { class strel { public: explicit 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.6.2/src/PaxHeaders.16724/strel.cc0000644000000000000000000000013213201323063014563 xustar0030 mtime=1510319667.175947267 30 atime=1510319667.175947267 30 ctime=1510319668.283933657 image-2.6.2/src/strel.cc0000644000175000017500000002372413201323063017333 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 #include // gives us feval so we can use @strel #include #define WANTS_FEVAL 1 #include "octave-wrappers.h" // 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 = octave_image::feval ("strel", strel_args)(0); if (error_state) return; } nhood = octave_image::feval ("getnhood", se)(0).bool_array_value (); height = octave_image::feval ("getheight", se)(0).array_value (); // Maybe we should handle this better but how? This makes imerode // and imdilate work with a [] strel if (nhood.is_empty ()) { nhood = boolNDArray (dim_vector (1, 1), false); height = NDArray (dim_vector (1, 1), 0); } ini_ctor (); origin = default_origin (); const octave_value se_seq = octave_image::feval ("getsequence", se)(0); const octave_idx_type seq_numel = octave_image::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 = octave_image::feval ("subsref", subsref_args)(0); const boolNDArray elem_nhood = octave_image::feval ("getnhood", elem)(0).bool_array_value (); const NDArray elem_height = octave_image::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.6.2/src/PaxHeaders.16724/octave-wrappers.h0000644000000000000000000000013213201323063016416 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/octave-wrappers.h0000644000175000017500000000453613201323063021166 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2017 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 // . // Core is going through a bunch of changes, and moving a lot of // functions into the octave namespace and deprecating thw old // functions. We want to be compatible with older versions and we // don't want to scare users with deprecation warnings so we have our // own wrappers so nothing breaks. // // We don't want to have a file per function we need to wrap; we don't // want to repeat the wrapper in each file that needs it; we don't // want to disable the deprecation warnings (so that we get warnings // next time we something else gets deprecated); and we don't want to // include all needed headers. // // It is the job of the file that includes this to include the // required headers, at least as long as core only changes the // namespace and not the header file. // // This wrappers are all temporary until we no longer support the // Octave version that made the change. #include "config.h" namespace octave_image { // Temporary wrapper until we no longer support Octave 4.0 (bug #48618) #if defined WANTS_MIN && ! defined HAS_MIN #define HAS_MIN 1 template inline T min (T x, T y) { #if defined HAVE_MIN_IN_OCTAVE_MATH_NAMESPACE return octave::math::min (x, y); #else return xmin (x, y); #endif } #endif // Temporary wrapper until we no longer support Octave 4.2 (bug #50180) #if defined WANTS_FEVAL && ! defined HAS_FEVAL #define HAS_FEVAL 1 inline octave_value_list feval (const std::string& name, const octave_value_list& args, int nargout = 0) { #if defined HAVE_FEVAL_IN_OCTAVE_NAMESPACE return octave::feval (name, args, nargout); #else return ::feval (name, args, nargout); #endif } #endif } image-2.6.2/src/PaxHeaders.16724/intlut.cc0000644000000000000000000000013213201323063014751 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/intlut.cc0000644000175000017500000001112713201323063017513 0ustar00carandraugcarandraug00000000000000// Copyright (C) 2013-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 // . // This function is implemented in C++ because it basically does // indexing with base 0. If implemented in a m file, it would // require conversion of the image to a float just to add 1. #include // XXX We need to include this first so it works with Octave 4.0.0. #include #include #include template static inline P intlut_index (const typename P::val_type A, const P lut_vec[]) { return lut_vec[A]; } template<> inline octave_int16 intlut_index (const typename octave_int16::val_type A, const octave_int16 lut_vec[]) { return lut_vec[32768 + A]; } template static T intlut (const T& A, const T& lut) { const auto* A_vec = A.fortran_vec (); const auto* lut_vec = lut.fortran_vec (); T B (A.dims ()); auto* B_vec = B.fortran_vec (); const octave_idx_type n = A.numel (); typedef typename T::element_type::val_type P_val_type; for (octave_idx_type i = 0; i < n; i++, B_vec++, A_vec++) *B_vec = intlut_index (static_cast (*A_vec), lut_vec); return B; } DEFUN_DLD (intlut, args, , "\ -*- texinfo -*-\n\ @deftypefn {Function File} {} intlut (@var{A}, @var{LUT})\n\ Convert integer values with lookup table (LUT).\n\ \n\ Replace the values from the array @var{A} with the corresponding\n\ value from the lookup table @var{LUT}. This is equivalent as indexing\n\ @var{LUT} with @var{A}, with a base equal to @var{A} minimum possible\n\ value, i.e., @code{intmin (@var{A})}.\n\ \n\ For the simplest case of uint8 and uint16 class, it corresponds to:\n\ \n\ @example\n\ @var{LUT}(double (@var{A}) +1)\n\ @end example\n\ \n\ but without the temporary conversion of @var{A} to floating point\n\ thus reducing memory usage.\n\ \n\ @var{A} and @var{LUT} must be of the same class, and uint8, uint16,\n\ or int16. @var{LUT} must have exactly 256 elements for class uint8,\n\ and 65536 for classes uint16 and int16. Output is of same class\n\ as @var{LUT}.\n\ \n\ @seealso{ind2gray, ind2rgb, rgb2ind}\n\ @end deftypefn") { octave_value_list rv (1); if (args.length () != 2) { print_usage (); return rv; } const std::string cls = args(0).class_name (); if (cls != args(1).class_name ()) { error ("intlut: A and LUT must be of same class"); return rv; } const dim_vector lut_dims = args(1).dims (); if (lut_dims.length () != 2 || (lut_dims(0) > 1 && lut_dims(1) > 1)) { error ("intlut: LUT must be a vector"); return rv; } #define IF_TYPE(TYPE, TYPE_RANGE) \ if (args(0).is_ ## TYPE ## _type ()) \ { \ if (args(1).numel () != TYPE_RANGE) \ { \ error ("intlut: LUT must have " #TYPE_RANGE " elements for class %s", \ cls.c_str ()); \ return rv; \ } \ rv(0) = intlut (args(0).TYPE ## _array_value (), \ args(1).TYPE ## _array_value ()); \ } IF_TYPE(uint8, 256) else IF_TYPE(uint16, 65536) else IF_TYPE(int16, 65536) else error ("intlut: A must be of class uint8, uint16, or int16"); #undef IF_TYPE return rv; } /* %!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)); %!error intlut (uint16 (1:20), uint16 (0:500)); %! error intlut (uint8 (56), uint8 (magic (16) -1)) */ image-2.6.2/src/PaxHeaders.16724/imreconstruct.cc0000644000000000000000000000013213201323063016333 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/imreconstruct.cc0000644000175000017500000004062513201323063021102 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 // XXX We need to include this first so it works with Octave 4.0.0. #include #include #include "connectivity.h" using namespace octave::image; #define WANTS_MIN 1 #include "octave-wrappers.h" /* ## 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] = octave_image::min (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.6.2/src/PaxHeaders.16724/hough_line.cc0000644000000000000000000000013213201323063015553 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/hough_line.cc0000644000175000017500000000754713201323063020330 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.numel (); 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.numel (); 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.6.2/src/PaxHeaders.16724/configure0000644000000000000000000000013213201323064015030 xustar0030 mtime=1510319668.275933754 30 atime=1510319668.219934442 30 ctime=1510319668.283933657 image-2.6.2/src/configure0000755000175000017500000036236713201323064017614 0ustar00carandraugcarandraug00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Octave-Forge image package 2.6.2. # # # 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 test \$(( 1 + 1 )) = 2 || 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.6.2' PACKAGE_STRING='Octave-Forge image package 2.6.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_subst_vars='LTLIBOBJS LIBOBJS XTRA_CXXFLAGS OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX MKOCTFILE OCTAVE SED 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.6.2 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.6.2:";; 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.6.2 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.6.2, 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_config_headers="$ac_config_headers config.h" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST 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_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed # Extract the first word of "octave", so it can be a program name with args. set dummy octave; 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_path_OCTAVE+:} false; then : $as_echo_n "(cached) " >&6 else case $OCTAVE in [\\/]* | ?:[\\/]*) ac_cv_path_OCTAVE="$OCTAVE" # Let the user override the test with a path. ;; *) 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_path_OCTAVE="$as_dir/$ac_word$ac_exec_ext" $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 ;; esac fi OCTAVE=$ac_cv_path_OCTAVE if test -n "$OCTAVE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCTAVE" >&5 $as_echo "$OCTAVE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$OCTAVE"; then as_fn_error $? "*** 'octave' not found." "$LINENO" 5 fi # Extract the first word of "mkoctfile", so it can be a program name with args. set dummy mkoctfile; 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_path_MKOCTFILE+:} false; then : $as_echo_n "(cached) " >&6 else case $MKOCTFILE in [\\/]* | ?:[\\/]*) ac_cv_path_MKOCTFILE="$MKOCTFILE" # Let the user override the test with a path. ;; *) 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_path_MKOCTFILE="$as_dir/$ac_word$ac_exec_ext" $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 ;; esac fi MKOCTFILE=$ac_cv_path_MKOCTFILE if test -n "$MKOCTFILE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKOCTFILE" >&5 $as_echo "$MKOCTFILE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$MKOCTFILE"; then as_fn_error $? "*** 'mkoctfile' not found." "$LINENO" 5 fi CXX=`${MKOCTFILE} -p CXX` image_save_CXX="$CXX" 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 clang++ 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 clang++ 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 $as_echo_n "checking for $CXX option to enable C++11 features... " >&6; } 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 ${ac_cv_prog_cxx_cxx11+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include #include #include namespace cxx11test { typedef std::shared_ptr sptr; typedef std::weak_ptr wptr; typedef std::tuple tp; typedef std::array int_array; constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; } #include #include #include #include #include #include #include #include #include #include #include #include #include namespace test { typedef std::vector string_vec; typedef std::pair map_value; typedef std::map map_type; typedef std::set set_type; template class printer { public: printer(std::ostringstream& os): os(os) {} void operator() (T elem) { os << elem << std::endl; } private: std::ostringstream& os; }; } int main () { { // Test auto and decltype std::deque d; d.push_front(43); d.push_front(484); d.push_front(3); d.push_front(844); int total = 0; for (auto i = d.begin(); i != d.end(); ++i) { total += *i; } auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for and lambda cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (int &x : array) { x += 23; } std::for_each(array.begin(), array.end(), [](int v1){ std::cout << v1; }); } { using cxx11test::sptr; using cxx11test::wptr; sptr sp(new std::string("ASCII string")); wptr wp(sp); sptr sp2(wp); } { cxx11test::tp tuple("test", 54, 45.53434); double d = std::get<2>(tuple); std::string s; int i; std::tie(s,i,d) = tuple; } { static std::regex filename_regex("^_?([a-z0-9_.]+-)+[a-z0-9]+$"); std::string testmatch("Test if this string matches"); bool match = std::regex_search(testmatch, filename_regex); } { cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; cxx11test::int_array::size_type size = array.size(); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets std::vector> v1; } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } try { // Basic string. std::string teststr("ASCII text"); teststr += " string"; // Simple vector. test::string_vec testvec; testvec.push_back(teststr); testvec.push_back("foo"); testvec.push_back("bar"); if (testvec.size() != 3) { throw std::runtime_error("vector size is not 1"); } // Dump vector into stringstream and obtain string. std::ostringstream os; for (test::string_vec::const_iterator i = testvec.begin(); i != testvec.end(); ++i) { if (i + 1 != testvec.end()) { os << teststr << '\n'; } } // Check algorithms work. std::for_each(testvec.begin(), testvec.end(), test::printer(os)); std::string os_out = os.str(); // Test pair and map. test::map_type testmap; testmap.insert(std::make_pair(std::string("key"), std::make_pair(53,false))); // Test set. int values[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; test::set_type testset(values, values + sizeof(values)/sizeof(values[0])); std::list testlist(testset.begin(), testset.end()); std::copy(testset.begin(), testset.end(), std::back_inserter(testlist)); } catch (const std::exception& e) { std::cerr << "Caught exception: " << e.what() << std::endl; // Test fstream std::ofstream of("test.txt"); of << "Test ASCII text\n" << std::flush; of << "N= " << std::hex << std::setw(8) << std::left << 534 << std::endl; of.close(); } std::exit(0); ; return 0; } _ACEOF for ac_arg in '' -std=gnu++11 -std=c++11 -std=gnu++0x -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi # AC_CACHE_VAL ac_prog_cxx_stdcxx_options= case "x$ac_cv_prog_cxx_cxx11" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) ac_prog_cxx_stdcxx_options=" $ac_cv_prog_cxx_cxx11" CXX=$CXX$ac_prog_cxx_stdcxx_options { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 $as_echo "$ac_cv_prog_cxx_cxx11" >&6; } ;; esac 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$ac_cv_prog_cxx_cxx11" != xno; then : ac_prog_cxx_stdcxx=cxx11 ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_cv_prog_cxx_cxx98=$ac_cv_prog_cxx_cxx11 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 $as_echo_n "checking for $CXX option to enable C++98 features... " >&6; } 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 ${ac_cv_prog_cxx_cxx98+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace test { typedef std::vector string_vec; typedef std::pair map_value; typedef std::map map_type; typedef std::set set_type; template class printer { public: printer(std::ostringstream& os): os(os) {} void operator() (T elem) { os << elem << std::endl; } private: std::ostringstream& os; }; } int main () { try { // Basic string. std::string teststr("ASCII text"); teststr += " string"; // Simple vector. test::string_vec testvec; testvec.push_back(teststr); testvec.push_back("foo"); testvec.push_back("bar"); if (testvec.size() != 3) { throw std::runtime_error("vector size is not 1"); } // Dump vector into stringstream and obtain string. std::ostringstream os; for (test::string_vec::const_iterator i = testvec.begin(); i != testvec.end(); ++i) { if (i + 1 != testvec.end()) { os << teststr << '\n'; } } // Check algorithms work. std::for_each(testvec.begin(), testvec.end(), test::printer(os)); std::string os_out = os.str(); // Test pair and map. test::map_type testmap; testmap.insert(std::make_pair(std::string("key"), std::make_pair(53,false))); // Test set. int values[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; test::set_type testset(values, values + sizeof(values)/sizeof(values[0])); std::list testlist(testset.begin(), testset.end()); std::copy(testset.begin(), testset.end(), std::back_inserter(testlist)); } catch (const std::exception& e) { std::cerr << "Caught exception: " << e.what() << std::endl; // Test fstream std::ofstream of("test.txt"); of << "Test ASCII text\n" << std::flush; of << "N= " << std::hex << std::setw(8) << std::left << 534 << std::endl; of.close(); } std::exit(0); ; return 0; } _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi # AC_CACHE_VAL ac_prog_cxx_stdcxx_options= case "x$ac_cv_prog_cxx_cxx98" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) ac_prog_cxx_stdcxx_options=" $ac_cv_prog_cxx_cxx98" CXX=$CXX$ac_prog_cxx_stdcxx_options { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 $as_echo "$ac_cv_prog_cxx_cxx98" >&6; } ;; esac 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$ac_cv_prog_cxx_cxx98" != xno; then : ac_prog_cxx_stdcxx=cxx98 ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 else ac_prog_cxx_stdcxx=no ac_cv_prog_cxx_stdcxx=no 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 if test "x$ac_prog_cxx_stdcxx" != "xcxx11"; then as_fn_error $? "** could not find a C++11 compiler" "$LINENO" 5 fi CXX11_SWITCH=$(echo "$CXX" | $SED "s,^$image_save_CXX,,") MKOCTFILE="$MKOCTFILE $CXX11_SWITCH" CXX="$image_save_CXX" XTRA_CXXFLAGS="-Wall" 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 ## Octave 4.2 moved functions that clashed with C functions into its own ## namespace while deprecated the old ones prefixed with "x". We want to ## be compatible with Octave 4.0 but we also want to avoid scaring the ## users with deprecated warnings. Remove this once we no longer support ## Octave 4.0.X image_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -I`$MKOCTFILE -p OCTINCLUDEDIR`" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xmin is in the octave::math namespace" >&5 $as_echo_n "checking whether xmin is in the octave::math namespace... " >&6; } if ${octave_image_cv_xmin_in_octave_math_namespace+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { octave::math::min (2.0, 3.0) ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : octave_image_cv_xmin_in_octave_math_namespace=yes else octave_image_cv_xmin_in_octave_math_namespace=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $octave_image_cv_xmin_in_octave_math_namespace" >&5 $as_echo "$octave_image_cv_xmin_in_octave_math_namespace" >&6; } if test "$octave_image_cv_xmin_in_octave_math_namespace" = yes; then $as_echo "#define HAVE_MIN_IN_OCTAVE_MATH_NAMESPACE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether feval is in the octave namespace" >&5 $as_echo_n "checking whether feval is in the octave namespace... " >&6; } if ${octave_image_cv_feval_in_octave_namespace+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { octave::feval ("eye") ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : octave_image_cv_feval_in_octave_namespace=yes else octave_image_cv_feval_in_octave_namespace=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $octave_image_cv_feval_in_octave_namespace" >&5 $as_echo "$octave_image_cv_feval_in_octave_namespace" >&6; } if test "$octave_image_cv_feval_in_octave_namespace" = yes; then $as_echo "#define HAVE_FEVAL_IN_OCTAVE_NAMESPACE 1" >>confdefs.h fi CXXFLAGS="$image_save_CXXFLAGS" ## 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_echo "$as_me:${as_lineno-$LINENO}: WARNING: 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. " >&5 $as_echo "$as_me: WARNING: 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. " >&2;} fi ## Starting with Octave 4.2 (and some 4.1.X versions), the function ## im2double has been moved to Octave core. HAS_IM2DOUBLE=`$OCTAVE -qf --eval "printf ('%i', exist ('im2double'))"` if test "$HAS_IM2DOUBLE" == 0; then ac_config_files="$ac_config_files im2double.m" 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}' DEFS=-DHAVE_CONFIG_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.6.2, 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 case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _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 --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers 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.6.2 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;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --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 "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "im2double.m") CONFIG_FILES="$CONFIG_FILES im2double.m" ;; "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 test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers 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" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " 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 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; 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.6.2/src/PaxHeaders.16724/rotate_scale.cc0000644000000000000000000000013213201323063016077 xustar0030 mtime=1510319667.175947267 30 atime=1510319667.175947267 30 ctime=1510319668.283933657 image-2.6.2/src/rotate_scale.cc0000644000175000017500000001351113201323063020640 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.6.2/src/PaxHeaders.16724/watershed.cc0000644000000000000000000000013213201323063015420 xustar0030 mtime=1510319667.175947267 30 atime=1510319667.175947267 30 ctime=1510319668.283933657 image-2.6.2/src/watershed.cc0000644000175000017500000004545413201323063020174 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 . #include #include #include #include #include #include #define WANTS_FEVAL 1 #include "octave-wrappers.h" #include "connectivity.h" using namespace octave::image; template static boolNDArray imregionalmin (const T& im, const connectivity& conn) { octave_value_list args (2); args(0) = im; args(1) = conn.mask; const octave_value regional_min = octave_image::feval ("imregionalmin", args)(0); return regional_min.bool_array_value (); } static NDArray bwlabeln (const boolNDArray& bw, const connectivity& conn) { octave_value_list args (2); args(0) = bw; args(1) = conn.mask; const octave_value label = octave_image::feval ("bwlabeln", args)(0); return label.array_value (); } // Implements watershed in a quite naïve way. From the wikipedia, named // "Meyer's flooding algorithm" (but I could not find the actual paper // that reports it). There are faster (and also nicer results) algorithms, // but this is the only one I found that matches Matlab results. // // 1. A set of markers, pixels where the flooding shall start, are chosen. // Each is given a different label. // 2. The neighboring pixels of each marked area are inserted into a // priority queue with a priority level corresponding to the gray level // of the pixel. // 3. The pixel with the lowest priority level is extracted from the // priority queue. If the neighbors of the extracted pixel that have // already been labeled all have the same label, then the pixel is // labeled with their label. All non-marked neighbors that are not yet // in the priority queue are put into the priority queue. // 4. Redo step 3 until the priority queue is empty. // // There is a detail missing on the description above. On step 3, if the // labeled neighbours do *not* have the same label, should the non-labeled // neighbours be added to the queue? Apparently not. template class Voxel { public: P val; octave_idx_type idx; // We need this to sort elements with the same priority. We need them // to come out in the same order they went in. octave_idx_type pos; Voxel (const P val, const octave_idx_type idx, const octave_idx_type pos) : val (val), idx (idx), pos (pos) { } inline bool operator>(const Voxel& rhs) const { if (val == rhs.val) return pos > rhs.pos; else return val > rhs.val; } }; // As part of this algorithm, we will check the neighbourhood for existing // labels. We don't know in advance the number of labeled neighbours, or // where the first label will be. But we do know the length of the // neighbourhood. template class Collection { public: explicit Collection (const octave_idx_type n) : data (new T[n]) { } ~Collection (void) { delete [] data; } inline octave_idx_type numel (void) const { return count; } inline void push_back (const T val) { data[count++] = val; } inline void reset (void) { count = 0; } protected: T* data = NULL; octave_idx_type count = 0; private: // Disable default and copy constructor and assignment Collection (void); Collection (Collection const& other); Collection& operator = (Collection const& other); }; class LabelsCollection : public Collection { public: using Collection::Collection; inline double label (void) const { return *data; } inline bool all_equal (void) const { for (octave_idx_type i = 0; i < count; i++) if (data[0] != data[i]) return false; return true; } }; class IdxCollection : public Collection { public: using Collection::Collection; inline octave_idx_type operator [] (octave_idx_type i) const { return data[i]; } }; template NDArray watershed (const T& im, const connectivity& conn) { typedef typename T::element_type P; // 1. A set of markers, pixels where the flooding shall start, are chosen. // Each is given a different label. const boolNDArray markers = imregionalmin (im, conn); boolNDArray padded_markers = conn.create_padded (markers, false); NDArray label_array = bwlabeln (padded_markers, conn); double* label = label_array.fortran_vec (); const T padded_im_array = conn.create_padded (im, 0); const P* padded_im = padded_im_array.fortran_vec (); const Array neighbours_array = conn.deleted_neighbourhood (padded_im_array.dims ()); const octave_idx_type* neighbours = neighbours_array.fortran_vec (); const octave_idx_type n_neighbours = neighbours_array.numel (); // We need two flags per voxel for this implementation: // 1. Whether a voxel has been labelled or not. (TODO profile this later, // maybe it's enough to do label > 0) // 2. Whether a voxel can go into the queue. Reasons to not go into // the queue are: it's a padding voxel, it's already in the queue, // it's already been labelled. bool* label_flag = padded_markers.fortran_vec (); boolNDArray queue_flag_array (padded_markers); connectivity::set_padding (markers.dims (), padded_markers.dims (), queue_flag_array, true); bool* queue_flag = queue_flag_array.fortran_vec (); const octave_idx_type n = padded_im_array.numel (); octave_idx_type pos = 0; // 2. The neighboring pixels of each marked area are inserted into a // priority queue with a priority level corresponding to the gray level // of the pixel. std::priority_queue, std::vector>, std::greater>> q; for (octave_idx_type i = 0; i < n; i++) if (label_flag[i]) for (octave_idx_type j = 0; j < n_neighbours; j++) { const octave_idx_type ij = i + neighbours[j]; if (! queue_flag[ij]) { queue_flag[ij] = true; q.push (Voxel

(padded_im[ij], ij, pos++)); } } // 3. The pixel with the lowest priority level is extracted from the // priority queue. If the neighbors of the extracted pixel that have // already been labeled all have the same label, then the pixel is // labeled with their label. All non-marked neighbors that are not yet // in the priority queue are put into the priority queue. // 4. Redo step 3 until the priority queue is empty. // // There is a detail missing on the description above. On step 3, if the // labeled neighbours do *not* have the same label, should the non-labeled // neighbours be added to the queue? Apparently not. LabelsCollection lc (n_neighbours); IdxCollection ic (n_neighbours); while (! q.empty ()) { Voxel

v = q.top (); q.pop (); lc.reset (); ic.reset (); for (octave_idx_type j = 0; j < n_neighbours; j++) { const octave_idx_type ij = v.idx + neighbours[j]; if (label_flag[ij]) lc.push_back(label[ij]); else if (! queue_flag[ij]) ic.push_back(ij); } if (lc.numel () > 0 && lc.all_equal ()) { label[v.idx] = lc.label (); label_flag[v.idx] = true; for (octave_idx_type i = 0; i < ic.numel (); i++) { const octave_idx_type ij = ic[i]; queue_flag[ij] = true; q.push (Voxel

(padded_im[ij], ij, pos++)); } } } conn.unpad (label_array); return label_array; } DEFUN_DLD(watershed, args, , "\ -*- texinfo -*-\n\ @deftypefn {Function File} {} watershed (@var{im})\n\ @deftypefnx {Function File} {} watershed (@var{im}, @var{conn})\n\ Compute watershed transform.\n\ \n\ Computes by immersion\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{bwdist, bwlabeln, regionprops}\n\ @end deftypefn") { const octave_idx_type nargin = args.length (); if (nargin < 1 || nargin > 2) { print_usage (); return octave_value_list (); } connectivity conn; try { conn = (nargin > 1) ? connectivity (args(1)) : connectivity (args(0).ndims (), "maximal"); } catch (invalid_connectivity& e) { error ("bwconncomp: MASK %s", e.what ()); return octave_value_list (); } #define IF_TYPE(IS_TYPE, VALUE_TYPE) \ if (args(0).is_ ## IS_TYPE ## _type ()) \ return octave_value (watershed (args(0). VALUE_TYPE ## array_value (), \ conn)); \ // My guess is that uint8, uint16, and double will be the most common types. IF_TYPE(uint8, uint8_) else IF_TYPE(uint16, uint16_) else if (args(0).is_float_type ()) { if (args(0).is_complex_type ()) { IF_TYPE(double, complex_) else IF_TYPE(single, float_complex_) } else { IF_TYPE(double, ) else IF_TYPE(single, float_) } } else IF_TYPE(uint32, uint32_) else IF_TYPE(uint64, uint64_) else IF_TYPE(int8, int8_) else IF_TYPE(int16, int16_) else IF_TYPE(int32, int32_) else IF_TYPE(int64, int64_) else IF_TYPE(uint8, uint8_) else IF_TYPE(bool, bool_) error ("watershed: IM of unsupported class `%s'", args(0).class_name ().c_str ()); return octave_value_list (); #undef IF_TYPE } /* ## Some simple tests that will check the multiple ways to measure ## distances (comes to light on plateus) %!test %! ex = tril (ones (50), -1) + triu (repmat (2, [50 50]), 2); %! ex(1, 1) = 1; %! ex(end, end) = 1; %! %! in = ones (50); %! in(end,1) = 0; %! in(1,end) = 0; %! assert (watershed (in), ex) %!test %! ex = tril (ones (49), -1) + triu (repmat (2, [49 49]), 2); %! ex(1, 1) = 1; %! ex(end, end) = 1; %! %! in = ones (49); %! in(end,1) = 0; %! in(1,end) = 0; %! assert (watershed (in), ex) %! %! c = (fspecial ('disk', 5) > 0) + 1; %! in(20:30,20:30) = c; %! c = (fspecial ('disk', 4) > 0) + 2; %! in(21:29,21:29) = c; %! assert (watershed (in), ex) %!test %! ex = tril (ones (49), -1) + triu (repmat (2, [49 49]), 2); %! ex(1:28,1:28) = (tril (ones (28) ,7) + triu (repmat (2, [28 28]), 10)); %! ex(1,9) = 1; %! ex(end,end) = 1; %! ex(20:29, 29) = 0; %! %! in = ones (49); %! in(end,1) = 0; %! in(1,end) = 0; %! c = (fspecial ("disk", 5) > 0) + 1; %! in(1:11,38:48) = c; %! %! assert (watershed (in), ex) ## See http://perso.esiee.fr/~info/tw/index.html for a page on topological ## watershed. The following test cases were taken from a powerpoint ## presentation there http://perso.esiee.fr/~info/tw/isis03b.ppt ## "A topological approach to watersheds". Presentation made by Gilles Bertrand ## at the ISIS Workshop on Mathematical Morphology in Paris, France, 2003. ## ## From that presentation, the algorithm we must implement for Matlab ## compatibility is named "Meyer". %!test %! im = [ %! 3 4 5 6 0 %! 2 3 4 5 6 %! 1 2 3 4 5 %! 0 1 2 3 4 %! 1 0 1 2 3]; %! %! labeled8 = [ %! 1 1 1 0 2 %! 1 1 1 0 0 %! 1 1 1 1 1 %! 1 1 1 1 1 %! 1 1 1 1 1]; %! labeled4 = [ %! 1 1 1 0 3 %! 1 1 1 0 0 %! 1 1 0 2 2 %! 1 0 2 2 2 %! 0 2 2 2 2]; %! labeled_weird = [ %! 1 1 1 0 2 %! 1 1 1 1 0 %! 1 1 1 1 1 %! 1 1 1 1 1 %! 1 1 1 1 1]; %! %! assert (watershed (im), labeled8); %! assert (watershed (im, 8), labeled8); %! assert (watershed (im, 4), labeled4); %! assert (watershed (im, [1 1 0; 1 1 1; 0 1 1]), labeled_weird); %!test %! im = [ %! 2 3 30 2 %! 3 30 3 30 %! 255 31 30 4 %! 2 255 31 30 %! 1 2 255 5]; %! %! labeled4 = [ %! 1 1 0 4 %! 1 0 3 0 %! 0 2 0 5 %! 2 2 2 0 %! 2 2 0 6]; %! labeled_weird = [ %! 1 1 0 3 %! 1 1 1 0 %! 0 1 1 1 %! 2 0 0 0 %! 2 2 0 4]; %! %! assert (watershed (im, 4), labeled4); %! assert (watershed (im, [1 1 0; 1 1 1; 0 1 1]), labeled_weird); ## The following test is required for Matlab compatibility. There must be ## something specific about their implementation that causes it to return ## this value. Even when solving it on paper, we get different results. %!test %! im = [ %! 2 3 30 2 %! 3 30 3 30 %! 255 31 30 4 %! 2 255 31 30 %! 1 2 255 5]; %! %! labeled8 = [ %! 1 1 0 3 %! 1 1 0 3 %! 0 0 0 0 %! 2 2 0 4 %! 2 2 0 4]; %! assert (watershed (im), labeled8); %! assert (watershed (im, 8), labeled8); %!test %! im = [ %! 2 2 2 2 2 2 2 %! 2 2 30 30 30 2 2 %! 2 30 20 20 20 30 2 %! 40 40 20 20 20 40 40 %! 1 40 20 20 20 40 0 %! 1 1 40 20 40 0 0 %! 1 1 1 20 0 0 0]; %! %! labeled8 = [ %! 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 %! 2 2 2 0 3 3 3 %! 2 2 2 0 3 3 3 %! 2 2 2 0 3 3 3]; %! labeled4 = [ %! 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 %! 2 0 1 1 1 0 3 %! 2 2 0 1 0 3 3 %! 2 2 2 0 3 3 3]; %! labeled_weird = [ %! 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 0 0 %! 2 0 0 0 3 3 3 %! 2 2 0 3 3 3 3 %! 2 2 2 0 3 3 3]; %! %! assert (watershed (im), labeled8); %! assert (watershed (im, 8), labeled8); %! assert (watershed (im, 4), labeled4); %! assert (watershed (im, [1 1 0; 1 1 1; 0 1 1]), labeled_weird); %!test %! im = [ %! 40 40 40 40 40 40 40 40 40 40 40 40 40 %! 40 3 3 5 5 5 10 10 10 10 15 20 40 %! 40 3 3 5 5 30 30 30 10 15 15 20 40 %! 40 3 3 5 30 20 20 20 30 15 15 20 40 %! 40 40 40 40 40 20 20 20 40 40 40 40 40 %! 40 10 10 10 40 20 20 20 40 10 10 10 40 %! 40 5 5 5 10 40 20 40 10 10 5 5 40 %! 40 1 3 5 10 15 20 15 10 5 1 0 40 %! 40 1 3 5 10 15 20 15 10 5 1 0 40 %! 40 40 40 40 40 40 40 40 40 40 40 40 40]; %! %! labeled8 = [ %! 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 0 0 0 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3]; %! labeled4 = [ %! 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 1 1 1 1 1 0 0 0 0 %! 2 2 2 2 0 1 1 1 0 3 3 3 3 %! 2 2 2 2 2 0 1 0 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3]; %! labeled_weird = [ %! 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 1 1 0 0 0 0 0 0 0 %! 2 2 2 2 0 0 0 3 3 3 3 3 3 %! 2 2 2 2 2 0 3 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3 %! 2 2 2 2 2 2 0 3 3 3 3 3 3]; %! %! assert (watershed (im), labeled8); %! assert (watershed (im, 8), labeled8); %! assert (watershed (im, 4), labeled4); %! assert (watershed (im, [1 1 0; 1 1 1; 0 1 1]), labeled_weird); ## This test is failing for Matlab compatibility %!test %! im_full = [ %! 1 2 10 3 8 7 5 %! 3 2 5 10 8 1 4 %! 1 8 2 3 8 3 6]; %! %! matlab_result_full = [ %! 1 1 0 3 0 4 4 %! 0 0 0 0 0 4 4 %! 2 2 2 0 4 4 4]; %! %! assert (watershed (im_crop), matlab_result_crop); %! %! im_crop = [ %! 2 10 3 8 7 5 %! 2 5 10 8 1 4 %! 8 2 3 8 3 6]; %! %! matlab_result_crop = [ %! 1 0 2 0 3 3 %! 1 0 0 0 3 3 %! 1 1 1 0 3 3]; %! %! assert (watershed (im_crop), matlab_result_crop); */ image-2.6.2/src/PaxHeaders.16724/__bilateral__.cc0000644000000000000000000000013213201323063016165 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/__bilateral__.cc0000644000175000017500000001334113201323063020727 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 #include inline double gauss (const std::vector x, const std::vector mu, const double sigma) { double s = 0; for (size_t i = 0; i < x.size (); 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)std::round (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 std::vector val (num_planes); std::vector 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++) { std::vector 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); 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.6.2/src/PaxHeaders.16724/__boundary__.cc0000644000000000000000000000013213201323063016051 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/__boundary__.cc0000644000175000017500000001306113201323063020612 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 . #include /** * Oct-file to trace the boundary of an object in a binary image. * * b = boundary(region, conn=8) */ #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 std::vector 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.6.2/src/PaxHeaders.16724/connectivity.cc0000644000000000000000000000013213201323063016150 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/connectivity.cc0000644000175000017500000002241513201323063020714 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 "connectivity.h" #include #include #include #include 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; } boolNDArray connectivity::padding_mask (const dim_vector& size, const dim_vector& padded_size) { boolNDArray mask (padded_size, false); set_padding (size, padded_size, mask, true); return mask; } image-2.6.2/src/PaxHeaders.16724/imerode.cc0000644000000000000000000000013213201323063015056 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/imerode.cc0000644000175000017500000010363613201323063017627 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 // for an optimization using logical matrices // XXX We need to include this first so it works with Octave 4.0.0. #include #include #include // to get ind2sub #include #include #include // 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; // If image is empty, return empty of the same class. if (im.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 boolNDArray nhood = se.get_nhood (); 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_type ()) 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] as mask returns the same value %!assert (imerode (eye (3), [1]), eye (3)); ## and an empty SE returns all Inf %!assert (imerode (eye (3), []), Inf (3, 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)); */ /* ## bug #47879 (invalid but mathematically interesting corner-case) ## This is all about empty sets, either by using a blank/empty/zeros SE ## or by picking a SE that "picks" elements only from the borders. These ## are two completely different issues that may look the same. See a more ## detailed explanation at http://stackoverflow.com/a/37117842/1609556 %!test # scalar blank SE %! se = 0; %! assert (imerode (5, se), Inf) %! assert (imerode (true, se), true) %! assert (imerode (false, se), true) %! assert (imerode (uint8 (3), se), uint8 (255)) %! %! assert (imdilate (5, se), -Inf) %! assert (imdilate (true, se), false) %! assert (imdilate (false, se), false) %! assert (imdilate (uint8 (3), se), uint8 (0)) %!test # empty SE %! se = []; %! assert (imerode (5, se), Inf) %! assert (imerode (true, se), true) %! assert (imerode (false, se), true) %! assert (imerode (uint8 (3), se), uint8 (255)) %! %! assert (imdilate (5, se), -Inf) %! assert (imdilate (true, se), false) %! assert (imdilate (false, se), false) %! assert (imdilate (uint8 (3), se), uint8 (0)) %!test # non-scalar blank SE %! se = zeros (3, 3); %! assert (imerode (5, se), Inf) %! assert (imerode (true, se), true) %! assert (imerode (false, se), true) %! assert (imerode (uint8 (3), se), uint8 (255)) %! %! assert (imdilate (5, se), -Inf) %! assert (imdilate(true, se), false) %! assert (imdilate (false, se), false) %! assert (imdilate (uint8 (3), se), uint8 (0)) %!test # erode only with out-of-border elements %! se = [1 1 1; 1 0 1; 1 1 1]; %! assert (imerode (5, se), Inf) %! assert (imerode (true, se), true) %! %! assert (imdilate (5, se), -Inf) %! assert (imdilate (true, se), false) %!test # only true elements of SE are out-of-border %! se = [0 0 0; 1 0 0; 1 1 0]; %! assert (imerode (zeros (3), se), [0 0 0; 0 0 0; Inf 0 0]) %! assert (imerode (false (3), se), logical ([0 0 0; 0 0 0; 1 0 0])) %! assert (imdilate (zeros (3), se), [0 0 -Inf; 0 0 0; 0 0 0]) %! assert (imdilate (false (3), se), false (3, 3)) %! %! se = [0 0 0; 0 0 0; 1 1 1]; %! assert (imerode (zeros (3, 3), se), [0 0 0; 0 0 0; Inf Inf Inf]) %! assert (imerode (false (3, 3), se), logical ([0 0 0; 0 0 0; 1 1 1])) %! assert (imdilate (zeros (3, 3), se), [-Inf -Inf -Inf; 0 0 0; 0 0 0]) %! assert (imdilate (false (3, 3), se), false (3, 3)) %!test # only true elements of even-sized SE are out-of-border %! se = logical ([0 1; 1 1]); %! assert (imerode (false (3, 3), se), logical ([0 0 0; 0 0 0; 0 0 1])) %! assert (imerode (zeros (3, 3), se), [0 0 0; 0 0 0; 0 0 Inf]) %! %! assert (imdilate (false (3, 3), se), false (3, 3)) %! assert (imdilate (zeros (3, 3), se), [-Inf 0 0; 0 0 0; 0 0 0]) */ image-2.6.2/src/PaxHeaders.16724/conndef.cc0000644000000000000000000000013213201323063015046 xustar0030 mtime=1510319667.167947366 30 atime=1510319667.167947366 30 ctime=1510319668.283933657 image-2.6.2/src/conndef.cc0000644000175000017500000002173313201323063017614 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.6.2/src/PaxHeaders.16724/nonmax_supress.cc0000644000000000000000000000013213201323063016516 xustar0030 mtime=1510319667.171947317 30 atime=1510319667.171947317 30 ctime=1510319668.283933657 image-2.6.2/src/nonmax_supress.cc0000644000175000017500000001242513201323063021262 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 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; 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; double testdist = M_PI; double dist = M_PI; for (int i = 0; i < 4; i++) { testdist = orientation-d[i]; if ( testdist > 0.5 * M_PI ) testdist = testdist - M_PI; testdist = fabs( testdist); if ( testdist < dist) { dist = testdist; 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.6.2/src/PaxHeaders.16724/bwfill.cc0000644000000000000000000000013213201323063014711 xustar0030 mtime=1510319667.163947416 30 atime=1510319667.163947416 30 ctime=1510319668.283933657 image-2.6.2/src/bwfill.cc0000644000175000017500000001523313201323063017455 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 #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\ @seealso{imfill}\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.numel (); 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; std::vector 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. std::vector 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.data (), ptstack.data (), &npoints); } while (npoints > 0) { npoints--; int pt = ptstack[npoints]; checkpoint (pt + ptLF, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptRT, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptUP, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptDN, imo.data (), ptstack.data (), &npoints); if (nb==8) { checkpoint (pt + ptLF + ptUP, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptRT + ptUP, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptLF + ptDN, imo.data (), ptstack.data (), &npoints); checkpoint (pt + ptRT + ptDN, imo.data (), ptstack.data (), &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.6.2/PaxHeaders.16724/NEWS0000644000000000000000000000013213201323063013033 xustar0030 mtime=1510319667.079948446 30 atime=1510319667.079948446 30 ctime=1510319668.283933657 image-2.6.2/NEWS0000644000175000017500000006564013201323063015606 0ustar00carandraugcarandraug00000000000000 Summary of important user-visible changes for image 2.6.2 (2017/11/09): ------------------------------------------------------------------------- ** image 2.6.2 is a patch release. ** Fix regionprops MajorAxisLength, MinorAxisLength, and Orientation when there's multiple regions in an image; and Orientation for thin regions. ** Fix montage usage with a cell array of image filepaths. ** Fixed installation for upcoming versions of Octave. Enables installation in current development version 4.3.0+. Summary of important user-visible changes for image 2.6.1 (2016/10/21): ------------------------------------------------------------------------- ** image 2.6.1 is a patch release. ** Fix imtranslate regression when used with the "crop" option. ** Fix compilation issues for clang++ users on Mac OSX. Summary of important user-visible changes for image 2.6.0 (2016/10/05): ------------------------------------------------------------------------- ** The following functions are new: imfill lab2rgb rgb2lab imgetfile lab2single rgb2xyz impyramid lab2uint16 watershed imquantize lab2uint8 xyz2lab lab2double lab2xyz xyz2rgb ** For better compatibility with Matlab, the imtransform function now uses 0 instead of NA for the default extrapolation value. ** The regionprops function has been rewritten and should perform several orders of magnitude faster dependending on the number of properties being measured and the number of objects; the new implementation will be specially faster for a large number of objects and multiple properties. In addition to the increased performance, regions can be defined with a bwconncomp structure. The following properties have changed: * FilledArea - new support for ND images * FilledImage - new support for ND images * SubarrayIdx - new property implemented ** stretchlim() now properly supports integer input and will return values in the [0 1] range. It also no longer performs rounding of the saturated fraction, so that TOL is now the saturation limit (rather than a saturation that it tries to approximate). Support for N dimensional images has been added. ** imadjust() now supports images of integer class without requiring an intermediary conversion to a floating point class. Support for N dimensional images has also been added. It now requires that input and output limits be always specified in a [0 1] range, even if the image of a floating point class. ** The function is isgray(), isind(), and isrgb() will return true for images of class single in addition to double. ** im2bw() now accepts a string specifying a graythresh() algorithm as an alternative to a threshold value. This simplifies the very common usage of `im2bw (im, graythresh (im, method))`. ** Fix imcrop() usage when defaulting to current figure and allow the bounding box to be selected by clicking on any two opposite corners of the image. ** fspecial() is now capable to create N dimensional gaussian filters. ** checkerboard() is now capable to create N dimensional checkerboards. ** Other functions that have been changed for smaller bugfixes, increased Matlab compatibility, or performance: edge imdilate imremap grayslice imerode mat2gray im2bw imfilter montage im2col imresize normxcorr2 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.