使用 Emgu OpenCV 计算直方图

Posted

技术标签:

【中文标题】使用 Emgu OpenCV 计算直方图【英文标题】:Histogram computation with Emgu OpenCV 【发布时间】:2014-10-16 06:59:51 【问题描述】:

我想使用 Emgu 获取图像的直方图。

我有一个灰度双图像

Image<Gray, double> Crop;

我可以得到一个直方图使用

Image<Gray, byte> CropByte = Crop.Convert<Gray, byte>(); 
DenseHistogram hist = new DenseHistogram(BinCount, new RangeF(0.0f, 255.0f));
hist.Calculate<Byte>(new Image<Gray, byte>[]  CropByte , true, null);

问题是,这样做我需要转换为字节图像。这是有问题的,因为它扭曲了我的结果。如果可以使用双图像,这会给出与我得到的结果略有不同的直方图。

我已经尝试使用 CvInvoke 来使用内部 opencv 函数来计算直方图。

IntPtr[] x =  Crop ; 

DenseHistogram cropHist = new DenseHistogram  
( 
    BinCount,  
    new RangeF 
    (
        MinCrop,
        MaxCrop
    ) 
); 

CvInvoke.cvCalcArrHist(x, cropHist, false, IntPtr.Zero); 

问题是我很难找到正确使用这个功能的方法

emgu/opencv 允许我这样做吗?我需要自己编写函数吗?

【问题讨论】:

【参考方案1】:

这不是 EmguCV/OpenCV 问题,这个想法本身没有意义,因为双直方图需要比可用内存更多的内存。当您分配有固定大小的直方图时,我所说的是正确的。解决这个问题的唯一方法是在处理图像时使用动态分配的直方图。但这对于大图像会很危险,因为它可以分配与图像本身一样多的内存。

我猜你的双重图像包含许多相同的值,否则直方图不会很有用。因此,解决此问题的一种方法是将您的值重新映射为短(16 位)而不是字节(8 位),这样您的直方图将与您对双精度值的期望非常相似。

【讨论】:

我为每个直方图计算设置了 bin 的数量(BinCount)。如果它们足够接近,不同的像素值将被分组到同一个 bin 中。我实际上是在使用论文中的一种方法来选择垃圾箱大小(和计数)。请参阅 David Scott 的“关于优化和基于数据的直方图”。由于我在视频上这样做,因此性能是一个问题。或许我还应该限制 bin 的数量,以避免您提到的内存分配问题。 只有当您需要应用其他 CPU 密集型算法同时保持视频实时时,您的潜在性能问题才会成为一个问题。如果将图像转换为短值,直方图将占用 2MB(每个 bin 使用 32 位 int),因此即使在智能手机上也不应该存在任何内存问题。【参考方案2】:

我查看了 opencv 源代码中的 histogram.cpp。

内部函数

void cv::calcHist( const Mat* images, int nimages, const int* channels,
                   InputArray _mask, OutputArray _hist, int dims, const int* histSize,
                   const float** ranges, bool uniform, bool accumulate )

有一个部分处理不同的图像类型

if( depth == CV_8U )
        calcHist_8u(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
    else if( depth == CV_16U )
        calcHist_<ushort>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
    else if( depth == CV_32F )
        calcHist_<float>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
    else
        CV_Error(CV_StsUnsupportedFormat, "");

虽然这里还没有处理双图像,但浮动是。

虽然浮点从 double 中损失了一点精度,但这并不是一个严重的问题。

以下代码 sn-p 对我来说效果很好

Image<Gray, float> CropByte = Crop.Convert<Gray, float>(); 
DenseHistogram hist = new DenseHistogram(BinCount, new RangeF(0.0f, 255.0f));
hist.Calculate<float>(new Image<Gray, float>[]  CropByte , true, null);

【讨论】:

以上是关于使用 Emgu OpenCV 计算直方图的主要内容,如果未能解决你的问题,请参考以下文章

使用Python,Opencv进行二维直方图的计算及绘制

使用Python,OpenCV计算图像直方图(cv2.calcHist)

OpenCV 学习(计算图像的直方图)

详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0

OpenCV 直方图计算

利用OpenCV的函数calcHist()计算出图像的直方图数据后绘制图像的直方图