我需要像entropyfilt()matlab 这样的函数,它在opencv中不存在.
在matlab中,J = entropyfilt(I)返回数组J,其中每个输出像素包含输入图像I中相应像素周围的9×9邻域的熵值.
我写了一个函数来用c ++实现它,foreach像素得到它的熵如下:
cvCalHist适当设置的mask参数来获得图像ROI(这是一个9*9的矩形).我列出了下面的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秒.
有谁知道如何加快它或知道任何其他良好的实施?
你的代码中的大缓慢是这样的: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的形态滤波器的源代码.