在opencv中查找熵

zhe*_*lee 5 matlab opencv

我需要像entropyfilt()matlab 这样的函数,它在opencv中不存在.

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

我写了一个函数来用c ++实现它,foreach像素得到它的熵如下:

  1. 使用cvCalHist适当设置的mask参数来获得图像ROI(这是一个9*9的矩形).
  2. 归一化直方图,使其总和等于1.
  3. 使用(香农)熵的公式.

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

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));
    }
Run Code Online (Sandbox Code Playgroud)

但是,代码太慢了.我在600*1200图像中测试它并且花费120秒,而在matlab中的entroyfilt只花费5秒.

有谁知道如何加快它或知道任何其他良好的实施

Bul*_*ull 5

你的代码中的大缓慢是这样的:log(gray_frequency)/log(2.0f)).

你不应该打电话cvNormalizeHist().你知道垃圾箱的总和会达到81,所以只需81 * log(81)/log(2)从计算的熵中减去(但当然这是一个常数,不是每次在你的循环中计算).如果你没有规范化hisgram,它的条目将是整数,你可以使用它们来访问查找表.

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

    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;
    }
Run Code Online (Sandbox Code Playgroud)

然后它只是:

entroy -= entropy_table[gray_frequency];
Run Code Online (Sandbox Code Playgroud)

您也可以发现实现自己的histgram代码是一个胜利.例如,如果你有一个小内核,你可以跟踪你将使用哪些垃圾箱,只清除它们.但由于你使用的是81/256垃圾箱,这可能不值得.

另一个你可以加速的地方是borrder像素处理.您正在检查每个像素.但是如果你为边界像素和内部像素设置了单独的循环,则可以避免大量的max和min调用.

如果仍然不够快,您可以考虑在条纹上使用parallel_for.作为如何做到这一点的一个很好的例子,看看OpenCV的形态滤波器的源代码.