Jump to content

Zhang-Suen thinning algorithm: Difference between revisions

m
Added syntax highlighting (working from the back of the task list).
(added Swift)
m (Added syntax highlighting (working from the back of the task list).)
Line 111:
{{trans|Python}}
 
<langsyntaxhighlight lang=11l>V beforeTxt = |‘1100111
1100111
1100111
Line 216:
print("\nFrom:\n#.".format(toTxt(image)))
V after = zhangSuen(&image)
print("\nTo thinned:\n#.".format(toTxt(after)))</langsyntaxhighlight>
 
{{out}}
Line 263:
 
=={{header|Action!}}==
<langsyntaxhighlight lang=Action!>PROC DrawImage(BYTE ARRAY image BYTE x,y,width,height)
BYTE i,j
BYTE POINTER ptr
Line 393:
DO UNTIL CH#$FF OD
CH=$FF
RETURN</langsyntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Zhang-Suen_thinning_algorithm.png Screenshot from Atari 8-bit computer]
 
=={{header|AppleScript}}==
<langsyntaxhighlight lang=applescript>-- Params:
-- List of lists (rows) of "pixel" values.
-- Record indicating the values representing black and white.
Line 489:
return join(matrix, linefeed)
end demo
return demo()</langsyntaxhighlight>
 
{{output}}
<lang applescriptpre>"00000000000000000000000000000000
00111111100000000011111100000000
00100000100000000110000000000000
Line 501:
00000000100001000110000110001000
00000000010000000001111000000000
00000000000000000000000000000000"</langpre>
Alternative demo:
<langsyntaxhighlight lang=applescript>on demo()
set pattern to "
################# #############
Line 532:
return join(matrix, linefeed)
end demo
return demo()</langsyntaxhighlight>
 
{{output}}
<lang applescriptpre>"
# ########## #######
Line 551:
# ############
### ###
</langpre>
"</lang>
 
=={{header|AutoHotkey}}==
{{works with|AutoHotkey_L}}
Reads input from a text file and writes output to a different text file (first creating the file, if necessary).
<langsyntaxhighlight lang=AutoHotkey>FileIn := A_ScriptDir "\Zhang-Suen.txt"
FileOut := A_ScriptDir "\NewFile.txt"
 
Line 635 ⟶ 634:
return 1
return Neighbors
}</langsyntaxhighlight>
'''Output:'''
<pre>
Line 656 ⟶ 655:
</pre>
The images before and after thinning are also printed on the console.
<syntaxhighlight lang=C>
<lang C>
#include<stdlib.h>
#include<stdio.h>
Line 817 ⟶ 816:
return 0;
}
</syntaxhighlight>
</lang>
 
Contents of input file : zhImage.txt
Line 887 ⟶ 886:
=={{header|C++}}==
Compiled with --std=c++14
<langsyntaxhighlight lang=CPP>#include <iostream>
#include <string>
#include <sstream>
Line 1,128 ⟶ 1,127:
return 0;
}
</syntaxhighlight>
</lang>
 
Output:
Line 1,202 ⟶ 1,201:
=={{header|D}}==
This uses the module from the Bitmap Task. And it performs no heap allocations.
<langsyntaxhighlight lang=d>import std.stdio, std.algorithm, std.string, std.functional,
std.typecons, std.typetuple, bitmap;
 
Line 1,329 ⟶ 1,328:
writeln;
}
}</langsyntaxhighlight>
{{out}}
<pre>From:
Line 1,430 ⟶ 1,429:
ELENA 5.0 :
{{trans|Java}}
<langsyntaxhighlight lang=elena>import system'collections;
import system'routines;
import extensions;
Line 1,597 ⟶ 1,596:
console.readChar()
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,621 ⟶ 1,620:
=={{header|Elixir}}==
{{trans|Ruby}}
<langsyntaxhighlight lang=elixir>defmodule ZhangSuen do
@neighbours [{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}] # 8 neighbours
Line 1,710 ⟶ 1,709:
00000000000000000000000000000000
"""
ZhangSuen.thinning(str, ?1)</langsyntaxhighlight>
 
{{out}}
Line 1,773 ⟶ 1,772:
 
=={{header|Fortran}}==
With F90 came standardisation of a variety of array manipulation facilities. Since the image array is to be inspected as a whole then adjusted rather than adjusted step-by-step as it is inspected, the first thought was to employ the special facility of the FOR ALL statement, which is that in an expression such as <langsyntaxhighlight lang=Fortarn>FOR ALL (i = 2:n - 1) A(i) = (A(i - 1) + A(i) + A(i + 1))/3</langsyntaxhighlight> all right-hand-side expressions will be evaluated with the original values of the array, while in the less special array assignment <langsyntaxhighlight lang=Fortran>A(2:N - 1) = (A(1:N - 2) + A(2:N - 1) + A(3:N))/3</langsyntaxhighlight> as in the case of the equivalent DO-loop, the processing will be with a mixture of old and new values as the loop proceeds.
 
So, that suggests something like <langsyntaxhighlight lang=Fortran> FOR ALL (I = 2:N - 1, J = 2:M - 1)
WHERE(DOT(I,J) .NE. 0) DOT(I,J) = ADJUST(DOT,I,J)</langsyntaxhighlight>
This requires function ADJUST to be a "pure" function, and they are not supposed to perpetrate side effects, such as one reporting that any adjustment was made. Nor is it clear that array DOT must be presented as a parameter either as the entire array or as element DOT(i,j), or if not, that it can be global to function ADJUST - which would also be an impurity - and for that matter, variables I and J could be global also...
 
Instead, thought turned to more closely following the task specification, which involves producing a list of elements to be adjusted after an inspection pass. Given that array DOT is two-dimensional, it would be nice if an element could be indexed via an expression such as <code>DOT(INDEX)</code> where INDEX was an array of two elements with INDEX(1) = i, and INDEX(2) = j, so as to access DOT(i,j) If this were possible, then obviously one could hope that array INDEX could be extended so as to store the multiple elements of a list of such locations to access, with a view to <code>DOT(INDEX(1:n)) = 0</code> adjusting the image.
 
Alas, such a syntax form is not accommodated. However, F90 also introduced the ability to define and use compound data types, such as the type PLACE as used below. It is not possible to define a type of a special, recognised form, such as say "SUBSCRIPT LIST" that can be used as dreamt of above, so the components are just ordinary variables. Two ordinary arrays could be used, one for each of the two subscripts, or a compound type could be devised in a hint towards self-documentation. Thus, <langsyntaxhighlight lang=Fortran> DOT(WHACK(1:WHACKCOUNT).I,WHACK(1:WHACKCOUNT).J) = 0</langsyntaxhighlight>
 
But it doesn't work... After a fair amount of head scratching, not at all assisted by the woolly generalities and inane examples of the compiler's "help" collection, it became apparent that the expression did not work through a list of indices as anticipated, but instead, for ''each'' value of the first index, ''all'' the values of the second index were selected. Thus, instead of the first change being DOT(WHACK('''1''').I,WHACK('''1''').J) only, it was DOT(WHACK('''1''').I,WHACK('''1:WHACKCOUNT''').J) that were being cleared. Accordingly, the fancy syntax has to be abandoned in favour of a specific DO-loop.
 
<langsyntaxhighlight lang=Fortran> MODULE ZhangSuenThinning !Image manipulation.
CONTAINS
SUBROUTINE ZST(DOT) !Attempts to thin out thick lines.
Line 1,890 ⟶ 1,889:
CALL SHOW(IMAGE)
 
END PROGRAM POKE </langsyntaxhighlight>
 
Output:
Line 1,920 ⟶ 1,919:
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang=freebasic>' version 08-10-2016
' compile with: fbc -s console
 
Line 2,054 ⟶ 2,053:
Print : Print "hit any key to end program"
Sleep
End</langsyntaxhighlight>
{{out}}
<pre>................................
Line 2,080 ⟶ 2,079:
 
=={{header|Go}}==
<langsyntaxhighlight lang=go>package main
 
import (
Line 2,268 ⟶ 2,267:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,284 ⟶ 2,283:
 
=={{header|Groovy}}==
<langsyntaxhighlight lang=groovy>def zhangSuen(text) {
def image = text.split('\n').collect { line -> line.collect { it == '#' ? 1 : 0} }
def p2, p3, p4, p5, p6, p7, p8, p9
Line 2,308 ⟶ 2,307:
while (reduce(step1) | reduce(step2));
image.collect { line -> line.collect { it ? '#' : '.' }.join('') }.join('\n')
}</langsyntaxhighlight>
Testing:
<langsyntaxhighlight lang=groovy>def small = """\
................................
.#########.......########.......
Line 2,348 ⟶ 2,347:
println zhangSuen(it)
println()
}</langsyntaxhighlight>
Output:
<pre>From:
Line 2,413 ⟶ 2,412:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang=Haskell>import Data.Array
import qualified Data.List as List
 
Line 2,534 ⟶ 2,533:
 
main :: IO ()
main = mapM_ (putStrLn . showBWArray . thin . toBWArray) [sampleExA, sampleExB]</langsyntaxhighlight>
{{out}}
<pre> ####### ######
Line 2,565 ⟶ 2,564:
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang=j>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
Line 2,589 ⟶ 2,588:
step2=: whiten frameImg@(cond2 neighbrs)
 
zhangSuen=: [: toImage [: step2@step1^:_ isBlackPx</langsyntaxhighlight>
'''Alternative, explicit representation of last verb above'''
<langsyntaxhighlight lang=j>zhangSuenX=: verb define
img=. isBlackPx y
whilst. 0 < +/ , msk1 +.&-. msk2 do.
Line 2,600 ⟶ 2,599:
end.
toImage img
)</langsyntaxhighlight>
'''Example Use:'''
<langsyntaxhighlight lang=j>toASCII=: ' #' {~ '1'&=;._2 NB. convert to ASCII representation
 
ExampleImg=: noun define
Line 2,627 ⟶ 2,626:
# # ## ## #
# ####
</langsyntaxhighlight>
 
=={{header|Java}}==
{{works with|Java|7}}
<langsyntaxhighlight lang=java>import java.awt.Point;
import java.util.*;
 
Line 2,747 ⟶ 2,746:
System.out.println(row);
}
}</langsyntaxhighlight>
 
Output:
Line 2,769 ⟶ 2,768:
=={{header|JavaScript}}==
{{trans|Java}}
<langsyntaxhighlight lang=javascript>function Point(x, y) {
this.x = x;
this.y = y;
Line 2,874 ⟶ 2,873:
return ZhangSuen;
}());
ZhangSuen.main(null);</langsyntaxhighlight>
 
Output:
Line 2,895 ⟶ 2,894:
 
=={{header|Julia}}==
<langsyntaxhighlight lang=julia>
const pixelstring =
"00000000000000000000000000000000" *
Line 2,972 ⟶ 2,971:
 
 
asciiprint(zsthinning(pixels))</langsyntaxhighlight>
{{output}}<pre>
loop number 1
Line 2,990 ⟶ 2,989:
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang=scala>// version 1.1.2
 
class Point(val x: Int, val y: Int)
Line 3,089 ⟶ 3,088:
fun main(args: Array<String>) {
thinImage()
}</langsyntaxhighlight>
 
{{out}}
Line 3,112 ⟶ 3,111:
 
=={{header|Lua}}==
<langsyntaxhighlight lang=lua>function zhangSuenThin(img)
local dirs={
{ 0,-1},
Line 3,252 ⟶ 3,251:
 
zhangSuenThin(image)
</syntaxhighlight>
</lang>
 
Output:
Line 3,271 ⟶ 3,270:
Mathematica supports directly the Thinning methods "Morphological" and "MedialAxis".
The Zhang-Suen algorithm implementation could be done with:
<langsyntaxhighlight lang=Mathematica>nB[mat_] := Delete[mat // Flatten, 5] // Total;
 
nA[mat_] := Module[{l},
Line 3,308 ⟶ 3,307:
 
 
FixedPoint[iter, dat]</langsyntaxhighlight>
 
Which results in:
Line 3,452 ⟶ 3,451:
 
=={{header|Nim}}==
<langsyntaxhighlight lang=Nim>import math, sequtils, strutils
 
type
Line 3,545 ⟶ 3,544:
echo()
echo "Output image:"
echo output</langsyntaxhighlight>
 
{{out}}
Line 3,575 ⟶ 3,574:
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight lang=perl>use List::Util qw(sum min);
 
$source = <<'END';
Line 3,637 ⟶ 3,636:
while (@black) { push @thinned, join '', qw<. #>[splice(@black,0,$h)] }
 
print join "\n", @thinned;</langsyntaxhighlight>
{{out}}
<pre>............................................................
Line 3,659 ⟶ 3,658:
 
=={{header|Phix}}==
<!--<langsyntaxhighlight lang=Phix>(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}};</span>
Line 3,726 ⟶ 3,725:
................................"""</span>
<span style="color: #000000;">Zhang_Suen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">small_rc</span><span style="color: #0000FF;">)</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 3,742 ⟶ 3,741:
 
=={{header|PL/I}}==
<syntaxhighlight lang=PL/I>zhang: procedure options (main); /* 8 July 2014 */
 
declare pic(10) bit(32) initial (
Line 3,864 ⟶ 3,863:
end B;
 
end zhang;</langsyntaxhighlight>
<pre>
[Initial configuration:]
Line 3,955 ⟶ 3,954:
=={{header|Python}}==
Several input images are converted.
<langsyntaxhighlight lang=python># -*- coding: utf-8 -*-
 
# Example from [http://nayefreza.wordpress.com/2013/05/11/zhang-suen-thinning-algorithm-java-implementation/ this blog post].
Line 4,072 ⟶ 4,071:
print('\nFrom:\n%s' % toTxt(image))
after = zhangSuen(image)
print('\nTo thinned:\n%s' % toTxt(after))</langsyntaxhighlight>
 
{{out}}
Line 4,102 ⟶ 4,101:
=={{header|Racket}}==
 
<langsyntaxhighlight lang=racket>#lang racket
(define (img-01string->vector str)
(define lines (regexp-split "\n" str))
Line 4,215 ⟶ 4,214:
; (read-display-thin-display-image e.g.-image/2)
; (newline)
(read-display-thin-display-image e.g.-image))</langsyntaxhighlight>
 
{{out}}
Line 4,245 ⟶ 4,244:
(formerly Perl 6)
Source image may be based on any characters whose low bits are 0 or 1 (which conveniently includes . and #).
<langsyntaxhighlight lang=perl6>my $source = qq:to/EOD/;
................................
.#########.......########.......
Line 4,295 ⟶ 4,294:
}
 
say @black.splice(0,h).join.trans('01' => '.#') while @black;</langsyntaxhighlight>
{{out}}
<pre>Ping: 66 remaining after removing 33 41 49 56 67 71 74 80 83 86 89 99 106 114 119 120 121 131 135 138 146 169 178 195 197 210 215 217 227 230 233 236 238 240 243 246 249 251 253 257 258 259 263 264 266 268 269 270 273 274 279 280 283 284 285
Line 4,315 ⟶ 4,314:
 
=={{header|REXX}}==
<langsyntaxhighlight lang=rexx>/*REXX program thins a NxM character grid using the Zhang-Suen thinning algorithm.*/
parse arg iFID .; if iFID=='' then iFID='ZHANG_SUEN.DAT'
white=' '; @.=white /* [↓] read the input character grid. */
Line 4,355 ⟶ 4,354:
Ps: rm=r-1; rp=r+1; cm=c-1; cp=c+1 /*calculate some shortcuts.*/
p2=@.rm.c\==white; p3=@.rm.cp\==white; p4=@.r.cp\==white; p5=@.rp.cp\==white
p6=@.rp.c\==white; p7=@.rp.cm\==white; p8=@.r.cm\==white; p9=@.rm.cm\==white; return</langsyntaxhighlight>
'''output''' &nbsp; when using the default input:
<pre>
Line 4,429 ⟶ 4,428:
First I define a function zs which given a point and its eight neighbours returns 1 if the point may be culled, 0 otherwise. g indicates if this is step 1 or step 2 in the task description. zs may be changed to remember the step independently if the reader does not wish to explore the algorithm.
 
<langsyntaxhighlight lang=ruby>class ZhangSuen
NEIGHBOUR8 = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]] # 8 neighbors
CIRCULARS = NEIGHBOUR8 + [NEIGHBOUR8.first] # P2, ... P9, P2
Line 4,496 ⟶ 4,495:
EOS
 
ZhangSuen.new(task_example, "1")</langsyntaxhighlight>
 
{{out}}
Line 4,514 ⟶ 4,513:
=={{header|Sidef}}==
{{trans|Ruby}}
<langsyntaxhighlight lang=ruby>class ZhangSuen(str, black="1") {
const NEIGHBOURS = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]] # 8 neighbors
const CIRCULARS = (NEIGHBOURS + [NEIGHBOURS.first]) # P2, ... P9, P2
Line 4,570 ⟶ 4,569:
EOS
 
ZhangSuen.new(text, black: "1").display</langsyntaxhighlight>
{{out}}
<pre>
Line 4,588 ⟶ 4,587:
{{trans|Python}}
 
<syntaxhighlight lang=swift>import UIKit
 
// testing examples
Line 4,758 ⟶ 4,757:
// print the result
print("\nTo thinned:\n\(toTxt(intmatrix: after))")
}</langsyntaxhighlight>
 
{{out}}
Line 4,863 ⟶ 4,862:
=={{header|Tcl}}==
Only the single image is converted.
<langsyntaxhighlight lang=tcl># -*- coding: utf-8 -*-
 
set data {
Line 4,940 ⟶ 4,939:
return $data
}
puts [string map {1 @ 0 .} [join [zhang-suen $data] \n]]</langsyntaxhighlight>
 
{{out}}
Line 4,958 ⟶ 4,957:
=={{header|VBA}}==
{{trans|Phix}}
<langsyntaxhighlight lang=vb>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}]
Line 5,040 ⟶ 5,039:
Small_rc(9) = "................................"
Zhang_Suen (Small_rc)
End Sub</langsyntaxhighlight>{{out}}
<pre>................................
...######.........######........
Line 5,054 ⟶ 5,053:
=={{header|Wren}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang=ecmascript>class Point {
construct new(x, y) {
_x = x
Line 5,161 ⟶ 5,160:
}
 
thinImage.call()</langsyntaxhighlight>
 
{{out}}
9,488

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.