Zhang-Suen thinning algorithm
1
class ZhangSuen(str, black="1") {
2
const NEIGHBOURS = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]] # 8 neighbors
3
const CIRCULARS = (NEIGHBOURS + [NEIGHBOURS.first]) # P2, ... P9, P2
4
5
has r = 0
6
has image = [[]]
7
8
method init {
9
var s1 = str.lines.map{|line| line.chars.map{|c| c==black ? 1 : 0 }}
10
var s2 = s1.len.of { s1[0].len.of(0) }
11
var xr = range(1, s1.end-1)
12
var yr = range(1, s1[0].end-1)
13
do {
14
r = 0
15
xr.each{|x| yr.each{|y| s2[x][y] = (s1[x][y] - self.zs(s1,x,y,1)) }} # Step 1
16
xr.each{|x| yr.each{|y| s1[x][y] = (s2[x][y] - self.zs(s2,x,y,0)) }} # Step 2
17
} while !r.is_zero
18
image = s1
19
}
20
21
method zs(ng,x,y,g) {
22
(ng[x][y] == 0) ->
23
|| (ng[x-1][y] + ng[x][y+1] + ng[x+g][y+g - 1] == 3) ->
24
|| (ng[x+g - 1][y+g] + ng[x+1][y] + ng[x][y-1] == 3) ->
25
&& return 0
26
27
var bp1 = NEIGHBOURS.map {|p| ng[x+p[0]][y+p[1]] }.sum # B(P1)
28
return 0 if ((bp1 < 2) || (6 < bp1))
29
30
var ap1 = 0
31
CIRCULARS.map {|p| ng[x+p[0]][y+p[1]] }.each_cons(2, {|a,b|
32
++ap1 if (a < b) # A(P1)
33
})
34
35
return 0 if (ap1 != 1)
36
r = 1
37
}
38
39
method display {
40
image.each{|row| say row.map{|col| col ? '#' : ' ' }.join }
41
}
42
}
43
44
var text = <<EOS
45
00000000000000000000000000000000
46
01111111110000000111111110000000
47
01110001111000001111001111000000
48
01110000111000001110000111000000
49
01110001111000001110000000000000
50
01111111110000001110000000000000
51
01110111100000001110000111000000
52
01110011110011101111001111011100
53
01110001111011100111111110011100
54
00000000000000000000000000000000
55
EOS
56
57
ZhangSuen.new(text, black: "1").display
Copied!

Output:

1
####### ######
2
# # ##
3
# # #
4
# # #
5
##### # #
6
## #
7
# # ## ## #
8
# ####
Copied!
Last modified 1yr ago
Copy link
Contents
Output: