3
votes

I have what should be a simple exercise in OpenCV, but can't seem to get it working. I'm trying to determine the density of edges in a section of an image. This is the process I follow: 1. pull subimage from image 2. use Canny to find edges in subImage 3. threshold to create binary image 4. create histogram for binary image 5. get number of pixels in binary image that are "on" (255) 6. calculate "edge density" as numPixelsOn/totalPixels

I've checked the results of 1,2,and 3 above, and results seem ok. Steps 4 and 5 seem to be giving me trouble.

Here's my code for calculating the histogram:

      int histSize = 256; // bin size
      float range[] = { 0, 256} ;
      const float* histRange = { range };

      bool uniform = true;
      bool accumulate = false;

      Mat hist;

      /// Compute the histograms:
      calcHist( &gray, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );

This doesn't seem to be working. When I check hist after calling calcHist, it has no data (i.e. data == 0)... or maybe I don't understand what I'm looking at.

Now for accessing the "bins" in the histogram, I've tried a number of things. First I tried this:

  uchar* p;
  p = hist.ptr<uchar>(0);
  double edgePixels = p[255];

I also tried to use:

cvQueryHistValue_1D(hist,255); // #include <opencv2/legacy/compat.hpp>

This wouldn't compile. Gave 2 errors: 'cv::Mat' does not have an overloaded member 'operator ->', and 'bins': is not a member of 'cv::Mat'

I guess I need some help on this.

1
why do you need a histogram? isn't it easier just traverse the gradient image or just use sum(I)/255 to get number of pixels that are on? Finally, using Canny is not a good idea since it is highly non-linear and thus poorly repeatable operator. It is better to use a simple Sobel summing sqrt(hor_grad^2+ver_grad^2) to get a better measure of edgeness.Vlad
@Vlad - Thanks for the advice. Although I appreciate getting the help on histograms, your comments make sense. I don't totally understand your comment about how to use Sobel for getting a better measure of "edgeness". Are you suggesting that I simply use the cv::Sobel function rather than cv::Canny? Thanks again!Bryan Greenway
I suggested that you use absolute values (either sum or sqrt of sum of squares) as an estimate of the absolute gradient. It is faster and more stable than Canny. The latter performs tons of non-linear operations and thus is not very repeatable and not very good for matching if you need these properties. On the flip side it is sensitive even to weak continues edges.Vlad

1 Answers

5
votes

There is an error in your 3rd param - channels, that should be an array so you should call it like this

 int histSize = 256; // bin size
 float range[] = { 0, 256} ;
 const float* histRange = { range };

 bool uniform = true;
 bool accumulate = false;

 Mat hist;

 int channels[] = {0};

 /// Compute the histograms:
 calcHist( &gray, 1, channels, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );

You should also call:

hist.at<float>(0);

to get your value, OpenCV stores them as floats, this is the reason you're getting 0 when using uchar as uchar is smaller than float and the numbers stores as small enough to not fill the first bites.