# Add two Histograms to calculate summed Mean and StandardDeviation

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!

Edit:

We are now using:

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

(*imagedata=ImageData[finalimage];*)

(*If[Mod[i,2]==0,histF=ImageHistogram[finalcrop,Appearance->\
"Separated"],histB=ImageHistogram[finalcrop,Appearance->\" Separated \
"]];

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

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

(*hist2=GraphicsRow[Histogram/@rgbImage,ImageSize->500];
Print[hist2];*)

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


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!

-

## 2 Answers

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 :).

-
Ah, Thank you, again! –  onemonkey Oct 19 '12 at 10:01
Edit: still learning that Return means post and does not add white line. Trying to post code we are now using... –  onemonkey Oct 19 '12 at 10:01
Judge for yourself: Join[imgChannelsRGB1, imgChannelsRGB2, 2] :-) –  Mr.Wizard Oct 19 '12 at 10:16
Haha, I am such a fan of yours :) –  Jacob Akkerboom Oct 19 '12 at 10:21
Thanks! I think I'm pretty good with Mathematica syntax but you should know that I'm a lightweight around here when it comes to math or computer science. –  Mr.Wizard Oct 19 '12 at 10:29

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"}}]


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"}}]


### Comments

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]]


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


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.)

-
very pretty plots! –  chris Oct 19 '12 at 19:52