领域均值平滑在计算均值时,领域内的所有像素都是一样的权重。表面模糊给领域中心像素,也就是要计算的像素位置的原像素最大权重,其他像素和中心像素的差值越大,则权重越小。网上给出的PhotoShop的表面模糊公式为
我看到的时候很奇怪为什么要加上一个2.5参数。后来才发现,原来这种公式在实际使用中还需要判断1-|xi-x1|/(2.5Y) 是否大于0,如果小于0不参与计算。我想在这里加2.5倍参数就是为了对于大多数像素值,这个公式大于0(对于8位256个色阶)。在领域平滑的实现中,大多使用一些优化的算法,比如O(1)复杂度的直方图更新算法(可以参考http://www.cnblogs.com/Imageshop/p/5995093.html)。在领域直方图中,可以很容易的限制只计算在中心像素左右阀值范围以内的像素,也就是可以保证|xi-x1|<=Y。这样,就可以把2.5去掉,同时也去掉判断1-|xi-x1|/(2.5Y)是否大于0,因为1-|xi-x1|/Y始终是大于等于0。再把整个式子乘以256,做整数定点计算,避免浮点计算。
low = cen - threshold; if (low < 0) low = 0; high = cen + threshold; if (high > 255) high = 255; for (i = low; i <= high; i++) { int delta = i - cen;
weight = (256 - (ABS(delta) * 256) / threshold)*Hist[i]; sum += weight * i; divisor += weight; } return BYTE(sum / divisor);
另外,再把256-256|xi-x1|/Y提前计算好放在数组中,计算时直接查表,也加快了速度。而且也不用计算i从-255到255,只需要计算i从-threshold到threshold的数组。另外还有一点注意,如果领域半径限制最大127,则领域中的像素数最大255*255。这里sum如果用long类型,有可能溢出。用unsigned long就没问题了。如果领域半径还要增大,就要用更大的64位整数类型了。