【发布时间】:2014-02-20 12:52:37
【问题描述】:
我试图了解super fast blur algorithm 背后的算法。下面是与 android 一起工作的 java 端口作为测试。貌似这个版本做了一些我不太明白的优化,也没有任何cmets。
void fastblur(Bitmap img, int radius){
if (radius<1){
return;
}
int w= img.getWidth();
int h=img.getHeight();
int wm=w-1;
int hm=h-1;
int wh=w*h;
int div=radius+radius+1;
int r[]=new int[wh];
int g[]=new int[wh];
int b[]=new int[wh];
int rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw;
int vmin[] = new int[Math.max(w,h)];
int vmax[] = new int[Math.max(w,h)];
int[] pix= new int[w*h];
img.getPixels(pix, 0, w, 0,0,w, h);
int dv[]=new int[256*div];
for (i=0;i<256*div;i++){
dv[i]=(i/div);
}
yw=yi=0;
for (y=0;y<h;y++){
rsum=gsum=bsum=0;
for(i=-radius;i<=radius;i++){
p=pix[yi+Math.min(wm,Math.max(i,0))];
rsum+=(p & 0xff0000)>>16;
gsum+=(p & 0x00ff00)>>8;
bsum+= p & 0x0000ff;
}
for (x=0;x<w;x++){
r[yi]=dv[rsum];
g[yi]=dv[gsum];
b[yi]=dv[bsum];
if(y==0){
vmin[x]=Math.min(x+radius+1,wm);
vmax[x]=Math.max(x-radius,0);
}
p1=pix[yw+vmin[x]];
p2=pix[yw+vmax[x]];
rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
yi++;
}
yw+=w;
}
for (x=0;x<w;x++){
rsum=gsum=bsum=0;
yp=-radius*w;
for(i=-radius;i<=radius;i++){
yi=Math.max(0,yp)+x;
rsum+=r[yi];
gsum+=g[yi];
bsum+=b[yi];
yp+=w;
}
yi=x;
for (y=0;y<h;y++){
pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
if(x==0){
vmin[y]=Math.min(y+radius+1,hm)*w;
vmax[y]=Math.max(y-radius,0)*w;
}
p1=x+vmin[y];
p2=x+vmax[y];
rsum+=r[p1]-r[p2];
gsum+=g[p1]-g[p2];
bsum+=b[p1]-b[p2];
yi+=w;
}
}
img.setPixels(pix,0, w,0,0,w,h);
}
如果我的猜测有误,请纠正我:
下面的循环是做什么的?它与预先计算内核表有关吗?那么 div 呢,是内核表的大小吗?我想我想问的是, dv[] 应该存储什么?
int dv[]=new int[256*div];
for (i=0;i<256*div;i++){
dv[i]=(i/div);
}
看水平传球:
下面的循环看起来像是在汇总单独的 RGB 值,但它只在每一行的起始像素处执行此操作,因为 yi 仅在我们完成处理所有像素直到达到宽度后才会增加。这是因为我们在下一个循环中处理像素时最终会添加到 RGB 总和?
for(i=-radius;i<=radius;i++){
int ind = yi+Math.min(wm,Math.max(i,0));
p=pix[ind];
rsum+=(p & 0xff0000)>>16;
gsum+=(p & 0x00ff00)>>8;
bsum+= p & 0x0000ff;
}
我们只是根据半径和当前像素位置选择最左边的像素和最右边的像素吗?
if(y==0){
vmin[x]=Math.min(x+radius+1,wm);
vmax[x]=Math.max(x-radius,0);
}
p1=pix[yw+vmin[x]];
p2=pix[yw+vmax[x]];
接下来最让我困惑的是: 我是否正确地说得到了左右像素之间的差异并添加了我们拥有的正在运行的 RGB 总数?
rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
我还没有看第二遍,因为这几乎超出了我的想象。任何澄清将不胜感激,任何关于垂直传球循环的评论也会有所帮助,谢谢。
【问题讨论】:
-
我认为同样的算法在这里描述得更恰当blog.ivank.net/fastest-gaussian-blur.html