从OpenCV直方图中获取数值

3
我有一个在OpenCV中应该很简单的练习,但是似乎无法让它正常工作。 我正在尝试确定图像部分的边缘密度。 我按照以下步骤进行: 1. 从图像中提取子图像 2. 使用Canny查找子图像中的边缘 3. 阈值化以创建二进制图像 4. 为二进制图像创建直方图 5. 获取二进制图像中“开启”(255)的像素数量 6. 计算“边缘密度”的公式为numPixelsOn/totalPixels
我已经检查了以上1,2和3步骤的结果,结果似乎还可以。 但第4和第5步似乎让我感到困扰。
下面是计算直方图的代码:
      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 );

这似乎没有起作用。在调用calcHist之后检查hist时,它没有数据(即data == 0)...或者我不明白我正在看什么。

现在要访问直方图中的“bins”,我尝试了许多方法。首先我尝试了这个:

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

我也尝试使用:
cvQueryHistValue_1D(hist,255); // #include <opencv2/legacy/compat.hpp>

这段代码无法编译。出现了两个错误:'cv::Mat'没有可重载的成员'operator ->',和'bins'不是'cv::Mat'的成员。我需要一些帮助。

为什么需要直方图?直接遍历梯度图或使用sum(I)/255计算打开的像素数量不是更容易吗?最后,使用Canny算子并不是一个好主意,因为它是高度非线性和难以重复的运算符。最好使用简单的Sobel算子,对水平和垂直梯度进行平方和再开根号,以得到更好的边缘测量结果。 - Vlad
@Vlad - 感谢您的建议。虽然我很感激在直方图方面得到帮助,但是您的评论很有道理。我不完全理解您关于如何使用Sobel来获得更好的“边缘度量”的评论。您是建议我仅使用cv :: Sobel函数而不是cv :: Canny吗?再次感谢! - Bryan Greenway
我建议您使用绝对值(总和或平方和的平方根)作为绝对梯度的估计。这比Canny更快,更稳定。后者执行大量非线性操作,因此不太可重复且不太适合匹配,如果您需要这些属性的话。但另一方面,它甚至对于弱连续边缘都很敏感。 - Vlad
1个回答

5

您的第三个参数 - channels 存在错误,应该是一个数组,因此您应该这样调用它:

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

您还需要调用以下内容:

您还需要调用:

hist.at<float>(0);

为获取您的值,OpenCV将其存储为浮点数。这就是为什么在使用uchar时会得到0的原因,因为uchar比float小,且数字被存储为足够小以不填充第一个字节。


谢谢!完美通过检查。 - Bryan Greenway

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接