fbpx

Histogram and Equalization

Basically, an image histogram is a plot of the relative frequency of occurrence of each of the permitted pixel values in the image against the values themselves.

 If we normalize such a frequency plot, so that the total sum of all frequency entries over the permissible range is one, we may treat the image histogram as a discrete probability density function which defines the likelihood of a given pixel value occurring within the image.

Visual inspection of an image histogram can reveal the basic contrast that is present in the image and any potential differences in the color distribution of the image foreground and background scene components.

For a simple grey-scale image, the histogram can be constructed by simply counting the number of times each grey-scale value (mean each value from 0  to 255) occurs within the image.

This image here clearly describes an image histogram.

On the x axis we have the numbering from zero to 255. This represents 256 greyscale levels present in the image.

From this image we can see that greyscale level zero occurred just one in the image there there is just one star showing at zero. We can see that greyscale level 2 occurred 3 times in the image hence we have three stars at level 2.

Normally the image histogram is not showed with stars. But rather bins, or vertical lines and height of the vertical line represents the occurrence of the particular greyscale level.

Over here we have a sample image and its corresponding historgram.

Here we can  see a histogram plot with two distinctive peaks: a high peak in the lower range of pixel values corresponds to the background intensity distribution of the image and a lower peak in the higher range of pixel values (these are the bright pixels) and they corresponds to the foreground objects which the coins.

Here we have a histogram of a more complex scene. Here it more difficult to differentiate the background bins or vertical line from the foreground bins.In a case such as this we might have to use a more sophisticated image segmentation method accurate separate the background from the foreground. This is all there is for this lesson. In the next lesson we shall look at histogram equalization. I will see you in the next lesson. If you have any questions just send me a message or leave them in the questions area.

Introduction to histogram equalization

Let’s begin by taking a look at this image over here.

As we can see, this image has a very poor contrast.

We can tell this from the image itself as well as from its histogram shown below. The histogram shows the grey levels grouped in the dark half of the scale. This is picture a residential area with lawns.

Here we are the roads. Over here and over here.

There are trees in a bushes in the lawn but we cannot see them because their grey levels are too close to the grey levels of the grass.

To solve this issue we must perform histogram equalization. Equalization causes a histogram with a bins grouped closely together to “spread out” into a flat or equalized histogram. Spreading or flattening the histogram makes the dark pixels appear darker and the light pixels appear lighter

The key word here is appear. The dark pixels in this picture cannot be any darker. If, however, the pixels that are only slightly lighter become much lighter, then the dark pixels will appear darker. We must also  note that histogram equalization does not operate on the histogram itself. Rather, histogram equalization uses the results of one histogram to transform the original image into an image that will have an equalized histogram.

This equation over here represents the equalization operation, where c is an image with a poor histogram. The as yet unknown function f transforms the image c into an image b with a flat histogram. This next equation shows the probability-density function of a pixel value “a”.  “p1(a)” is the probability of finding a pixel with the value “a” in the image. “Area-1” is the area or number of pixels in the image and H1(a) is the histogram of the image

This is what the image will look like after we have histogram equalization

Over here also we have two images, the original and what is produced after histogram equalization.

As we can see the equalized version has better contrast and we can also see that the bins are spread out.

c++ code : ImageProcessing.cpp

#include "ImageProcessing.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

ImageProcessing::ImageProcessing(
                                 const char *_inImgName,
                                 const char *_outImgName,
                                 int * _height,
                                 int * _width,
                                 int * _bitDepth,
                                 unsigned char * _header,
                                 unsigned char * _colorTable,
                                 unsigned char * _inBuf,
                                 unsigned char * _outBuf

                                 )
{
    inImgName  = _inImgName;
    outImgName = _outImgName;
    height     = _height;
    width      = _width;
    bitDepth   = _bitDepth;
    header     = _header;
    colorTable = _colorTable;
    inBuf      = _inBuf;
    outBuf     = _outBuf;
}


void ImageProcessing::readImage()
{

    int i;
    FILE *streamIn;
    streamIn = fopen(inImgName,"rb");
    if(streamIn ==(FILE *)0)
    {
        cout<<"Unable to open file. Maybe file does not exist"<<endl;
        exit(0);
    }
    for(i=0;i<BMP_HEADER_SIZE;i++)
    {
        header[i] =  getc(streamIn);
    }
    *width = *(int *)&header[18];           //read the width from the image header
    *height = *(int *)&header[22];
    *bitDepth = *(int *)&header[28];

    if(*bitDepth <=8)
    {

        fread(colorTable,sizeof(unsigned char),BMP_COLOR_TABLE_SIZE,streamIn);
    }

    fread(inBuf,sizeof(unsigned char),_512by512_IMG_SIZE,streamIn );

    fclose(streamIn);
}

void ImageProcessing::writeImage(){

    FILE  *fo = fopen(outImgName,"wb");
    fwrite(header,sizeof(unsigned char),BMP_HEADER_SIZE,fo);
    if(*bitDepth <=8)
    {
        fwrite(colorTable,sizeof(unsigned char),BMP_COLOR_TABLE_SIZE,fo);
    }

   fwrite(outBuf, sizeof(unsigned char),_512by512_IMG_SIZE,fo);
   fclose(fo);
}

void ImageProcessing ::copyImgData(unsigned char *_srcBuf, unsigned char *_destBuf, int bufSize)
{
    for(int i =0;i<bufSize;i++)
    {
        _destBuf[i] = _srcBuf[i];
    }
}

void ImageProcessing::binarizeImage(unsigned char *_inImgData, unsigned char *_outImgData, int imgSize, int threshold)
{
    for(int i=0;i<imgSize;i++)
    {
        _outImgData[i] =  (_inImgData[i] > threshold) ? WHITE :BLACK;
    }
}
void ImageProcessing::brigthnessUp(unsigned char *_inputImgData, unsigned char *_outImgData, int imgSize, int brightness)
{

    for(int i =0;i<imgSize;i++)
    {
        int temp = _inputImgData[i]+ brightness;
        _outImgData[i] =  (temp > MAX_COLOR)? MAX_COLOR :temp;
    }
}

void ImageProcessing::brigthnessDown(unsigned char *_inputImgData, unsigned char *_outImgData, int imgSize, int darkness)
{
     for(int i =0;i<imgSize;i++)
     {
         int temp = _inputImgData[i] - darkness;
         _outImgData[i] = (temp<MIN_COLOR) ? MIN_COLOR :temp;
     }
}

void ImageProcessing::computeHistogram(unsigned char * _imgData, int imgRows, int imgCols, float hist[])
{
    FILE *fptr;
    fptr =fopen("image_hist.txt","w");

    int x,y,i,j;
    long int ihist[255],sum;
    for(i =0;i<=255;i++)
    {
        ihist[i] =0;
    }
    sum =0;
    for(y=0;y<imgRows;y++)
    {
        for(x=0;x<imgCols;x++)
        {
            j = *(_imgData+x+y*imgCols);
            ihist[j] = ihist[j] +1;
            sum = sum+1;
        }

    }
    for(i=0;i<255;i++)
        hist[i] =  (float)ihist[i]/(float)sum;
  for(int i=0;i<255;i++)
    {
        fprintf(fptr,"\n%f",hist[i]);
    }
    fclose(fptr);
}

ImageProcessing::~ImageProcessing()
{
    //dtor
}


main.cpp

#include <iostream>
#include "ImageProcessing.h"

using namespace std;

int main()
{
    float imgHiSt[NO_OF_GRAYLEVELS];

    int imgWidth, imgHeight, imgBitDepth;
    unsigned char imgHeader[BMP_HEADER_SIZE];
    unsigned char imgColorTable[BMP_COLOR_TABLE_SIZE];
    unsigned char imgInBuffer[_512by512_IMG_SIZE];
    unsigned char imgOutBuffer[_512by512_IMG_SIZE];

    const char imgName[] ="images/lena512.bmp";
    const char newImgName[] ="images/blank.bmp";

    ImageProcessing *myImage  = new ImageProcessing(imgName,
                                                    newImgName,
                                                    &imgHeight,
                                                    &imgWidth,
                                                    &imgBitDepth,
                                                    &imgHeader[0],
                                                    &imgColorTable[0],
                                                    &imgInBuffer[0],
                                                    &imgOutBuffer[0]
                                                    );

     myImage->readImage();
     myImage->computeHistogram(imgInBuffer,imgHeight,imgWidth,imgHiSt);


     cout<<"Success !"<<endl;
     cout<<"Image Height : "<<imgHeight<<endl;
     cout<<"Image Width  : "  <<imgWidth<<endl;

    return 0;
}

ImageProcessing.h

#ifndef IMAGEPROCESSING_H
#define IMAGEPROCESSING_H

 static const int   _512by512_IMG_SIZE  = 262144; // 512*512
 static const int   BMP_COLOR_TABLE_SIZE= 1024;
 static const int   BMP_HEADER_SIZE     = 54;
 static const int   MAX_COLOR           = 255;
 static const int   MIN_COLOR           =  0;
 static const int   WHITE               =  MAX_COLOR;
 static const int   BLACK               =  MIN_COLOR;
 static const int   NO_OF_GRAYLEVELS     = 255;

class ImageProcessing
{
    public:
        ImageProcessing(
                                 const char *_inImgName,
                                 const char *_outImgName,
                                 int * _height,
                                 int * _width,
                                 int * _bitDepth,
                                 unsigned char * _header,
                                 unsigned char * _colorTable,
                                 unsigned char * _inBuf,
                                 unsigned char * _outBuf

                                 );

        void readImage();
        void writeImage();
        void copyImgData(unsigned char *_srcBuf, unsigned char *_destBuf, int bufSize);
        void binarizeImage(unsigned char *_inImgData, unsigned char *_outImgData, int imgSize, int threshold);
        void brigthnessUp(unsigned char *_inputImgData, unsigned char *_outImgData, int imgSize, int brightness);
        void brigthnessDown(unsigned char *_inputImgData, unsigned char *_outImgData, int imgSize, int darkness);
        void computeHistogram(unsigned char * _imgData, int imgRows, int imgCols, float hist[]);

        virtual ~ImageProcessing();

    protected:

    private:
        const char *inImgName;
        const char *outImgName;
        int * height;
        int * width;
        int * bitDepth;
        unsigned char * header;
        unsigned char * colorTable;
        unsigned char * inBuf;
        unsigned char * outBuf;
};

#endif // IMAGEPROCESSING_H

Add Comment

Your email address will not be published. Required fields are marked *

Phone: +447491265055
W12 7JN, London, United Kingdom
34A Frithville Gardens
Style switcher RESET
Body styles
Color settings
Link color
Menu color
User color
Background pattern
Background image