Porikli F. Integral histogram: A fast way to extract histograms in cartesian spaces[C]//Computer Vision and Pattern Recognition, 2005. CVPR 2005. IEEE Computer Society Conference on. IEEE, 2005, 1: 829-836.
Download
这篇Paper中罗里吧嗦给出了一种积分图的快速算法(请原谅我的肤浅,只看懂了灰度特征的积分图),示意图如下:
他这个公式太高深,咱们就肤浅一点,假如只看灰度特征,意思就是
如果要求从 (i,j) 到 (i+m,j+n) 两个像素构成的矩形区域的直方图,只需再以上积分图的基础上(此处有误,待修改)
即可,非常方便,适用于大量的需要求取局部直方图的场合
但是,仔细看看那个求积分图的过程发现,其实不用分成4部分来进行,只需要2部分就可以了,那就是
(⊙v⊙)嗯,看着还不错哦,貌似一下子简化了很多恩。
为什么会是这样呢,,,
想想看,一副 M×N 的图片,从左至右,从上到下的计算积分图,每个像素需要做: 2次加法和一个减法(不考虑第一行和第一列像素) ,即复杂度 O(3×M×N)
再看看那个所谓的改进的快速算法,每个像素需要做: 2次加法(不考虑第一行像素) ,即复杂度 O(2×M×N)
有问题么??????
有,你把ColumnSum的计算复杂度给吃啦?
这样,把ColumnSum也按照积分图的思想做成累积的形式,,,那么计算ColumnSum的复杂度为 O(M×N) ,为什么是这样?因为你计算ColumnSum是个累计列和的向量啊,长度为 N ,图像总共 M 行,没一行时ColumnSum总得更新吧,,,,
那么那个所谓的改进的快速算法复杂度时多少?
答: O(3×M×N)
那么下面编程实现,并测试一下:
/** * @brief Compute the integral map (The Original Method) * @param pImg * @param width * @param height * @param integmap */
void integralMap(unsigned char *pImg, int width, int height, int *integmap)
{
int index,sum;
unsigned char *pCur,*pEnd;
int *piCur;
memset(integmap,0,sizeof(int)*width*height);
//第一行
for(sum=0,pCur=pImg,pEnd=pImg+width,piCur=integmap;pCur<pEnd;pCur++,piCur++)
{
sum+=*pCur;
*piCur=sum;
}
//第一列
for(sum=0,pCur=pImg,pEnd=pImg+width*height,piCur=integmap;pCur<pEnd;pCur+=width,piCur+=width)
{
sum+=*pCur;
*piCur=sum;
}
for(sum=0,index=0,pCur=pImg+width+1,pEnd=pImg+width*height,piCur=integmap+width+1;pCur<pEnd;)
{
*piCur=*pCur+*(piCur-1)+*(piCur-width)-*(piCur-width-1);
index++;
if(index == width-1)
{
piCur+=2;
pCur+=2;
index=0;
}
else
{
pCur++;
piCur++;
}
}
return;
}
/** * @brief Compute the integral map (The So-Fast Method) * @param pImg * @param width * @param height * @param integmap */
void integralMapFast(unsigned char *pImg, int width, int height, int *integmap)
{
unsigned char *pCur,*pEnd;
int *piCur;
int *colsum,*pc;
int i,sum;
colsum = (int*)malloc(sizeof(int)*width);
memset(colsum,0,sizeof(int)*width);
memset(integmap,0,sizeof(int)*width*height);
//第一行
for(sum=0,pCur=pImg,pEnd=pImg+width,piCur=integmap,pc=colsum;pCur<pEnd;pCur++,piCur++,pc++)
{
*pc=*pCur;
sum+=*pCur;
*piCur=sum;
}
for(i=0,pCur=pImg+width,pEnd=pImg+width*height,piCur=integmap+width,pc=colsum;pCur<pEnd;pCur++,piCur++,pc++)
{
if(!i)
{
*pc+=*pCur;
*piCur=*pc;
}
else
{
*pc+=*pCur;
*piCur=*pc+*(piCur-1);
}
i++;
if(i==width)
{
i=0;
pc=colsum;
}
}
free(colsum);
return;
}
下面是测试结果(我用到Ubuntu,可以精确到微秒):
可以看出来,那个所谓的改进的快速算法并不快,反而还要慢,,因为需要为ColumnSum分配空间,还要对其寻址,,,,这都是额外的系统开销,慢是必然的,,,