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 Histogram:
Light Exposure Image:
Dark Exposure Image Histogram:
Dark Exposure Image Histogram:
Light Exposure Image:
Dark Exposure Image Histogram:
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.
_________________________________________________________
High Contrast Image:
High Contrast Image Histogram:
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
- The
probability of occurrence of each pixel (PrRk).
- Its
cumulative density function (PrSk).
- Cumulative
density function multiplied by the Gray levels minus 1.
- 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
|
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 Equalised Histogram:
No comments:
Post a Comment