Skip to main content

Computing Entropy of an image (CORRECTED)

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:
};

     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;
    }

Comments

  1. Can we use this as a way to measure contrast?

    ReplyDelete
  2. when i try run your example code the program show me this error:

    D:\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?

    ReplyDelete
    Replies
    1. calcHist() function expects the first argument to be 'Mat*' instead of 'Mat' .

      Try 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.

      Delete
    2. Hello, I tried the code above but somehow I get negative entropy. Am I wrongly implemented the code?

      Delete
  3. sorry, i work with QtCreator. This it's a recommendation that Qt give me.

    note: 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?

    ReplyDelete
  4. how i can give input image above function...and i gives error to me

    ReplyDelete

Post a Comment

Popular posts from this blog

Artificial Intelligence (K Nearest Neighbor) in OPENCV

In pattern recognition , the k -nearest neighbor algorithm ( k -NN) is a method for classifying objects based on closest training examples in the feature space . k -NN is a type of instance-based learning , or lazy learning where the function is only approximated locally and all computation is deferred until classification. The k -nearest neighbor algorithm is amongst the simplest of all machine learning algorithms: an object is classified by a majority vote of its neighbors, with the object being assigned to the class most common amongst its k nearest neighbors ( k is a positive integer , typically small). If k = 1, then the object is simply assigned to the class of its nearest neighbor. The k -NN algorithm can also be adapted for use in estimating continuous variables. One such implementation uses an inverse distance weighted average of the k -nearest multivariate neighbors. This algorithm functions as follows: Compute Euclidean or Mahalanobis distance from target plo

Blob Detection, Connected Component (Pure Opencv)

Connected-component labeling (alternatively connected-component analysis, blob extraction, region labeling, blob discovery, or region extraction) is an algorithmic application of graph theory, where subsets of connected components are uniquely labeled based on a given heuristic. Connected-component labeling is not to be confused with segmentation. i got the initial code from this URL: http://nghiaho.com/?p=1102 However the code did not compile with my setup of OpenCV 2.2, im guessing it was an older version. so a refactored and corrected the errors to come up with this Class class atsBlobFinder     {     public:         atsBlobFinder()         {         }         ///Original Code by http://nghiaho.com/?p=1102         ///Changed and added commments. Removed Errors         ///works with VS2010 and OpenCV 2.2+         void FindBlobs(const cv::Mat &binary, vector < vector<cv::Point>  > &blobs)         {             blobs.clear();             // Fill the la