Mercurial > hg > octave-image
changeset 564:7db61a0a2632
imhist: complete rewrite of the function to be matlab compatible. Added test cases. No old code left so removed old copyright owners.
author | carandraug |
---|---|
date | Mon, 14 May 2012 17:23:29 +0000 |
parents | d2a6dc5e921e |
children | 7fcfcce0b2f9 |
files | NEWS inst/imhist.m |
diffstat | 2 files changed, 118 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS +++ b/NEWS @@ -54,6 +54,10 @@ isind mat2gray + ** `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. + ** `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").
--- a/inst/imhist.m +++ b/inst/imhist.m @@ -1,6 +1,4 @@ -## Copyright (C) 1999,2000 Kai Habel <kai.habel@gmx.de> -## Copyright (C) 2000 Paul Kienzle <pkienzle@users.sf.net> -## Copyright (C) 2011 Carnë Draug <carandraug+dev@gmail.com> +## Copyright (C) 2011, 2012 Carnë Draug <carandraug+dev@gmail.com> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -20,7 +18,7 @@ ## @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{}) -## Shows the histogram of an image @var{I}. +## 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 @@ -30,65 +28,142 @@ ## 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. +## +## Since a colorbar is not displayed under the histogram, calling this function +## to visualize the histogram of an indexed image may not be very helpful. +## ## @seealso{hist, histc, histeq} ## @end deftypefn -function [nn, bins] = imhist (I, b) +function [varargout] = imhist (img, b) + + ## then img can either be a "normal" or indexed image. We will need to + ## check the second argument to find out + indexed = false; if (nargin < 1 || nargin > 2) - print_usage(); + print_usage; elseif (nargin == 1) - if (islogical(I)) - bins = 0:1; + if (islogical (img)) + b = 2; else - bins = 0:255; + b = 256; endif elseif (nargin == 2) - ## A matrix with 3 columns is a colormap so... - if (ismatrix (b) && columns (b) == 3) - using_colormap = true; + if (iscolormap (b)) ## if using a colormap, image must be an indexed image - if (!isind(I)) - error ("second argument is a colormap but image is not indexed"); + indexed = true; + elseif (isnumeric (b) && isscalar (b) && fix(b) == b) + ## do nothing, all is good + if (islogical (img) && b != 2) + error ("there can only be 2 bins when input image is binary") endif - max_idx = max (I(:)); - bins = 0:rows(b)-1; - if (max_idx > bins(end)) - warning ("largest index exceeds length of colormap"); - endif - elseif (isnumeric (b) && isscalar (b) && fix(b) == b) - bins = 0:b-1; else error ("second argument should either be a positive integer scalar or a colormap"); endif endif - ## matlab returns bins as one column and not one row so we transpose the range - bins = bins'; + ## check if img is good + if (indexed) + if (!isind(img)) + error ("second argument is a colormap but image is not indexed"); + endif + ## an indexed image reads differently wether it's uint8/16 or double + ## If uint8/16, index-1 is the colormap row number (there's an offset of 1) + ## 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 ("largest index in image exceeds length of colormap"); + endif + endif - ## XXX at the moment, this function is not working at all, at least for - ## grayscale images. I'm assuming that the code will at least be working for - ## indexed images and colormaps so I'm leaving the original code for those - ## cases and use only the "new" code when "using_colormap" is false - ## Carnë Draug 10/11/2011 - if (nargout == 0) - if (exist ("using_colormap", "var") && using_colormap) - hist (I(:), bins); + ## prepare bins + if (indexed) + if (isinteger (img)) + bins = 0:rows(b)-1; else - [nn] = histc (I(:), bins); - stem (bins, nn); + bins = 1:rows(b); endif else - if (exist ("using_colormap", "var") && using_colormap) - [nn,bins] = hist (I(:), bins); + if (isinteger (img)) + bins = linspace (intmin (class (img)), intmax (class (img)), b); + elseif (islogical (img)) + bins = 0:1; else - [nn] = histc (I(:), bins); + ## image must be single or double + bins = linspace (0, 1, b); + endif + ## we will use this bins with histc where they are the edges for each bin + ## but in imhist we want them to be the center of each bin. We can't use + ## hist either since values right in the middle will go to the bottom + ## bin (4.5 will be placed on the bin 4 instead of 5 and this is like + ## matlab, not an octave bug). So we still use histc but we decrease their + ## values by half of bin width and increase it back in the end to return + ## the values (if we did it on the image it would be only one step but + ## would be heavier on the system since images are likely to be larger + ## than bins) + if (!islogical (img)) + bins -= ((bins(2) - bins(1))/2); endif + ## matlab returns bins as one column instead of a row but only for non + ## indexed images + bins = bins'; + endif - vr_val_cnt = 1; - varargout{vr_val_cnt++} = nn; - varargout{vr_val_cnt++} = bins; + ## if not dealing with indexed image, we may need to make sure values are + ## between get bin values + if (!indexed) + ## while integers could in no way have a value below the minium of their + ## class, floats can have values below zero which need to be truncated + if (isfloat (img)) + img(img < 0) = 0; + endif + ## because we adjusted the bins edge below the max value of the class, and + ## because histc will not count values outside the edges, we need to bring + ## them down (no need to worry about the min because the min edge is already + ## below the mininum of the class). This also adjusts floats above 1 + if (max (img(:)) > bins(end)) + ## in case it's a integer, if we try to assign the non integer values it + ## will fail so we need to make it double. But this means it takes more + ## memory so let's first make sure we need to + 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(2) - bins(1))/2); + endif + + if (nargout != 0) + varargout{1} = nn; + varargout{2} = bins; + else + stem (bins, nn); + ## would be cool if we managed to have the colormap showed under the + ## histogram like matlab does. Should look into the code of waitfor and + ## colormap to check how to do it 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'})