Why does imhist() do this?
40 views (last 30 days)
Show older comments
I thought I had asked this once before, but maybe it was a fever dream. It's hard to tell at this point.
IPT imhist() is a convenience tool for creating histograms of grayscale image data. It bins the image data such that the end bins are centered on the ends of the interval implied by the numeric class of the data (e.g. [0 1] for 'double'). It displays the histogram using a stem() plot, with one stem in the center of each histogram bin.
This much might be disagreeable, since the end bins are effectively half-width, but let's accept the choice to align the bin centers to the interval limits instead of aligning the bin edges.
What I can't understand is the colorbar. Beneath the stem plot is a grayscale colorbar showing the progression N gray levels corresponding to the N histogram bins. The problem is twofold:
- While the histogram bin centers are aligned to the interval limits (and cannot be changed), the gray segments of the colorbar have their edges aligned with the interval limits -- and they can't be changed either. The two are always misaligned.
- The actual gray values used in the colorbar correspond to the upper edge of where the histogram bins would be if they were edge-aligned, but they're not. The first half of the gray segments don't even correspond to the bin they represent. The asymmetry makes plots with small N extra nonsensical.
So I put together a thing for visual emphasis and figured I'd run it here to see if it's just my old version. It's not.
% some inputs
inpict = rand(500);
n = 5;
% imhist() can either give outputs or plot.
% it can't do both, so we have to call it twice.
imhist(inpict,n); hold on
[counts centers] = imhist(inpict,n);
% find the axes since it won't give them to us
hax = findobj(get(gcf,'children'),'type','axes');
% figure out the bin edges from the centers,
% since it won't give us edges either
dx = diff(centers(1:2));
xr = [centers(1)-dx/2 centers(end)+dx/2];
yr = ylim(hax(2));
% create two images:
% top is a smooth sweep from black to white.
% bottom corresponds to the center of each histogram bin.
% the two images should periodically match at each bin center.
smoothramp = repmat(linspace(xr(1),xr(2),100),[1 1 3]);
binramp = repmat(centers.',[1 1 3]);
binramp = imresize(binramp,[1 size(smoothramp,2)],'nearest');
% concatenate the two stripe images
% clamp as necessary for legacy versions
compramp = min(max([binramp; smoothramp],0),1);
% put the composite image behind the stem plot
hi = image(xr,yr,compramp,'parent',hax(2));
uistack(hi,'bottom')
% find the stem plot and make it fat so it's easier to see
hst = findobj(hax(2),'type','stem');
set(hst,'linewidth',3)
% draw a solid gray circle above each stem,
% such that the circle color is taken directly from the stem position
for k = 1:n
hp = plot(hax(2),centers(k),yr(2)*0.67,'.');
set(hp,'color',[1 1 1]*centers(k));
set(hp,'markersize',60);
end
So we have a stem plot, two images, and circular plot markers that all agree, but the color bar is off doing its own thing. The gray level in the first two colorbar segments isn't even in the corresponding histogram bin.
Apparently this is the way imhist() has done it for at least the last 15 years, so is there actually a reason for it, or is it just one of those forever-bugs?
I'm in the middle of trying to write my way around MIMT's usage of imhist(), and I'm inclined to just take a step back and make a complete replacement instead.
3 Comments
Answers (2)
Alex Taylor
on 22 May 2024
Edited: Alex Taylor
on 22 May 2024
The function imhist is one of the older functions in the Image Processing Toolbox and we on the development team are aware that imhist has a variety of questionable design choices including but not limited to:
- Definition of histogram based on bin centers vs. bin edges.
- Use of number of left hand side arguments to infer whether user wants plotting vs. programatic histogram binning (e.g. histcounts). This results in the behavior noted above where two calls to imhist were required to plot and compute the histogram counts and the plotting can't use the count information.
For these items, I would recommend in the near term using the modern histogram display and computation functions in MATLAB: histogram and histcounts. They can be used to address both of the behaviors above.
The main value add at this point of imhist is its visualization of image gray levels in the context of a histogram, which is not something trivial to reproduce with histogram and histcounts today. That and I suppose indexed image support for people who work with indexed images. There is also the matter of default binning behavior as a function of input datatype, so a few things.
I consider the two behaviors you noted in the misalignment of the colorbar with respect to the histogram bin center definition (and stem placement) and certainly the indexed image behavior colorbar behavior of displaying colors not present in the data in the colorbar to be a bug and will track them as such.
I appreciate the detailed discussion here and in particular your histogram code as a means of communicating your desired behavior. I can't provide any short term fixes or workarounds for the moment with these issues but we do take your bug report seriously and intend to fix both the bugs and some of the UX choices described above in a future release of the product.
See Also
Categories
Find more on Data Distribution Plots in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!