entropy is a measure of the uncertainty associated with a random variable.
basically i want to get a single value representing the entropy of an image.
1. Assign 255 bins for the range of values between 0-255
2. separate the image into its 3 channels
3. compute histogram for each channel
4. normalize all 3 channels unifirmely
5. for each channel get the bin value (Hc) and use its absolute value (negative log is infinity)
6. compute Hc*log10(Hc)
7. add to entropy and continue with 5 until a single value converges
5. get the frequency of each channel - add all the values of the bin
6. for each bin get a probability -
if bin 1 = 20
bin 2 = 30
then frequency is 50 and probability is 20/50 and 30/50
then compute using shannon formula
REFERENCE: http://people.revoledu.com/kardi/tutorial/DecisionTree/how-to-measure-impurity.htm
class atsHistogram
{
public:
cv::Mat DrawHistogram(Mat src)
{
/// Separate the image in 3 places ( R, G and B )
vector<Mat> rgb_planes;
split( src, rgb_planes );
/// Establish the number of bins
int histSize = 255;
/// Set the ranges ( for R,G,B) )
float range[] = { 0, 255 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat r_hist, g_hist, b_hist;
/// Compute the histograms:
calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histograms for R, G and B
int hist_w = 400; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
/// Normalize the result to [ 0, histImage.rows ]
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// Draw for each channel
/*for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}*/
double entropy = (double)computeShannon(r_hist,g_hist,b_hist);
//printf("Entropy: %f" , entropy );
cout << entropy << endl;
return histImage;
}
float getHistogramBinValue(Mat hist, int binNum)
{
//return cvRound(hist.at<float>(binNum));
return hist.at<float>(binNum);
}
float computeShannon(Mat r, Mat g, Mat b)
{
int histSize = 255; //number of bins
float entropy = 0.0;
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(r,i));
//cout << "Red " << Hc << endl;
entropy += Hc * log10(Hc);
//cout << "-" << Hc << " -n- " << entropy << endl;
}
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(g,i));
//cout << "Green " << Hc << endl;
entropy += Hc * log10(Hc);
}
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(b,i));
//cout << "Blue " << Hc << endl;
entropy += Hc * log10(Hc);
}
entropy = entropy * -1;
//cout << entropy <<endl;
return entropy;
}
private:
};
basically i want to get a single value representing the entropy of an image.
1. Assign 255 bins for the range of values between 0-255
2. separate the image into its 3 channels
3. compute histogram for each channel
4. normalize all 3 channels unifirmely
5. get the frequency of each channel - add all the values of the bin
6. for each bin get a probability -
if bin 1 = 20
bin 2 = 30
then frequency is 50 and probability is 20/50 and 30/50
then compute using shannon formula
REFERENCE: http://people.revoledu.com/kardi/tutorial/DecisionTree/how-to-measure-impurity.htm
float getHistogramBinValue(Mat hist, int binNum)
{
return hist.at<float>(binNum);
}
float getFrequencyOfBin(Mat channel)
{
float frequency = 0.0;
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(channel,i));
frequency += Hc;
}
return frequency;
}
float computeShannonEntropy(Mat r, Mat g, Mat b)
{
float entropy = 0.0;
float frequency = getFrequencyOfBin(r);
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(r,i));
entropy += -(Hc/frequency) * log10((Hc/frequency));
}
frequency = getFrequencyOfBin(g);
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(g,i));
entropy += -(Hc/frequency) * log10((Hc/frequency));
}
frequency = getFrequencyOfBin(b);
for( int i = 1; i < histSize; i++ )
{
float Hc = abs(getHistogramBinValue(b,i));
entropy += -(Hc/frequency) * log10((Hc/frequency));
}
entropy = entropy;
//cout << entropy <<endl;
return entropy;
}
Can we use this as a way to measure contrast?
ReplyDeletewhen i try run your example code the program show me this error:
ReplyDeleteD:\Adrian\Mis Programas\Image_work\Image_Work\image_work.cpp:181: error: no matching function for call to 'calcHist(cv::Mat*&, int, int, cv::Mat, cv::Mat&, int, int*, const float*&, bool&, bool&)'
can you help me?
calcHist() function expects the first argument to be 'Mat*' instead of 'Mat' .
DeleteTry this function. It worked fine for me.
/****************************************************
Method to calculate entropy of an image
****************************************************/
double entropy(Mat *img)
{
int numBins = 256, nPixels;
float range[] = {0, 255};
double imgEntropy = 0 , prob;
const float* histRange = { range };
Mat histValues;
//calculating the histogram
calcHist(img, 1, 0, Mat(), histValues, 1, &numBins, &histRange, true, true );
nPixels = sum(histValues)[0];
for(int i = 1; i < numBins; i++)
{
prob = histValues.at(i)/nPixels;
if(prob < FLT_EPSILON)
continue;
imgEntropy += prob*(log(prob)/log(2));
}
return (0-imgEntropy);
}
/**************************************************************************************/
Before calling the function, you should split the image into channels using 'split()' function and pass the address of the channel of your choice.
Hope this helps you.
Hello, I tried the code above but somehow I get negative entropy. Am I wrongly implemented the code?
Deletesorry, i work with QtCreator. This it's a recommendation that Qt give me.
ReplyDeletenote: void cv::calcHist(const cv::Mat*, int, const int*, const cv::_InputArray&, cv::SparseMat&, int, const int*, const float**, bool, bool)
how i can change the parameters of this function to my program run correctly?
how i can give input image above function...and i gives error to me
ReplyDelete