Friday 3 July 2015

How to draw Histogram of an Image/ Method of doing Histogram equalisation /Importance of Histogram Equalisation and Its Advantages

This opencv tutorial is about  histogram equalization along with the  significance of a histogram equalized image.

In the last article you might have wondered how to draw the histogram of an image. 
What does histogram equalization actually mean and the underlying algorithms by which it is done.Simply said, a histogram is a bar graph of raw data that creates a picture of the data distribution. 

Or in other words histogram describes the distribution of the pixel element in the image.

Importance of Histogram:

  • It helps us to get a better view of photographs that are over or under-exposed.
E.g. We can obtain the better view of bone structure in X-ray image.

  • Secondly it helps us to adjust the contrast of the image.

Understanding Histograms:
For a Binary image:
Pixel value of 0 indicates dark image.
Pixel value of 1 indicates bright image.

For a Gray scale image:
Pixel value of 0 indicates dark.
Pixel value of 255 indicates bright.

Thus we can say that when there are more dark pixels in the image, they would show up on the left hand side.
And the lighter pixels will show up on the right hand side of the histogram.
Dark Exposure Image:
Dark Exposure Image OpenCV
Dark Exposure Image Histogram:
Dark Exposure Image Histogram OpenCV

Light Exposure Image:
Light Exposure Image OpenCV
Dark Exposure Image Histogram:
Light Exposure Image Histogram OpenCV

Now you all might be thinking what do all these observations conclude to?
·        Well, if most of the pixels are found on the left hand side of your image, it is most likely that your image is under-exposed and will be too dark and lack details in the shadow areas.
·        If the majority of the pixels are found on the right hand side then the photo is most likely to be over-exposed and will be too light with little or no detail in bright parts of the image.


An image with low contrast will generally have a sharp peak on the histogram while an image with more contrast will have a more a rounded peak.

Low Contrast Image:
Low Contrast Image OpenCV
Low Contrast Image Histogram:
Low Contrast Image Histogram OpenCV
_________________________________________________________

High Contrast Image:
High Contrast Image OpenCv
High Contrast Image Histogram:
High Contrast Image Histogram OpenCV



Note: There is nothing called as perfect histogram. The right histogram of one scene may be not right for the other scene.

e.g. A photo of the moon in the night where almost all the pixels are on the left hand side of the histogram though the image was properly exposed.
Concept of histogram Calculation:
E.g.: Consider the following matrix of an image :-
5
2
4
0
5
2
4
2
4
1
2
3
1
4
1
7
1
4
0
1
2
3
2
7
4
7
3
7
2
6
7
5
2
7
4
5
2
3
7
4
3
1
3
1
1
6
7
3
4
4
0
0
0
6
7
2
6
2
2
0
0
3
0
3
2
6
7
2
0
0
0
7

Plot the table of the pixel value and the frequency of its occurrence:
Pixel Value
(Grey Levels)
No. Of Pixels
(nk)
0
11
1
8
2
14
3
9
4
10
5
4
6
5
7
11

Calculate

  1. The probability of occurrence of each pixel (PrRk).
  2.  Its cumulative density function (PrSk).
  3. Cumulative density function multiplied by the Gray levels minus 1.
  4. Finally rounding off the calculated value to get the new grey levels.
Grey Levels
nk
PrRk
(nk/Total)
PrSk
PrSk * (L-1)
Final

0
11
0.15278
0.15278
1.06946
1
1
8
0.11111
0.26389
1.84723
2
2
14
0.19444
0.45833
3.20831
3
3
9
0.125
0.58333
4.08331
4
4
10
0.13889
0.72222
5.05554
5
5
4
0.05555
0.77778
5.44446
5
6
5
0.06944
0.84722
5.93054
6
7
11
0.15278
1
7
7
Total
72






Old Grey Levels
nk
New Grey Levels
New nk
Modified Grey Levels
0
11
1
11
0-->1
1
8
2
8
1-->2
2
14
3
14
2-->3
3
9
4
9
3 -->4
4
10
5
14
4 -->5
5
4
5
14
5 -->5
6
5
6
5
6 -->6
7
11
7
11
7 -->7

New Grey Levels
 New nk
0
0
1
11
2
8
3
14
4
9
5
14
6
5
7
11


Original Histogram

Histogram Equalized

Here is the opencv code for histogram equalisation: 
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
 
using namespace std;
using namespace cv;
 
void imhist(Mat image, int histogram[])
{
 
    // initialize all intensity values to 0
    for(int i = 0; i < 256; i++)
    {
        histogram[i] = 0;
    }
 
    // calculate the no of pixels for each intensity values
    for(int y = 0; y < image.rows; y++)
        for(int x = 0; x < image.cols; x++)
            histogram[(int)image.at<uchar>(y,x)]++;
}
     
void histDisplay(int histogram[], const char* name)
{
    int hist[256];
    for(int i = 0; i < 256; i++)
    {
        hist[i]=histogram[i];
    }
    // draw the histograms
    int hist_w = 512; int hist_h = 400;
    int bin_w = cvRound((double) hist_w/256);
 
    Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(255, 255, 255));
 
    // find the maximum intensity element from histogram
    int max = hist[0];
    for(int i = 1; i < 256; i++){
        if(max < hist[i]){
            max = hist[i];
        }
    }

    // normalize the histogram between 0 and histImage.rows
    for(int i = 0; i < 256; i++)
 {
        hist[i] = ((double)hist[i]/max)*histImage.rows;
    }
 
 
    // draw the intensity line for histogram
    for(int i = 0; i < 256; i++)
    {
        line(histImage, Point(bin_w*(i), hist_h), Point(bin_w*(i), hist_h - hist[i]),Scalar(0,0,0), 1, 8, 0);
    }
 
    // display histogram
    namedWindow(name, CV_WINDOW_AUTOSIZE);
    imshow(name, histImage);
}
 
int main()
{
    // Load the image
    Mat image = imread("C:\\Users\\arjun\\Desktop\\input.jpg", CV_LOAD_IMAGE_GRAYSCALE);
 
    // Generate the histogram
    int histogram[256];
    imhist(image, histogram);
 
    // Calculate the size of image
    int size = image.rows * image.cols;

    // Calculate the probability of each intensity
    float PrRk[256];
    for(int i = 0; i < 256; i++)
    {
        PrRk[i] = (double)histogram[i] / size;
    }
 
    // Generate the equalized histogram
    float PsSk[256];
    for(int i = 0; i < 256; i++)
    {
        PsSk[i] = 0;
    }
 
    for(int i = 0; i < 256; i++)
  for(int j=0; j<=i; j++)
          PsSk[i] += PrRk[j];

    int final[256];
    for(int i = 0; i < 256; i++)
        final[i] = cvRound(PsSk[i]*255);

 for(int i = 0; i < 256; i++)
  for(int j=0; j<=255; j++)
          if (final[i]==final[j] && i!=j)
           {
           final[i]+=final[j];
        } 

 int final1[256];
    for(int i = 0; i < 256; i++)
 {
  final1[i]=0;
 }
  
    for(int i = 0; i < 256; i++)
 {
        final1[cvRound(PsSk[i]*255)] =cvRound(PrRk[i]*size);
 }

    for(int i = 0; i < 256; i++)
  for(int j=0; j<256; j++)
          if (final1[i]==final[j] && i!=j)
           {
          final1[i]+=final1[j];
          cout<<"final1["<<i<<"]="<<final1[i]<<endl;
        }

    // Generate the equlized image
    Mat new_image = image.clone();

    for(int y = 0; y < image.rows; y++)
        for(int x = 0; x < image.cols; x++)
            new_image.at<uchar>(y,x) = saturate_cast<uchar>(final[image.at<uchar>(y,x)]);
 
   // Display the original Image
    namedWindow("Original Image");
    imshow("Original Image", image);
 
    // Display the original Histogram
    histDisplay(histogram, "Original Histogram");

    // Display the equilzed histogram
    histDisplay(final1, "Equilized Histogram");

    // Display equilized image
    namedWindow("Equilized Image");
    imshow("Equilized Image",new_image);

    waitKey(0);
    return 0;
}
Opencv Input Image:
Image Before Histogram Equalization OpenCV

Histogram Equalised Image:
Image After Histogram Equalization OpenCV

Opencv Input Image Histogram:
Histogram of Image
Opencv Equalised Histogram:
Histogram Equalized OpenCV

No comments:

Post a Comment