java圖像處理之倒角距離變換
圖像處理中的倒角距離變換(Chamfer Distance Transform)在對象匹配識(shí)別中經(jīng)常用到,算法基本上是基于3x3的窗口來生成每個(gè)像素的距離值,分為兩步完成距離變換,第一步從左上角開始,從左向右、從上到下移動(dòng)窗口掃描每個(gè)像素,檢測在中心像素x的周圍0、1、2、3四個(gè)像素,保存最小距離與位置作為結(jié)果,圖示如下:

第二步從底向上、從右向左,對每個(gè)像素,檢測相鄰像素4、5、6、7保存最小距離與位置作為結(jié)果,如圖示所:

完成這兩步以后,得到的結(jié)果輸出即為倒角距離變換的結(jié)果。完整的圖像倒角距離變換代碼實(shí)現(xiàn)可以分為如下幾步:
1.對像素?cái)?shù)組進(jìn)行初始化,所有背景顏色像素點(diǎn)初始距離為無窮大,前景像素點(diǎn)距離為0
2.開始倒角距離變換中的第一步,并保存結(jié)果
3.基于第一步結(jié)果完成倒角距離變換中的第二步
4.根據(jù)距離變換結(jié)果顯示所有不同灰度值,形成圖像
最終結(jié)果顯示如下(左邊表示原圖、右邊表示CDT之后結(jié)果)

完整的二值圖像倒角距離變換的源代碼如下:
package com.gloomyfish.image.transform;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import com.gloomyfish.filter.study.AbstractBufferedImageOp;
public class CDTFilter extends AbstractBufferedImageOp {
private float[] dis; // nn-distances
private int[] pos; // nn-positions, 32 bit index
private Color bakcgroundColor;
public CDTFilter(Color bgColor)
{
this.bakcgroundColor = bgColor;
}
@Override
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
int width = src.getWidth();
int height = src.getHeight();
if (dest == null)
dest = createCompatibleDestImage(src, null);
int[] inPixels = new int[width * height];
pos = new int[width * height];
dis = new float[width * height];
src.getRGB(0, 0, width, height, inPixels, 0, width);
// 隨機(jī)生成距離變換點(diǎn)
int index = 0;
Arrays.fill(dis, Float.MAX_VALUE);
int numOfFC = 0;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
index = row * width + col;
if (inPixels[index] != bakcgroundColor.getRGB()) {
dis[index] = 0;
pos[index] = index;
numOfFC++;
}
}
}
final float d1 = 1;
final float d2 = (float) Math.sqrt(d1 * d1 + d1 * d1);
System.out.println(numOfFC);
float nd, nd_tmp;
int i, in, cols, rows, nearestPixel;
// 1 2 3
// 0 i 4
// 7 6 5
// first pass: forward -> L->R, T-B
for (rows = 1; rows < height - 1; rows++) {
for (cols = 1; cols < width - 1; cols++) {
i = rows * width + cols;
nd = dis[i];
nearestPixel = pos[i];
if (nd != 0) { // skip background pixels
in = i;
in += -1; // 0
if ((nd_tmp = d1 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += -width; // 1
if ((nd_tmp = d2 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += +1; // 2
if ((nd_tmp = d1 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += +1; // 3
if ((nd_tmp = d2 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
dis[i] = nd;
pos[i] = nearestPixel;
}
}
}
// second pass: backwards -> R->L, B-T
// exactly same as first pass, just in the reverse direction
for (rows = height - 2; rows >= 1; rows--) {
for (cols = width - 2; cols >= 1; cols--) {
i = rows * width + cols;
nd = dis[i];
nearestPixel = pos[i];
if (nd != 0) {
in = i;
in += +1; // 4
if ((nd_tmp = d1 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += +width; // 5
if ((nd_tmp = d2 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += -1; // 6
if ((nd_tmp = d1 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
in += -1; // 7
if ((nd_tmp = d2 + dis[in]) < nd) {
nd = nd_tmp;
nearestPixel = pos[in];
}
dis[i] = nd;
pos[i] = nearestPixel;
}
}
}
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
index = row * width + col;
if (Float.MAX_VALUE != dis[index]) {
int gray = clamp((int) (dis[index]));
inPixels[index] = (255 << 24) | (gray << 16) | (gray << 8)
| gray;
}
}
}
setRGB(dest, 0, 0, width, height, inPixels);
return dest;
}
private int clamp(int i) {
return i > 255 ? 255 : (i < 0 ? 0 : i);
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot多環(huán)境開發(fā)及使用方法
這篇文章主要介紹了Springboot多環(huán)境開發(fā)及多環(huán)境設(shè)置使用、多環(huán)境分組管理的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Java編程反射機(jī)制用法入門與實(shí)例總結(jié)
這篇文章主要介紹了Java編程反射機(jī)制用法,簡單說明了反射機(jī)制的概念、原理并結(jié)合實(shí)例形式總結(jié)分析了java反射機(jī)制的簡單使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-12-12
Java中BigDecimal除法使用不當(dāng)導(dǎo)致精度問題
本文主要介紹了Java中BigDecimal除法使用不當(dāng)導(dǎo)致精度問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
SpringBoot利用AOP實(shí)現(xiàn)一個(gè)日志管理詳解
目前有這么個(gè)問題,有兩個(gè)系統(tǒng)CSP和OMS,這倆系統(tǒng)共用的是同一套日志操作:Log;目前想?yún)^(qū)分下這倆系統(tǒng)的日志操作,那沒辦法了,只能重寫一份Log的日志操作。本文就將利用AOP實(shí)現(xiàn)一個(gè)日志管理,需要的可以參考一下2022-09-09
IDEA解決maven包沖突easypoi NoClassDefFoundError的問題
這篇文章主要介紹了IDEA解決maven包沖突easypoi NoClassDefFoundError的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10

