 • ## The Histogram

The histogram `H` of a gray value image is an integer-array of lenght 256, where `H[g]` contains the no. of pixels carrying the gray value `g`.
`H` contains the no. of zeros, `H` the no. of ones et cetera.

The sum of all histogram values must give the total no of pixels !
Pseudo-code of the check whether a histogram `H` fits to an image `I[width*height]`:
```sum = 0; for (int i=0; i < 256; i++ ) sum += H[i]; if ( sum != width*height ) -> Histogram H doesn't fit to image I !```

Black-and-white images have one, true color images have three histograms.
A histograms shows the statistical distribution of brightness values of a picture.
It informs about basic image properties such as exposure, contrast, color proportions.

Code to compute the histogram `int H` of an image `Byte I[ySize][xSize]`,
`H` must be pre-filled with `0`.
Slow code
:
```for ( y=0; y < ySize; y++ )   for ( x=0; x < xSize; x++ )     H[I[y][x]]++;```
Fast code:
```int* pointer = I; for ( i=0; i < xSize*ySize; i++ ) H[*(pointer+i)]++;```
Very fast code:
`for ( int* pointer = I; pointer < I + xSize*ySize; ) H[*pointer++]++;`

Mini-Sample: The histogram `H` of mini-image `I`

```         01020
I= 27891    Solution: H = [ 5, 4, 3, 2, 0, 1, 1, 2, 1, 1 ]
06571    Proof: The sum of the histogram must be ySize*xSize = 4*5 = 20.
13230```

As a rule histograms are plotted in form of a bar chart with:
gray values extending from 0 to 255 on the horizontal axis and
normalized frequencies of gray values on the vertical axis.
Professional video cameras monitor three (RGB) histograms online on the screen, which makes it possible for the cameraman to control exposure, aperture, image section etc.

The cumulative histogram is the image's accumulated normalized histogram in which the vertical axis gives not just the counts for a single gray, but rather gives the counts for that gray plus all left-side values:
`for (i=0; i < gray; i++) CumulativeHistogram[gray] += Histogram[i];`
Cumulative histograms can give sense to visualize the result of contrast stretching operations.

Binarisation by Thresholding is an important first step of pattern recognition.
It requires a fixed threshold to separate foreground from background.
A histogram with two peaks is ideal to determine the threshold in the mid of the valley between the peaks. Binarisation of images with a two peak histogram:
Slow code:
```for ( y=0; y < ySize; y++ )   for ( x=0; x < xSize; x++ )      if ( I[y][x]] < threshold ) I[y][x] = 0; else I[y][x] = 255;```
Fast code:
`int* pointer = I;for ( i=0; i < xSize*ySize; i++, pointer++ ) if ( *pointer < threshold ) *pointer = 0; else *pointer = 255;`

# Experiment:

• Drag the slider at different thresholds and release the left mouse button.

# Experiment: Drag the three sliders to about these positions in order to obtain a realistic image of the butterfly with just pure red, green and blue.
• ## The Code of the Black-and-White Histogram

```WriteableBitmap img0, img1; //input+output images
Int32 xSize, ySize; //image width+height
Int32[] Histogram = new Int32;
Brush brush = new SolidColorBrush( Colors.Black );
Int32 threshold = 255;
Int32[xSize*ySize] RGB; //intermediary array for (r+g+b)/3
Canvas HistogramCanvas: //area to draw lines
private void ComputeColorHistogram()
{ for ( int gray=0; gray < 256; gray++ ) Histogram[gray] = 0; //clear
for ( int i=0; i < xSize*ySize; i++ ) //for all Int32-pixels
{ Int32 r, g ,b, argb = img0.Pixels[i]; //local variables
r = (argb & 0xff0000) >> 16; //Cut out red   and shift it down.
g = (argb & 0x00ff00) >>  8; //Cut out green and shift it down.
b =  argb & 0x0000ff;        //Cut out blue.
RGB[i] = (r + g + b) / 3;    //gray = mean of r+g+b
Histogram[RGB[i]]++;         //Increment the histogram bar no. RGB[i].
}
//Normalisation: Scale the tallest bar of the histogram to height = 100.
Int32 max = 0;
for ( int gray=0; gray < 256; gray++ ) //maximum finder
if ( Histogram[gray] > max ) max = Histogram[gray];
float factor = 100f / max; //normalisation factor
for ( int gray=0; gray < 256; gray++ )
Histogram[gray] = Convert.ToInt32(Histogram[gray] * factor);
HistogramCanvas.Children.Clear(); //throw away any former graphics.
//Draw 256 vertical bars on the canvas.
for ( int gray=0; gray < 256; gray++ )
{ Line line = new Line(); line.X1 = line.X2 = gray;
line.Y1 = 100; line.Y2 = 100 - Histogram[gray];
line.Stroke = brush; line.StrokeThickness = 1;
}
}```

# Explanations

1. The pixels `img0[i]` are 32-bit integers carrying 4 bytes.
2. The leftmost byte carries the opacity value (0 = totally transparent, 255 = totally opaque),
the next bytes carry red-, green- and blue.
3. The opacity byte is always `0xff`. The color bytes must be cut out by 3 bit-masks `0x00ff0000, 0x0000ff00, 0x000000ff`.
4. The masked red value has to be shifted 16 bits to the right and the green has to be shifted 8 bits.
5. `RGB[i] = (r + g + b) / 3;` averages the three colors to a single brightness value,
that `Histogram[RGB[i]]++;` sums up.
• ## The Code of the Color Histograms

```WriteableBitmap img0, img1; //input+output images
Int32 xSize, ySize; //image width+height
Int32[,] Histogram = new Int32[3,256]; //3 histograms
Brush[] brush = { new SolidColorBrush( Colors.Red   ), //3 brushes
new SolidColorBrush( Colors.Green ),
new SolidColorBrush( Colors.Blue  ) };
Int32[] threshold = { 255, 255, 255 }; //3 thresholds
Int32[] R; //intermediary array for red
Int32[] G; //intermediary array for green
Int32[] B; //intermediary array for blue
Canvas[] canvas = new Canvas; //3 areas to draw lines
private void ComputeColorHistogram()
{ for ( int color=0; color < 3; color++ )
for ( int gray=0; gray < 256; gray++ ) Histogram[color,gray] = 0; //clear
for ( int i=0; i < xSize*ySize; i++ ) //for all Int32-pixels
{ Int32 argb = img0.Pixels[i]; //local variables
R[i] = (argb & 0xff0000) >> 16; //Cut out red   and shift it down.
G[i] = (argb & 0x00ff00) >>  8; //Cut out green and shift it down.
B[i] =  argb & 0x0000ff;        //Cut out blue.
Histogram[0,R[i]]++;         //Increment the histogram bar no. R[i].
Histogram[1,G[i]]++;         //Increment the histogram bar no. G[i].
Histogram[2,B[i]]++;         //Increment the histogram bar no. B[i].
}
//Scale the tallest bar of the histogram to height = 100.
Int32 max = 0;
for ( int color=0; color < 3; color++ )
for ( int gray=0; gray < 256; gray++ )
if ( Histogram[color,gray] > max ) max = Histogram[color,gray];
float factor = 100f / max;
for ( int color=0; color < 3; color++ )
{ for ( int gray=0; gray < 256; gray++ )
Histogram[color,gray] = Convert.ToInt32(Histogram[color,gray] * factor);
canvas[color].Children.Clear(); //Throw away any former canvas content.
//Draw 256 vertical bars on the canvas.
for ( int gray=0; gray < 256; gray++ )
{ Line line = new Line(); line.X1 = line.X2 = gray;
line.Y1 = 100; line.Y2 = 100 - Histogram[color,gray];
line.Stroke = brush[color]; line.StrokeThickness = 1;
}
}
}```

# Explanations

1. The pixels `img0[i]` are 32-bit integers carrying 4 bytes.
2. The leftmost byte carries the opacity value (0 = totally transparent, 255 = totally opaque),
the next bytes carry red-, green- and blue.
3. The opacity byte is always `0xff`. The color bytes must be cut out by 3 bit-masks `0x00ff0000, 0x0000ff00, 0x000000ff`.
4. The masked red value has to be shifted 16 bits to the right and the green has to be shifted 8 bits.
5. `R[i], G[i], B[i]` store the color planes for further use in thresholding,
and `Histogram[0,R[i]]++;` and sums up the first (red) histogram.

******************************************************************************
Q: What is a histogram H ? Purpose ?
A: An array H: int, where element H[g] contains the no. of pixels carrying the gray value g.
It shows the statistical distribution of brightness values of a picture and basic image properties such as exposure, contrast, color proportions.
******************************************************************************
Q: Pseudo-code of a histogram `H` of a black-and-white image `I[width*height]` ?
A: `for (int i=0; i < width*height; i++) H[I[i]]++;`
******************************************************************************
Q: Pseudo-code of 3 histograms `Red, Green, Blue` of a color image `I[width*height]` ?
A:
```for (int i=0; i < width*height; i++) { Red  [red   byte of I[i]]++;   Green[green byte of I[i]]++;   Blue [blue  byte of I[i]]++; }```
******************************************************************************
Q: What is the histogram `H` of the following 5x4-image ? Check the result !
```  0 1 0 2 0   2 7 8 9 1   0 6 5 7 1   1 3 2 3 0```
A: `H = [ 5, 4, 3, 2, 0, 1, 1, 2, 1, 1 ]`
Check: `5+4+3+2+0+1+1+2+1+1 = 20 = 5*4`
******************************************************************************
Q: Samples of frequent and famous histograms ?
A: ******************************************************************************
Q: What is histogram normalisation ?
A: Linear upset of the (normally huge) maximal value of the array to a fixed value e.g. 100.
******************************************************************************
Q: How to compute a cumulative histogram ?
A: `for (i=0; i < gray; i++) CumulativeHistogram[gray] += Histogram[i];`
******************************************************************************
Q: What is binarisation ? Pseudo-code of thresholding ?
A: Reducing a black-and-white image to just two gray values e.g. 0 and 255.
`If ( pixel < threshold ) pixel = black; else pixel = white;`
******************************************************************************