September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -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> &nbsp; P9 &nbsp; </td><td> &nbsp; P2 &nbsp; </td><td> &nbsp; P3 &nbsp; </td></tr>
<tr><td> &nbsp; P8 &nbsp; </td><td><b> &nbsp; P1 &nbsp; </b></td><td> &nbsp; P4 &nbsp; </td></tr>
<tr><td> &nbsp; P7 &nbsp; </td><td> &nbsp; P6 &nbsp; </td><td> &nbsp; P5 &nbsp; </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.

View file

@ -0,0 +1 @@
--- {}

View file

@ -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
]

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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