September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -42,18 +42,23 @@ It produces the thinned output:
|
|||
;Algorithm:
|
||||
Assume black pixels are one and white pixels zero, and that the input image is a rectangular N by M array of ones and zeroes.
|
||||
|
||||
The algorithm operates on all black pixels P1 that can have eight neighbours. The neighbours are, in order, arranged as:
|
||||
<table border="1">
|
||||
<tr><td>P9</td><td>P2</td><td>P3</td></tr>
|
||||
<tr><td>P8</td><td><b>P1</b></td><td>P4</td></tr>
|
||||
<tr><td>P7</td><td>P6</td><td>P5</td></tr>
|
||||
The algorithm operates on all black pixels P1 that can have eight neighbours.
|
||||
|
||||
The neighbours are, in order, arranged as:
|
||||
|
||||
<table border="4">
|
||||
<tr><td> P9 </td><td> P2 </td><td> P3 </td></tr>
|
||||
<tr><td> P8 </td><td><b> P1 </b></td><td> P4 </td></tr>
|
||||
<tr><td> P7 </td><td> P6 </td><td> P5 </td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
Obviously the boundary pixels of the image cannot have the full eight neighbours.
|
||||
|
||||
* Define <math>A(P1)</math> = the number of transitions from white to black, (0 -> 1) in the sequence P2,P3,P4,P5,P6,P7,P8,P9,P2. (Note the extra P2 at the end - it is circular).
|
||||
* Define <math>B(P1)</math> = The number of black pixel neighbours of P1. ( = sum(P2 .. P9) )
|
||||
|
||||
|
||||
;Step 1:
|
||||
All pixels are tested and pixels satisfying all the following conditions (simultaneously) are just noted at this stage.
|
||||
* (0) The pixel is black and has eight neighbours
|
||||
|
|
@ -61,8 +66,10 @@ All pixels are tested and pixels satisfying all the following conditions (simult
|
|||
* (2) A(P1) = 1
|
||||
* (3) At least one of P2 and P4 and P6 is white
|
||||
* (4) At least one of P4 and P6 and P8 is white
|
||||
|
||||
After iterating over the image and collecting all the pixels satisfying all step 1 conditions, all these condition satisfying pixels are set to white.
|
||||
|
||||
|
||||
;Step 2:
|
||||
All pixels are again tested and pixels satisfying all the following conditions are just noted at this stage.
|
||||
* (0) The pixel is black and has eight neighbours
|
||||
|
|
@ -70,24 +77,29 @@ All pixels are again tested and pixels satisfying all the following conditions a
|
|||
* (2) A(P1) = 1
|
||||
* (3) At least one of P2 and P4 and '''P8''' is white
|
||||
* (4) At least one of '''P2''' and P6 and P8 is white
|
||||
|
||||
After iterating over the image and collecting all the pixels satisfying all step 2 conditions, all these condition satisfying pixels are again set to white.
|
||||
|
||||
|
||||
;Iteration:
|
||||
If any pixels were set in this round of either step 1 or step 2 then all steps are repeated until no image pixels are so changed.
|
||||
|
||||
|
||||
;Task:
|
||||
# Write a routine to perform Zhang-Suen thinning on an image matrix of ones and zeroes.
|
||||
# Use the routine to thin the following image and show the output here on this page as either a matrix of ones and zeroes, an image, or an ASCII-art image of space/non-space characters.
|
||||
<pre>00000000000000000000000000000000
|
||||
01111111110000000111111110000000
|
||||
01110001111000001111001111000000
|
||||
01110000111000001110000111000000
|
||||
01110001111000001110000000000000
|
||||
01111111110000001110000000000000
|
||||
01110111100000001110000111000000
|
||||
01110011110011101111001111011100
|
||||
01110001111011100111111110011100
|
||||
00000000000000000000000000000000</pre>
|
||||
|
||||
00000000000000000000000000000000
|
||||
01111111110000000111111110000000
|
||||
01110001111000001111001111000000
|
||||
01110000111000001110000111000000
|
||||
01110001111000001110000000000000
|
||||
01111111110000001110000000000000
|
||||
01110111100000001110000111000000
|
||||
01110011110011101111001111011100
|
||||
01110001111011100111111110011100
|
||||
00000000000000000000000000000000
|
||||
|
||||
|
||||
;Reference:
|
||||
* [http://nayefreza.wordpress.com/2013/05/11/zhang-suen-thinning-algorithm-java-implementation/ Zhang-Suen Thinning Algorithm, Java Implementation] by Nayef Reza.
|
||||
|
|
|
|||
1
Task/Zhang-Suen-thinning-algorithm/00META.yaml
Normal file
1
Task/Zhang-Suen-thinning-algorithm/00META.yaml
Normal file
|
|
@ -0,0 +1 @@
|
|||
--- {}
|
||||
|
|
@ -3,8 +3,6 @@ import system'routines.
|
|||
import extensions.
|
||||
import extensions'routines.
|
||||
|
||||
type charmatrix = matrix<CharValue>.
|
||||
|
||||
const image = (
|
||||
" ",
|
||||
" ################# ############# ",
|
||||
|
|
@ -31,9 +29,9 @@ nbrs = ((0, -1), (1, -1), (1, 0), (1, 1), (0, 1),
|
|||
nbrGroups = (((0, 2, 4), (2, 4, 6)), ((0, 2, 6),
|
||||
(0, 4, 6))).
|
||||
|
||||
charmatrix extension zhangsuenOp
|
||||
extension<Matrix<CharValue>> zhangsuenOp
|
||||
{
|
||||
$proceed : r : c : toWhite : firstStep
|
||||
proceed(r, c, toWhite, firstStep)
|
||||
[
|
||||
if (self[r][c] != $35)
|
||||
[ ^ false ].
|
||||
|
|
@ -54,7 +52,7 @@ charmatrix extension zhangsuenOp
|
|||
^ true.
|
||||
]
|
||||
|
||||
numNeighbors :r : c
|
||||
numNeighbors(r,c)
|
||||
[
|
||||
int count := 0.
|
||||
|
||||
|
|
@ -67,7 +65,7 @@ charmatrix extension zhangsuenOp
|
|||
^ count.
|
||||
]
|
||||
|
||||
numTransitions : r : c
|
||||
numTransitions(r,c)
|
||||
[
|
||||
int count := 0.
|
||||
|
||||
|
|
@ -85,7 +83,7 @@ charmatrix extension zhangsuenOp
|
|||
^ count.
|
||||
]
|
||||
|
||||
atLeastOneIsWhite : r : c : step
|
||||
atLeastOneIsWhite(r, c, step)
|
||||
[
|
||||
int count := 0.
|
||||
var group := nbrGroups[step].
|
||||
|
|
@ -114,13 +112,13 @@ charmatrix extension zhangsuenOp
|
|||
while (hasChanged || firstStep)
|
||||
[
|
||||
hasChanged := false.
|
||||
firstStep := firstStep not.
|
||||
firstStep := firstStep inverted.
|
||||
|
||||
1 till(self rows - 1) do(:r)
|
||||
[
|
||||
1 till(self columns - 1) do(:c)
|
||||
[
|
||||
if(self~zhangsuenOp $proceed(r,c,toWhite,firstStep))
|
||||
if(self proceed(r,c,toWhite,firstStep))
|
||||
[ hasChanged := true ].
|
||||
].
|
||||
].
|
||||
|
|
@ -144,21 +142,26 @@ charmatrix extension zhangsuenOp
|
|||
]
|
||||
}
|
||||
|
||||
program =
|
||||
public program
|
||||
[
|
||||
charmatrix grid := MatrixSpace::
|
||||
Matrix<CharValue> grid := MatrixSpace::
|
||||
{
|
||||
rows = image length.
|
||||
int rows = image length.
|
||||
|
||||
columns = image[0] length.
|
||||
int columns = image[0] length.
|
||||
|
||||
getAt int:i int:j
|
||||
getAt(int i, int j)
|
||||
= image[i][j].
|
||||
|
||||
setAt(int i, int j, object o)
|
||||
[
|
||||
image[i][j] := o.
|
||||
]
|
||||
}.
|
||||
|
||||
grid thinImage.
|
||||
|
||||
grid print.
|
||||
|
||||
console readChar.
|
||||
].
|
||||
console readChar
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ isBlackPx=: '1'&=;._2 NB. boolean array of black pixels
|
|||
toImage=: [: , LF ,.~ '01' {~ ] NB. convert to original representation
|
||||
frameImg=: 0 ,. 0 , >:@$ {. ] NB. adds border of 0's to image
|
||||
|
||||
neighbrs=: adverb define NB. applies verb u to neighbourhoods
|
||||
(1 1 ,: 3 3) u;._3 y
|
||||
)
|
||||
neighbrs=: 1 :'(1 1 ,: 3 3)&(u;._3)' NB. applies verb u to neighbourhoods
|
||||
|
||||
Bdry=: 1 2 5 8 7 6 3 0 1 NB. map pixel index to neighbour order
|
||||
getPx=: { , NB. get desired pixels from neighbourhood
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
constant DEBUG = 1;
|
||||
my $source = qq:to/EOD/;
|
||||
................................
|
||||
.#########.......########.......
|
||||
.###...####.....####..####......
|
||||
.###....###.....###....###......
|
||||
.###...####.....###.............
|
||||
.#########......###.............
|
||||
.###.####.......###....###......
|
||||
.###..####..###.####..####.###..
|
||||
.###...####.###..########..###..
|
||||
................................
|
||||
EOD
|
||||
|
||||
my @lines = ([.ords X+& 1] for lines); # The low bits Just Work.
|
||||
my @lines = ([.ords X+& 1] for $source.split("\n")); # The low bits Just Work.
|
||||
my \v = +@lines;
|
||||
my \h = +@lines[0];
|
||||
my @black = flat @lines.map: *.values; # Flatten to 1-dimensional.
|
||||
|
|
@ -30,11 +41,11 @@ repeat while my @goners1 or my @goners2 {
|
|||
|
||||
@goners1 = seewhite (0,2,4), (2,4,6);
|
||||
@black[@goners1] = 0 xx *;
|
||||
say "Ping: {[+] @black} remaining after removing ", @goners1 if DEBUG;
|
||||
say "Ping: {[+] @black} remaining after removing ", @goners1;
|
||||
|
||||
@goners2 = seewhite (0,2,6), (0,4,6);
|
||||
@black[@goners2] = 0 xx *;
|
||||
say "Pong: {[+] @black} remaining after removing ", @goners2 if DEBUG;
|
||||
say "Pong: {[+] @black} remaining after removing ", @goners2;
|
||||
}
|
||||
|
||||
say @black.splice(0,h).join.trans('01' => '.#') while @black;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
use List::Util qw(sum min);
|
||||
|
||||
$source = <<'END';
|
||||
............................................................
|
||||
..#################...................#############.........
|
||||
..##################...............################.........
|
||||
..###################............##################.........
|
||||
..########.....#######..........###################.........
|
||||
....######.....#######.........#######.......######.........
|
||||
....######.....#######........#######.......................
|
||||
....#################.........#######.......................
|
||||
....################..........#######.......................
|
||||
....#################.........#######.......................
|
||||
....######.....#######........#######.......................
|
||||
....######.....#######........#######.......................
|
||||
....######.....#######.........#######.......######.........
|
||||
..########.....#######..........###################.........
|
||||
..########.....#######.######....##################.######..
|
||||
..########.....#######.######......################.######..
|
||||
..########.....#######.######.........#############.######..
|
||||
............................................................
|
||||
END
|
||||
|
||||
for $line (split "\n", $source) {
|
||||
push @lines, [map { 1 & ord $_ } split '', $line]
|
||||
}
|
||||
|
||||
$v = @lines;
|
||||
$h = @{$lines[0]};
|
||||
push @black, @$_ for @lines;
|
||||
@p8 = ((-$h-1), (-$h+0), (-$h+1), # flatland distances to 8 neighbors.
|
||||
0-1, 0+1,
|
||||
$h-1, $h+0, $h+1)[1,2,4,7,6,5,3,0]; # (in cycle order)
|
||||
|
||||
# Candidates have 8 neighbors and are known black
|
||||
@cand = grep { $black[$_] } map { my $x = $_; map $_*$h + $x, 1..$v-2 } 1..$h-2;
|
||||
|
||||
do {
|
||||
sub seewhite {
|
||||
my($w1,$w2) = @_;
|
||||
my(@results);
|
||||
sub cycles { my(@neighbors)=@_; my $c; $c += $neighbors[$_] < $neighbors[($_+1)%8] for 0..$#neighbors; return $c }
|
||||
sub blacks { my(@neighbors)=@_; sum @neighbors }
|
||||
|
||||
@prior = @cand; @cand = ();
|
||||
for $p (@prior) {
|
||||
@n = @black[map { $_+$p } @p8];
|
||||
if (cycles(@n) == 1 and 2 <= sum(blacks(@n)) and sum(blacks(@n)) <= 6 and min(@n[@$w1]) == 0 and min(@n[@$w2]) == 0) {
|
||||
push @results, $p;
|
||||
} else {
|
||||
push @cand, $p
|
||||
}
|
||||
}
|
||||
return @results;
|
||||
}
|
||||
|
||||
@goners1 = seewhite [0,2,4], [2,4,6]; @black[@goners1] = 0 x @goners1;
|
||||
@goners2 = seewhite [0,2,6], [0,4,6]; @black[@goners2] = 0 x @goners2;
|
||||
} until @goners1 == 0 and @goners2 == 0;
|
||||
|
||||
while (@black) { push @thinned, join '', qw<. #>[splice(@black,0,$h)] }
|
||||
|
||||
print join "\n", @thinned;
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
Public n As Variant
|
||||
Private Sub init()
|
||||
n = [{-1,0;-1,1;0,1;1,1;1,0;1,-1;0,-1;-1,-1;-1,0}]
|
||||
End Sub
|
||||
|
||||
Private Function AB(text As Variant, y As Integer, x As Integer, step As Integer) As Variant
|
||||
Dim wtb As Integer
|
||||
Dim bn As Integer
|
||||
Dim prev As String: prev = "#"
|
||||
Dim next_ As String
|
||||
Dim p2468 As String
|
||||
For i = 1 To UBound(n)
|
||||
next_ = Mid(text(y + n(i, 1)), x + n(i, 2), 1)
|
||||
wtb = wtb - (prev = "." And next_ <= "#")
|
||||
bn = bn - (i > 1 And next_ <= "#")
|
||||
If (i And 1) = 0 Then p2468 = p2468 & prev
|
||||
prev = next_
|
||||
Next i
|
||||
If step = 2 Then '-- make it p6842
|
||||
p2468 = Mid(p2468, 3, 2) & Mid(p2468, 1, 2)
|
||||
'p2468 = p2468(3..4)&p2468(1..2)
|
||||
End If
|
||||
Dim ret(2) As Variant
|
||||
ret(0) = wtb
|
||||
ret(1) = bn
|
||||
ret(2) = p2468
|
||||
AB = ret
|
||||
End Function
|
||||
|
||||
Private Sub Zhang_Suen(text As Variant)
|
||||
Dim wtb As Integer
|
||||
Dim bn As Integer
|
||||
Dim changed As Boolean, changes As Boolean
|
||||
Dim p2468 As String '-- (p6842 for step 2)
|
||||
Dim x As Integer, y As Integer, step As Integer
|
||||
Do While True
|
||||
changed = False
|
||||
For step = 1 To 2
|
||||
changes = False
|
||||
For y = 1 To UBound(text) - 1
|
||||
For x = 2 To Len(text(y)) - 1
|
||||
If Mid(text(y), x, 1) = "#" Then
|
||||
ret = AB(text, y, x, step)
|
||||
wtb = ret(0)
|
||||
bn = ret(1)
|
||||
p2468 = ret(2)
|
||||
If wtb = 1 _
|
||||
And bn >= 2 And bn <= 6 _
|
||||
And InStr(1, Mid(p2468, 1, 3), ".") _
|
||||
And InStr(1, Mid(p2468, 2, 3), ".") Then
|
||||
changes = True
|
||||
text(y) = Left(text(y), x - 1) & "!" & Right(text(y), Len(text(y)) - x)
|
||||
End If
|
||||
End If
|
||||
Next x
|
||||
Next y
|
||||
If changes Then
|
||||
For y = 1 To UBound(text) - 1
|
||||
text(y) = Replace(text(y), "!", ".")
|
||||
Next y
|
||||
changed = True
|
||||
End If
|
||||
Next step
|
||||
If Not changed Then Exit Do
|
||||
Loop
|
||||
Debug.Print Join(text, vbCrLf)
|
||||
End Sub
|
||||
|
||||
Public Sub main()
|
||||
init
|
||||
Dim Small_rc(9) As String
|
||||
Small_rc(0) = "................................"
|
||||
Small_rc(1) = ".#########.......########......."
|
||||
Small_rc(2) = ".###...####.....####..####......"
|
||||
Small_rc(3) = ".###....###.....###....###......"
|
||||
Small_rc(4) = ".###...####.....###............."
|
||||
Small_rc(5) = ".#########......###............."
|
||||
Small_rc(6) = ".###.####.......###....###......"
|
||||
Small_rc(7) = ".###..####..###.####..####.###.."
|
||||
Small_rc(8) = ".###...####.###..########..###.."
|
||||
Small_rc(9) = "................................"
|
||||
Zhang_Suen (Small_rc)
|
||||
End Sub
|
||||
Loading…
Add table
Add a link
Reference in a new issue