图像处理中的倒角距离变换(chamfer distance transform)在对象匹配识别中经常用到,算法基本上是基于3x3的窗口来生成每个像素的距离值,分为两步完成距离变换,第一步从左上角开始,从左向右、从上到下移动窗口扫描每个像素,检测在中心像素x的周围0、1、2、3四个像素,保存最小距离与位置作为结果,图示如下:
第二步从底向上、从右向左,对每个像素,检测相邻像素4、5、6、7保存最小距离与位置作为结果,如图示所:
完成这两步以后,得到的结果输出即为倒角距离变换的结果。完整的图像倒角距离变换代码实现可以分为如下几步:
1.对像素数组进行初始化,所有背景颜色像素点初始距离为无穷大,前景像素点距离为0
2.开始倒角距离变换中的第一步,并保存结果
3.基于第一步结果完成倒角距离变换中的第二步
4.根据距离变换结果显示所有不同灰度值,形成图像
最终结果显示如下(左边表示原图、右边表示cdt之后结果)
完整的二值图像倒角距离变换的源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
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); // 随机生成距离变换点 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); } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/jia20003/article/details/42620499