在opencv中寻找熵 [英] Finding entropy in opencv

查看:99
本文介绍了在opencv中寻找熵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在matlab中使用类似entropyfilt()的功能,而该功能在opencv中不存在.

I need a function like entropyfilt() in matlab, which doesn't exists in opencv.

在matlab中,J = entropyfilt(I)返回数组J,其中每个输出像素包含输入图像I中相应像素周围的9×9邻域的熵值.

In matlab, J = entropyfilt(I) returns the array J, where each output pixel contains the entropy value of the 9-by-9 neighborhood around the corresponding pixel in the input image I.

我写了一个函数用c ++实现,因为每个像素都像这样获得其熵:

I wrote a function to implement it in c++, foreach pixel get its entropy like this:

  1. 使用cvCalHist并适当设置mask参数以获得图像ROI(这是一个9 * 9矩形).
  2. 对直方图进行归一化,以便其bin的总和等于1.
  3. 使用(香农)熵的公式.
  1. Use cvCalHist with the mask parameter appropriately set to get image ROI (That's a 9*9 rectangle).
  2. Normalize the histogram so the sum of its bins is equal to 1.
  3. Use the formula for (Shannon) entropy.

我在下面列出了C ++代码:

I list the C++ code below:

GetLocalEntroyImage( const IplImage*gray_src,IplImage*entopy_image){
    int hist_size[]={256};
    float gray_range[]={0,255};
    float* ranges[] = { gray_range};
    CvHistogram * hist = cvCreateHist( 1, hist_size, CV_HIST_SPARSE, ranges,1);
    for(int i=0;i<gray_src.width;i++){
            for(int j=0;j<gray_src.height;j++){
                //calculate entropy for pixel(i,j) 
                //1.set roi rect(9*9),handle edge pixel
                CvRect roi;
                int threshold=Max(0,i-4);
                roi.x=threshold;
                threshold=Max(0,j-4);
                roi.y=threshold;
                roi.width=(i-Max(0,i-4))+1+(Min(gray_src->width-1,i+4)-i);
                roi.height=(j-Max(0,j-4))+1+(Min(gray_src->height-1,j+4)-j);
                cvSetImageROI(const_cast<IplImage*>(gray_src),roi);
                IplImage*gray_src_non_const=const_cast<IplImage*>(gray_src);                            

                //2.calHist,here I chose CV_HIST_SPARSE to speed up
                cvCalcHist( &gray_src_non_const, hist, 0, 0 );*/
                cvNormalizeHist(hist,1.0);
                float total=0;
                float entroy=0;

               //3.get entroy
                CvSparseMatIterator it;
                for(CvSparseNode*node=cvInitSparseMatIterator((CvSparseMat*)hist-   >bins,&it);node!=0;node=cvGetNextSparseNode(&it)){
                float gray_frequency=*(float*)CV_NODE_VAL((CvSparseMat*)hist->bins,node);
                entroy=entroy-gray_frequency*(log(gray_frequency)/log(2.0f));//*(log(gray_frequency)/log(2.0))
                }
                ((float*)(local_entroy_image->imageData + j*local_entroy_image->widthStep))[i]=entroy;
                cvReleaseHist(&hist);
            }
        }
        cvResetImageROI(const_cast<IplImage*>(gray_src));
    }

但是,代码太慢.我在600 * 1200的图片中对其进行了测试,它的成本为120s,而在matlab中的entroyfilt仅需5s.

有人知道如何加快速度或知道其他任何良好的实现方式吗??

推荐答案

代码中最大的问题是:log(gray_frequency)/log(2.0f)).

The big slow down in your code is this: log(gray_frequency)/log(2.0f)).

您不应致电cvNormalizeHist().您知道bin的总和为81,因此只需从计算出的熵中减去81 * log(81)/log(2)(当然,这是一个常数,并非每次循环都计算得出).如果不对直方图进行规范化,则直方图的条目将为整数,您可以使用它们来访问查找表.

You should not call cvNormalizeHist(). You know the bins are going to sum to 81, so just subtract 81 * log(81)/log(2) from the calculated entropy (but of course that is a constant not calcualted every time in your loop). If you don't normalize the hisgram, its entries will be integers and you can use them to access a lookup table.

由于您具有9x9内核,因此gray_frequency的最大值为81(只要您不对直方图进行标准化),就可以通过一次对预先计算的表的查找来轻松替换对log()的这两个调用.这将产生巨大的变化.您可以像这样初始化一个表:

Since you have a 9x9 kernel the maximum value of gray_frequency is 81 (as long as you don't normalize the histogram) and you can easily replace those two calls to log() by a single lookup of a precalculated table. This will make a huge difference. You can initialize a table like this:

    double entropy_table[82]; // 0 .. 81
    const double log2 = log(2.0);
    entropy_table[0] = 0.0;
    for(int i = 1; i < 82; i ++)
    {
        entropy_table[i] = i * log(double(i)) / log2;
    }

那么以后就是:

entroy -= entropy_table[gray_frequency];

此外,您可能会发现实现自己的直方图代码是一个胜利.例如.如果您的内核较小,则可以跟踪要使用的垃圾箱,并仅清除它们.但是,由于您使用的是81/256档,这可能不值得.

Also you may find implementing your own histgram code is a win. E.g. if you have a small kernel you can keep track of which bins you are going to use and only clear those. But since you are using 81/256 bins this mightn't be worth it.

您可以提高速度的另一个地方是处理波特像素.您正在检查每个像素.但是,如果对边界像素和内部像素有单独的循环,则可以避免多次调用max和min.

Another place you can get a speed up is in borrder pixel handling. You are checking this for every pixel. But oif you had separate loops for the boarder pixels and the inner pixels a re lot of calls to max and min could be avoided.

如果仍然不够快,则可以考虑在条带上使用parallel_for.作为一个很好的例子,请看一下OpenCV形态过滤器的源代码.

If that still isn't fast enough, you may consider using parallel_for on stripes. As a good example on how to do that, have a look at the source code for OpenCV's morphological filter.

这篇关于在opencv中寻找熵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆