Lo sviluppo di un esperimento

^M Come primo esperimento sviluppiamo un programma atto a realizzare, su una immagine caricata dall'host, il thinning, cioè l'assottigliamento delle linee.
Questa operazione si compie su una immagine binaria, quindi un solo layer della CAM 8 sarà impiegato per contenere l'intera immagine, riservando altri layers per rendere visibile il vicinato che è necessario al corretto svolgimento del compito.
Il vicinato è reso visibile in questo modo: prima di compiere uno scan, il layer 0 che è quello contenente l'immagine, viene copiato nei layers dal 2 al 9; successivamente questi vengono traslati in opportuna direzione e quantità, come è illustrato in figura1. Con riferimento alla figura 1b, in ogni cella CAM 8 è presente il bit dell'immagine (sempre sul layer 0) e i bits dei vicini (sui layer precedentemente definiti). La cella può ora essere usata per indirizzare la LUT e avere il nuovo valore per il bit dell'immagine.

Per prima cosa, occorre decidere le dimensioni dello spazio di simulazione ed il numero di layers coinvolti nell'update:

  new-experiment        10 is #layers

  256 by 256 space
 
Definisco poi i layers, avendo cura di scegliere quei nomi che meglio caratterizzano la funzione svolta:
   0 0 == center
   1 1 == center'
   0 1 == centers

   2 2 == north
   3 3 == south
   4 4 == east
   5 5 == west

   6 6 == n.east
   7 7 == n.west
   8 8 == s.east
   9 9 == s.west
 
Ora posso riferire il layer 0 come center nelle regole di update, e così per tutti gli altri layer definiti dal comando ==.
È questa una fase fondamentale poiché, senza regole, la CAM 8 non saprebbe come agire. Successivamente occorrerà definire il kick dei layers che renderà visibile il vicinato.
Il thinning è composto da molte operazioni, dette di riconoscimento di pattern, nelle quali un pattern predefinito nelle regole di update viene confrontato con il bit dell'immagine e e con i bits del vicinato. Le regole saranno quindi costruite seguendo questi pattern e riconosceranno il verificarsi della condizione scrivendo, al posto del vecchio bit di immagine, il nuovo bit.
I pattern sono in tutto otto, avrò quindi bisogno di otto regole di update, una per ogni matching. Prendo il primo pattern da riconoscere
00-
011
-1-

Ciò significa che se center, east, south sono impostati ad 1 e north, n.west, west sono impostati a 0, (I rimanenti n.east e s.west non importano, cioè entrambi i valori 1 o 0 verificano il matching) allora si è verificata la coincidenza dei pattern: al posto del valore vecchio di center viene posto uno 0. Se non si verifica viene rimesso il vecchio valore. Ecco la prima regola:

 : thin1 
   center' east south and and 
   north not n.west not west not and and 
   and
   {{ center 0 }} -> center
         center -> center'
         propagate
 ;
 
La doppia parentesi graffa indica un case, cioè se il risultato dell'operazione immediatamente precedente, o meglio il valore contenuto nello stack risultato dell'ultima operazione, è 0, allora nello stack torna il valore center, altrimenti torna il valore 0. Esso viene poi consumato dall'operatore -> che lo ripone in center.
Nel definire la regola posso però fare di più: so che i vicini sono visibili tramite copie, quindi non devo aver cura di non distruggere informazioni utili, posso allora copiare center in center' e in tutti gli altri 8 layers, trovando così, alla fine di uno scan, già pronto lo spazio di celle per il kick.
Lo strano comando propagate non è un comando CAMForth, è stato da me aggiunto al dizionario tramite l'operatore : , allo scopo di non ripetere le stesse linee per ogni regola.
 : propagate            \ copio l'immagine negli altri layers

   update

   center

   dup -> north
   dup -> south
   dup -> east
   dup -> west
   dup -> n.east
   dup -> n.west
   dup -> s.east
       -> s.west
 ;
 
Occorre notare che la definizione delle regole dev'essere necessariamente seguita dalla creazione, sulla base di dette regole, di opportune tabelle per mezzo del comando rule>table. Dopo averle create, le succitate tabelle vengono rese disponibili tramite il comando create-lut.
Per quanto concerne il kick bisogna dire che in questa particolare applicazione esso ha lo scopo di rendere visibile il vicinato, e pertanto è unico e non varia da regola a regola.
Ciò a cui bisogna prestare molta attenzione adesso è la direzione di traslazione dei layers (La profondità sarà ovviamente 1, poiché voglio rendere visibili i primi vicini di ogni cella).
Per esempio il layer south dovrà, per rispettare il nome affidatogli, compiere uno shift verso l'alto, rendendo il suo nome una garanzia per le regole appena costruite (vedere figura 2).

Inoltre occorre impostare la CAM 8 per l'update dei siti tramite il comando lut-src site. Successivamente essa verrà informata per mezzo del comando site-src lut che i risultati dovranno essere scritti nelle celle. Il tutto entro un definizione define-step per rendere l'esecuzione più veloce.
 define-step  free-step     \ compio gli shift e lo scan
        full-space
        lut-src   site    \ imposto l'update tramite lut
        site-src  lut
        display   site    \ visualizzo i siti
        kick       north  field   0 x   1 y
                      south  field   0 x  -1 y
                      east   field  -1 x   0 y
                      west   field   1 x   0 y
                      n.east field  -1 x   1 y
                      n.west field   1 x   1 y
                      s.east field  -1 x  -1 y
                      s.west field   1 x  -1 y

        run         free    \ parte lo scan

 end-step
 
Non resta ora che avviare l'elaborazione: per prima cosa si carica la regola opportuna nella LUT non attiva che viene successivamente attivata disattivando l'altra, quindi si avvia il primo matching mandando in esecuzione la define-step di cui sopra.
Il listato completo è visibile in appendice. Le immagini che la CAM 8 accetta devono essere in formato RAW, cioè 16 bit senza compressione.


Ritorno al precedente