图像处理之基于采样距离变换算法
算法是别人提出来的,感兴趣可以搜索《Distance Transforms of Sampled Functions》
这篇论文,网上也有很多实现的代码,但是结构不是很好,而且很分散不是一个完整的
算法。所以我整理了一下,写成一个单独的类,只要简单调用一下即可出结果图片。
至于算法原理什么的,我真很难解释清楚,大致的思想是基于能量最小化的,分别
进行行与列的1D距离变变换采样。
运行结果:
算法代码:
package com.gloomyfish.image.transform;
import java.awt.image.BufferedImage;
import com.gloomyfish.filter.study.GrayFilter;
/**
*
* @author gloomyfish
*
*/
public class FastDistanceTransformAlg extends GrayFilter {
public final static double INF = 1E20;
private int backgroundColor = 0; // default black
public int getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
}
@Override
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
int width = src.getWidth();
int height = src.getHeight();
dest = super.filter(src, null);
//
int[] inPixels = new int[width*height];
float[] outPixels = new float[width*height];
getRGB( dest, 0, 0, width, height, inPixels );
int index = 0;
for(int row=0; row<height; row++) {
int tr = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
tr = (inPixels[index] >> 16) & 0xff;
if(tr == backgroundColor)
outPixels[index] = (float)INF;
else
outPixels[index] = 0;
}
}
// transform along columns
float[] f = new float[Math.max(width, height)];
for(int col=0; col<width; col++) {
for(int row=0; row<height; row++) {
index = row * width + col;
f[row] = outPixels[index];
}
float[] disColumns = distance1DTransform(f, height);
for(int row=0; row<height; row++) {
index = row * width + col;
outPixels[index] = disColumns[row];
}
}
// transform along rows
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
index = row * width + col;
f[col] = outPixels[index];
}
float[] disColumns = distance1DTransform(f, width);
for (int col = 0; col < width; col++) {
index = row * width + col;
outPixels[index] = disColumns[col];
}
}
// post sqrt calculation
int[] result = new int[width*height];
for(int row=0; row<height; row++) {
for(int col=0; col<width; col++) {
index = row * width + col;
int pc = clamp(Math.sqrt(outPixels[index]));
result[index] = (255 << 24) | (pc << 16) | (pc << 8) | pc;
}
}
setRGB( dest, 0, 0, width, height, result );
return dest;
}
public static int clamp(double c)
{
return c > 255 ? 255 : (c < 0 ? 0 : (int)c);
}
/**
* 1D distance transform using squared distance
*
* @param data
* @param n
* @return
*/
private float[] distance1DTransform(float[] f, int n)
{
float[] d = new float[n];
int[] v = new int[n];
double[] z = new double[n+1];
int k = 0;
v[0] = 0;
z[0] = -INF;
z[1] = +INF;
for (int q = 1; q <= n-1; q++) {
double s = ((f[q]+square(q))-(f[v[k]]+square(v[k])))/(2*q-2*v[k]);
while (s <= z[k]) {
k--;
s = ((f[q]+square(q))-(f[v[k]]+square(v[k])))/(2*q-2*v[k]);
}
k++;
v[k] = q;
z[k] = s;
z[k+1] = +INF;
}
k = 0;
for (int q = 0; q <= n-1; q++) {
while (z[k+1] < q)
k++;
d[q] = (float)square(q-v[k]) + f[v[k]];
}
return d;
}
private double square(double v)
{
return v*v;
}
}
2013年的最后一篇!谢谢一直关注的各位!