As a follow up to this question: Calculate mean and standard deviation from ImageHistogram

I would like to add two histograms before calculating the mean and StDev. I would like to sum the numbers, not superimpose the graphics.

Explanation: I have photographed flat samples, they have a front and back side, and so I would like to get 1 outcome/Histogram for both sides summed.

Thank you for responding!


We are now using:

hist = ImageHistogram[finalCrop, Appearance -> "Separated"];
Print[hist]; resImage = ImageResize[finalCrop, 200];


"Separated"],histB=ImageHistogram[finalcrop,Appearance->\" Separated \

If[Mod[i,2] == 0, Print[histF],Print[histB]];*)

rgbImage = Transpose@Flatten[ImageData[finalCrop], 1];


table = TableForm[Through[{Mean, StandardDeviation}[#]] & /@ rgbImage,
    TableHeadings -> {{"Red", "Blue", "Green"}, {"Mean", "StDev"}}];

And I will the first to admit that I do not completely understand this, but as you can (hopefully) see, we are using histF (front of sample) en histB (back of sample) so then I would use

histTotal = Join @@@ Transpose[{histF,histB}] 

followed by

GraphicsRow[Histogram /@ histTotal]

Correct? Am trying it now!


In his reply to your previous (linked) question, Murta adviced to use

GraphicsRow[Histogram /@ imgChannelsRGB, ImageSize -> 500]

Here histogram is being applied to each of the three elements of the list imgChannelsRGB, which are themselves a List of values for red, values for green and values for blue respectively.

Suppose you have similar data of two pictures, imgChannelsRGB1 and imgChannelsRGB2.

You can use

newImgChannelsRGB = Join @@@ Transpose[{imgChannelsRGB1,imgChannelsRGB2}] 

to get a similar List of Lists of values for the individual colors. Then you can use

GraphicsRow[Histogram /@ newImgChannelsRGB]

like before.

As a side remark, note that if the red values of one picture are concentrated around 0.8 and the red values of the other are concentrated around 0.3, and each have a standard deviation of 0.1, then taking the standard deviation of the "joined sample" may be misleading (of course).

Another note: I am sure Mr. Wizard can write Join @@@ Transpose[{imgChannelsRGB1,imgChannelsRGB2}] more elegantly :).

  • $\begingroup$ Ah, Thank you, again! $\endgroup$ – onemonkey Oct 19 '12 at 10:01
  • $\begingroup$ Edit: still learning that Return means post and does not add white line. Trying to post code we are now using... $\endgroup$ – onemonkey Oct 19 '12 at 10:01
  • 1
    $\begingroup$ Judge for yourself: Join[imgChannelsRGB1, imgChannelsRGB2, 2] :-) $\endgroup$ – Mr.Wizard Oct 19 '12 at 10:16
  • $\begingroup$ Haha, I am such a fan of yours :) $\endgroup$ – Jacob Akkerboom Oct 19 '12 at 10:21
  • 1
    $\begingroup$ Or, I believe, you could just use imgChannelsRGB1 + imgChannelsRGB2 ;-) -- With either version the data dimensions will need to be exactly the same. $\endgroup$ – Mr.Wizard Oct 19 '12 at 16:40

The spirit of the question seems to involve basing all computations on the "histograms"--binned summaries of data--rather than on the raw data. Here, then, is a solution in that spirit.

Begin with the data for an image, represented as a list of {Red, Green, Blue} values, as in this example:

x = Flatten[ImageData[Import["ExampleData/lena.tif"]], 1];

The histograms with the finest resolutions actually tally the values in the bands:

{r, g, b} = Tally /@ Transpose[x];

The result of Tally lists {value, count} pairs. All subsequent calculations will be based only on these summaries. A plot of them is tantamount to a histogram:

ListPlot[{b, r, g}, Filling -> Axis, 
     FillingStyle -> Table[i -> Directive[Opacity[1/3], {Blue, Red, Green}[[i]]], {i, 1, 3}]]


To compute the statistics, we need to weight the values and their squares by the counts before averaging. This can conveniently be done with matrix operations provided we augment each {value, count} pair to include the constant $1$ and the squared value. The following implementation uses variable names to document the meanings of the calculations being performed:

stats[x_List] := 
  Block[{z = Join[x, {1, #[[1]]^2} & /@ x, 2], a, count, mean, sum, sumSquares},
   a = Transpose[z] . z;
   sum = a[[1, 2]];
   sumSquares = a[[2, 4]];
   count = a[[2, 3]];
   mean = sum/count;
   {count, mean, Sqrt[sumSquares/count - mean^2]}

The output evidently is a list of basic statistics: the number of pixels, their average, and their standard deviation. Here is a summary by band:

TableForm[stats /@ {r, g, b} // N , TableHeadings -> {{"Red","Green","Blue"}, {"Count","Mean","SD"}}]

Summary of three bands separately

For statistics of combined data, it suffices to concatenate the information in the histograms:

TableForm[{stats[Join[r, g, b]]} // N, TableHeadings -> {{}, {"Count","Mean","SD"}}]

Joint Summary


Notice that the preceding result summarizes 52,200 values--the combined count of all three bands--rather than just 17,400 pixels, which would be the result of first superimposing the bands (by per-pixel averaging, for instance) and then summarizing. Let's compare by creating a superposition of the three bands (gray) and repeating the analyses:

gray =  Tally[Mean /@ x];
ListPlot[gray, Filling -> Axis, PlotStyle -> Black, FillingStyle -> Directive[Opacity[0.5], Gray]]

Grayscale histogram

TableForm[{stats[gray]} // N, TableHeadings -> {{}, {"Count", "Mean", "SD"}}]

Grayscale summary

As one would expect--and can easily be proven--the means are identical, but the standard deviations and counts change. (The slightly smaller SD indicates a lack of perfect correlation among the bands, also to be expected, because this was not a grayscale image.)

  • $\begingroup$ very pretty plots! $\endgroup$ – chris Oct 19 '12 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.