我需要像entropyfilt()
matlab 这样的函数,它在opencv中不存在.
在matlab中,J = entropyfilt(I)
返回数组J,其中每个输出像素包含输入图像I中相应像素周围的9×9邻域的熵值.
我写了一个函数来用c ++实现它,foreach像素得到它的熵如下:
使用cvCalHist
适当设置的mask参数来获得图像ROI(这是一个9*9的矩形).
归一化直方图,使其总和等于1.
使用(香农)熵的公式.
我列出了下面的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;iwidth-1,i+4)-i); roi.height=(j-Max(0,j-4))+1+(Min(gray_src->height-1,j+4)-j); cvSetImageROI(const_cast (gray_src),roi); IplImage*gray_src_non_const=const_cast (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 (gray_src)); }
但是,代码太慢了.我在600*1200图像中测试它并且花费120秒,而在matlab中的entroyfilt只花费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; }
然后它只是:
entroy -= entropy_table[gray_frequency];
您也可以发现实现自己的histgram代码是一个胜利.例如,如果你有一个小内核,你可以跟踪你将使用哪些垃圾箱,只清除它们.但由于你使用的是81/256垃圾箱,这可能不值得.
另一个你可以加速的地方是borrder像素处理.您正在检查每个像素.但是如果你为边界像素和内部像素设置了单独的循环,则可以避免大量的max和min调用.
如果仍然不够快,您可以考虑在条纹上使用parallel_for.作为如何做到这一点的一个很好的例子,看看OpenCV的形态滤波器的源代码.