In attempt to recognize objects by examining images, various Image processing and analysis techniques are applied. This article briefly describes linear stretch algorithm and its use within OpenCV.
Linear stretch technique can be applied to images where substantial lack of contrast can result in false identification of objects, its spacial relationship and significance. Contrast enhancement by linear stretch can be applied to images with very low or very high variations of brightness. To apply the Linear stretch algorithm an image needs to be converted into gray-scale and all 8bit pixels and its values are recorded into histogram.
Histogram will contain all 256 grey-levels ( 0 – 255 ) in so called bins and each pixel value will take place in the bin represented with its own value. When the histogram and the image is created, maximum ( OMAX ) and minimum ( OMIN ) values are identified.
Linear stretch is applied to the histogram as follows:
- create a histogram of the original image
- set new maximum ( NMAX ) and new minimum ( NMIN ) values
- calculate number of bins in the original histogram where value of bins = ( OMAX – OMIN )
- calculate spacing for a new histogram so space = ( NMAX – NMIN ) / ( OMAX – OMIN )
- create a new histogram with corresponding positions for new bins ( Nb ) represented by
- use new histogram to create new image
The previous formula can be represented by simplified version of c++ code as follows:
#include <iostream> using namespace std; int main() { const int NMIN = 0; const int NMAX = 255; const int OMIN = 60; const int OMAX = 65; int space = ( NMAX - NMIN ) / ( OMAX - OMIN ) ; int bins = ( OMAX - OMIN ); for ( int j = 0; j <= bins; j++ ) { std::cout << j + OMIN << ": " << NMIN + ( j * space ) << endl; } return 0; }
COMPILE:
g++ bins.cpp -o bins
OUTPUT:
60: 0 61: 51 62: 102 63: 153 64: 204 65: 255
The c++ code above is really simplified version of the linear stretch algorithm. In the next section we are going use OpenCV library to do this task.
Using OpenCV library we can take advantage of cvNormalize function. This function takes at minimum five arguments ( original image, new image, NMIN, NMAX and normalization type ). The following OpenCV c++ code takes sample image as a single argument. The following c++ code will apply cvNormalize function to a sample image and create histogram for original as well as normalized image.
#include "cv.h" #include "highgui.h" void create_histogram_image(IplImage*, IplImage*); int main( int argc, char** argv ) { //load color image specified by first argument IplImage *source = cvLoadImage( argv[1]); // create new image structure // for the grayscale output image IplImage *gray_img = cvCreateImage( cvSize( source->width, source->height ), IPL_DEPTH_8U, 1 ); // set type CV_RGB2GRAY to convert // RGB image to grayscale cvCvtColor( source, gray_img, CV_RGB2GRAY ); // create new image structure // to hold histogram image IplImage *hist_img = cvCreateImage(cvSize(300,240), 8, 1); cvSet( hist_img, cvScalarAll(255), 0 ); // create new image structure // to hold stretched output image IplImage *stretched_img = cvCreateImage( cvSize( source->width, source->height ), IPL_DEPTH_8U, 1 ); // create new image structure // to hold histogram image IplImage *stretched_hist_img = cvCreateImage(cvSize(300,240), 8, 1); cvSet( stretched_hist_img, cvScalarAll(255), 0 ); // create new image structure // to hold stretched output image IplImage *equalized_img = cvCreateImage( cvSize( source->width, source->height ), IPL_DEPTH_8U, 1 ); // cvNormalize function call to apply linear stretch cvNormalize(gray_img, stretched_img, 0, 255, CV_MINMAX); // create histogram of the original image create_histogram_image(gray_img, hist_img); // create histogram of the new image. create_histogram_image(stretched_img, stretched_hist_img); // display all images cvNamedWindow( "Original Gray-scale Image", 1 ); cvShowImage( "Original Gray-scale Image",gray_img); cvNamedWindow( "Stretched Gray-scale Image", 1 ); cvShowImage( "Stretched Gray-scale Image",stretched_img); cvNamedWindow( "Gray-scale Image Histogram", 1 ); cvShowImage( "Gray-scale Image Histogram",hist_img); cvNamedWindow( "Stretched Image Histogram", 1 ); cvShowImage( "Stretched Image Histogram",stretched_hist_img); // wait indefinitely for keystroke cvWaitKey(0); return 0; } void create_histogram_image(IplImage* gray_img, IplImage* hist_img) { CvHistogram *hist; int hist_size = 256; float range[]={0,256}; float* ranges[] = { range }; float max_value = 0.0; float w_scale = 0.0#000000;">; // create array to hold histogram values hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1); // calculate histogram values cvCalcHist( &gray_img, hist, 0, NULL ); // Get the minimum and maximum values of the histogram cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 ); // set height by using maximim value cvScale( hist->bins, hist->bins, ((float)hist_img->height)/max_value, 0 ); // calculate width w_scale = ((float)hist_img->width)/hist_size; // plot the histogram for( int i = 0; i < hist_size; i++ ) { cvRectangle( hist_img, cvPoint((int)i*w_scale , hist_img->height), cvPoint((int)(i+1)*w_scale, hist_img->height - cvRound(cvGetReal1D(hist->bins,i))), cvScalar(0), -1, 8, 0 ); } }
COMPILE:
g++ `pkg-config opencv --cflags --libs` normalize.cpp -o normalize
EXECUTE:
./normalize sample.png
OUTPUT:
sample.png ( original RGB image )
In the next step we have converted RGB image to a gray-scale:
using cvNormalize we have applied linear stretch:
Now we can compare histograms of both images.
Histogram of the original gray-scale image:
Histogram of the new stretched image: