Chamfer Distance Transform in image processing is often used in object matching recognition. The algorithm basically generates the distance value of each pixel based on a 3x3 window, and is divided into two steps to complete the distance transformation. The first step starts from the upper left corner, scans each pixel from the left to the right, from top to bottom, and detects four pixels around the center pixel x, and saves the minimum distance and position as the result. The figure is as follows:
The second step is to detect the minimum distance and position of adjacent pixels 4, 5, 6, 7 from the bottom to the right to the left, as the result, for each pixel:
After completing these two steps, the result output is the result of the chamfer distance transformation. The complete image chamfer distance transformation code implementation can be divided into the following steps:
1. Initialize the pixel array, the initial distance of all background color pixels is infinite, and the distance of the foreground pixels is 0.
2. Start the first step in chamfer distance transformation and save the result
3. Complete the second step in chamfer distance transformation based on the results of the first step
4. Display all different grayscale values according to the distance transformation results to form an image
The final result is displayed as follows (the left indicates the original image and the right indicates the result after CDT)
The source code for the complete binary image chamfer distance transformation is as follows:
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); // Randomly generated distance transformation point 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, TB for (rows = 1; rows < height - 1; rows++) { for (cols = 1; cols < width - 1; cols++) { 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, BT // 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 = d2 + dis[in]) < nd) { nd = nd_tmp; nearestPixel = pos[in]; } in += -1; // 6 if ((nd_tmp = d2 + dis[in]) < nd) { nd = nd_tmp; nearestPixel = pos[in]; } in += -1; // 6 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); } }The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.