影像處理之倒角距離變換,影像處理倒角變換
影像處理之倒角距離變換
影像處理中的倒角距離變換(Chamfer Distance Transform)在對象匹配識別中經常用到,
演算法基本上是基於3x3的視窗來產生每個像素的距離值,分為兩步完成距離變換,第一
步從左上方開始,從左向右、從上到下移動視窗掃描每個像素,檢測在中心像素x的周
圍0、1、2、3四個像素,儲存最小距離與位置作為結果,圖示如下:
第二步從底向上、從右向左,對每個像素,檢測相鄰像素4、5、6、7儲存最小距離與
位置作為結果,示所:
完成這兩步以後,得到的結果輸出即為倒角距離變換的結果。完整的映像倒角距離變
換代碼實現可以分為如下幾步:
1. 對像素數組進行初始化,所有背景顏色像素點初始距離為無窮大,前景像素點距
離為0
2. 開始倒角距離變換中的第一步,並儲存結果
3. 基於第一步結果完成倒角距離變換中的第二步
4. 根據距離變換結果顯示所有不同灰階值,形成映像
最終結果顯示如下(左邊表示原圖、右邊表示CDT之後結果)
完整的二值映像倒角距離變換的原始碼如下:
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-distancesprivate int[] pos; // nn-positions, 32 bit indexprivate Color bakcgroundColor;public CDTFilter(Color bgColor){this.bakcgroundColor = bgColor;}@Overridepublic 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);// 隨機產生距離變換點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-Bfor (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 pixelsin = i;in += -1; // 0if ((nd_tmp = d1 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += -width; // 1if ((nd_tmp = d2 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += +1; // 2if ((nd_tmp = d1 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += +1; // 3if ((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 directionfor (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; // 4if ((nd_tmp = d1 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += +width; // 5if ((nd_tmp = d2 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += -1; // 6if ((nd_tmp = d1 + dis[in]) < nd) {nd = nd_tmp;nearestPixel = pos[in];}in += -1; // 7if ((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);}}
轉載請註明出處!!