狠狠撸

狠狠撸Share a Scribd company logo
Documentazione
                              Class visual狠狠撸Show.FullShow
                       Class visual狠狠撸Show.ScontriniPanel

Sommario
 1.       Introduzione .................................................................................................................................. 1
 2.       Algoritmo ....................................................................................................................................... 1
 3.       Descrizione Interfaccia Grafica ...................................................................................................... 2
 4.       Implementazione ........................................................................................................................... 3
 4.1.     Class FullShow ............................................................................................................................... 3
 4.1.1.   Variabili di classe ........................................................................................................................... 3
 4.1.2.   Costruttore .................................................................................................................................... 4
 4.1.3.   Metodi ........................................................................................................................................... 4
 4.2.     Class ScontriniPanel ....................................................................................................................... 6
 4.2.1.   Variabili di classe ........................................................................................................................... 6
 4.2.2.   Costruttore .................................................................................................................................... 7
 4.2.3.   Metodi ........................................................................................................................................... 7
 4.2.4.   Eventi Generati .............................................................................................................................. 8
 4.3.     Installazione del progetto .............................................................................................................. 8
 5.       Conclusioni .................................................................................................................................... 8
1. Introduzione
GEC_Scan è un programma che coopera con GEC (prodotto e mantenuto dalla Mida4), si occupa
dell’archiviazione digitale di documenti acquisiti tramite scanner.
L’acquisizione impone che sia scannerizzato un documento alla volta, operazione che diventa molto
onerosa dal punto di vista temporale se si devono acquisire molti documenti di piccola dimensione come gli
scontrini.
Si è pensato quindi di acquisire tramite un’unica scansione più documenti e poi successivamente dividerli e
farli risultare come documenti singoli. Queste operazioni devono risultare veloci e richiedere da parte
dell’utente meno click possibili.
Per l’aggiunta di questa funzionalità deve essere modificato GEC_Scan (precisamente il componente
Visual狠狠撸Show) il meno possibile.

2. Algoritmo
Una volta acquisita l’immagine con più documenti ne viene fatta una copia, tagliando 3 pixel per lato in
modo da escludere imperfezioni che si creano sui bordi durante le scansioni, la copia dell’immagine sarà
manipolata per l’identificazione dei documenti (tutte le operazioni vengono eseguite sulla copia
dell’immagine così da non sporcare l’immagine originale).
L’immagine viene ridimensionata a 827x1169 pixel in modo da avere un’immagine con risoluzione 100dpi in
entrambe le direzioni (supponendo di avere in ingresso la scansione di un foglio in formato A4 con qualsiasi
risoluzione).
Successivamente viene eseguito 20 volte il filtro Erosion3x3 contenuto nelle librerie AForge1.
Questo filtro espande i pixel di colore nero tramite un pennello di dimensione 3x3 pixel, cioè disegnando un
quadrato di 3 pixel di lato per ogni pixel di colore nero presente nell’immagine. Dopo alcuni test si è scelto
di applicare questo filtro in successione, invece del filtro Erosion generico in cui si può definire un pennello
di dimensione e forma arbitraria ma risultava meno performante usare un pennello grande poche volte
rispetto ad un pennello piccolo molte volte




                                         Immagine prima e dopo l’erosione

1
Pagina del progetto AForge http://code.google.com/p/aforge/
Sull’immagine risultante che è composta da “macchie nere” viene eseguito l’algoritmo di flood fill (metodo
Find_Rect, si rimanda alla sezione 4.1.3 per un maggior dettaglio sull’algoritmo di flood fill) esaminando un
pixel ogni 10 così da testare meno pixel possibile, ma essendo certi di esaminare tutte le aree di rilevanza.
Grazie a questo passaggio si ricavano le coordinate, sull’immagine modificata, delle aree nere connesse e
tramite una semplice conversione si ricavano le coordinate corrispondenti sull’immagine originale, quindi la
divisione dei documenti.
Attenzione: il numero di volte che è necessario eseguire l’erode dipende strettamente dalla dimensione
dell’immagine su cui si lavora, se si decide di ridimensionare l’immagine con altri valori, è necessario
stabilire nuovamente quante volte viene applicato il filtro.

3. Descrizione Interfaccia Grafica
I documenti trovati vengono messi in evidenza sull’interfaccia tramite pannelli di colore blu trasparente




L’interfaccia si basa principalmente sull’uso del mouse per la modifica dei pannelli nel caso che
l’identificazione abbia portato a qualche errore, e punta a ridurre al minimo il numero di click necessari per
correggere l’eventuale errore.
Gesture da mouse:

    ?   Doppio click sul pannello: cancella il pannello
    ?   Click destro sul pannello:
            o Seleziona il pannello
            o Se un pannello è selezionato unisci il pannello con quello selezionato
    ?   Trascinamento bordo del pannello ridimensiona il pannello
    ?   Trascinamento interno al pannello taglia il pannello nella direzione dello spostamento
    ?   Click e trascinamento all’esterno dei pannelli, crea un nuovo pannello
Scorciatoie da tastiera:
    ?   Alt + D avvia la divisione
    ?   Alt + S salva la selezione e chiude il form
    ?   Alt + A annulla la selezione e chiude il form
    ?   Alt + ? apre delle brevi istruzioni
4. Implementazione
    4.1.        Class FullShow
Classe derivata dalla classe Form. Identifica il form nel quale verrà caricata l’immagine per la divisione dei
documenti. Fornisce i metodi per la divisione e per il calcolo delle coordinate sull’immagine base.
    ? Per il corretto funzionamento c’è bisogno delle .dll di AForge tra i “Riferimenti” di visualStudio o
      comunque che siano presenti nella cartella che contiene visual狠狠撸Show.dll; nello specifico come
      riferimenti AForge e AForge.Imaging; come dll AForge, AForge.Imaging, AForge.Math

        4.1.1.Variabili di classe
    ?   Private Bitmap _originalImage
        Rappresenta l’immagine prima delle modifiche.
    ?   Private Bitmap _modImage
        è l’immagine sulla quale verranno svolte le operazioni
    ?   Private const int _dimX
        Numero di pixel in orizzontale per il ridimensionamento (827 porta un foglio A4 ad avere una
        risoluzione orizzontale di 100dpi)
    ?   Private const int _dimY
        Numero di pixel in verticale per il ridimensionamento (1169 porta un foglio A4 ad avere una
        risoluzione orizzontale di 100dpi)
    ?   Private double _fatX
        Fattore di conversione da dimensione X originale a dimensione _dimX



    ?   Private double _fatY
        Fattore di conversione da dimensione Y originale a dimensione _dimY



    ?   Private double _fatXY
        Fattore di conversione dalla dimensione originale alla dimensione del componete pictureBox. Per
        mantenere le proporzioni e non sformare l’immagine contenuta.
            Se l’immagine contenuta nella pictureBox “tocca” a destra e a sinistra



                Se “tocca” in alto e in basso



    ?   Private bool[,] _visited
        Matrice di dimensioni pari all’immagine per velocizzare il floodfill.
        Il floodfill invece di settare il colore dei pixel visitati imposta a true gli elementi di questa matrice
        operazione che richiede meno tempo.
    ?   Private int _span
        Rappresenta il valore di spazio “non immagine” tra il bordo del contollo (pictureBox) e il bordo
        effettivo dell’immagine in esso contenuto
?   Private int _dimMinPanel
    ? la dimensione minima di un nuovo pannello aggiunto dall’utente (default 8 pixel)
?   Private bool _clicked
    Variabile per il coordinamento tra i metodi. Se true un tasto del mouse è premuto sulla pictureBox
?   Private bool _insert
    Variabile per il coordinamento tra i metodi. Se true si sta inserendo un nuovo pannello
?   Private bool _formResize
    Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il Form
?   Private Point _mouseDownP
    Coordinate del punto in cui il mouse è stato premuto (sul pictureBox)
?   Private List<Rectangle> _listRect
    Lista di delle coordinate dei documenti sull’immagine originale
?   Private int _picDimX
    Larghezza della pictureBox prima di ogni ridimensionamento
?   Private int _picDimY
    Altezza della pictureBox prima di ogni ridimensionamento
?   Private List<Image> _listNewImages
    Lista che contiene le nuove immagini ritagliate e pronte all’uso
?   Public List<Image> listNewImages
    get restituisce la lista _listNewImages permettendone l’accesso in lettura dall’esterno della classe.

    4.1.2.Costruttore
?   Public Fullshow(Image img, String caption)
    img rappresenta l’immagine che deve essere elaborata
            se null verrà sollevata un’eccezione (null image)
    caption è il titolo della finestra

    4.1.3.Metodi
?   Private void button1_Click(object sender, EventArgs e)
    Inizializza le variabili che vengono coinvolte nel procedimento e lancia in successione i vari metodi
    per individuare i vari documenti
?   Private void trovaScontrini()
    metodo che:
         o clona in _modImage _originalImage tagliando 3 pixel di contorno,
         o calcola i vari fattori che serviranno successivamente,
         o ridimensiona l’immagine a _dimX, _dimY (filtro AForge)
         o inizializza la matrice _visited
         o converte l’immagine a toni di grigio (filtro AForge)
         o esegue sull’immagine 20 volte l’erode (filtro AForge)
         o lancia il floodfill (find_Rect)
?   Private void find_Rect (int xx, int yy)
    questo è l’algoritmo di floodfill, xx e yy sono le coordinate del punto di partenza del floodfill il
    colore obiettivo è il nero e non c’è un colore sostituto perché si usa la matrice _visited.
    Questo algoritmo procede in maniera verticale (inizialmente cerca la coordinata Y per cui sopra non
    c’è il colore cercato). Poi controlla a destra e a sinistra del punto e se non è stato visitato e
    corrisponde al colore cercato lo mette in coda (Q); per evitare che la coda aumenti troppo di
dimensione le variabili booleane spanLeft e spanRight vengono settate a true quando viene
    aggiunto un punto e messe a false quando nella colonna vicina non c’è il colore cercato quindi
    rendendo possibile l’inserimento in coda di un altro punto se nella colonna adiacente si ripresenta il
    colore cercato. Questo procedimento viene ripetuto finché non vengono visitati tutti i punti
    presenti in Q, quindi visitate tutte le colonne che hanno almeno un punto del colore specificato.
    Quando viene settato a true il valore corrispondente al pixel nella matrice _visited si incrementa
    anche il valore di area e dopo gli spostamenti del punto di interesse vengono salvati gli estremi in
    maxN, maxE, maxS, maxW.
    Alla fine se l’area è maggiore di un certo valore di soglia (5000 pixel2) per eliminare le zone troppo
    piccole dovute all’espansione di imperfezioni del foglio viene aggiunto un pannello
    opportunamente dimensionato tramite i fattori di scala e tenuto conto dello spazio dal bordo del
    pictureBox al bordo dell’immagine. Le coordinate vengono salvate anche in _listRect gli opportuni
    riscaldamenti.
?   Private void dipingi()
    setta l’immagine da visualizzare nella pictureBox a _originalImage e esegue un refresh della
    pictureBox
?   Private void button2_Click(object sender, EventArgs e)
    procede al salvataggio delle immagini tramite la lista _listRect nella lista _listNewImages una volta
    completata l’operazione chiude il form
?   Private void addMyPanel (Point e, int wid, int hei)
    colloca un pannello di tipo ScontriniPanel con l’angolo in alto a destra individuato dal punto e, e di
    larghezza wid e altezza hei.
    N.B. Queste grandezze devono essere proporzionate alla pictureBox e NON all’immagine in essa
    contenuta
?   Private void pan_PanResizeEvent(object sender, EventArgs e)
    lancia il metodo replacePanels quando un pannello genera l’evento PanResizeEvent
?   Private void aggiornaLista(object sender, EventArgs e)
    lancia il metodo popListRect quando un pannello lancia l’evento PanModEvent
?   Private void popListRect()
    svuota la lista _listRect e la ripopola sulla base dei panelli esistenti controllando che ogni rettangolo
    (e quindi ogni pannello) sia dentro i limiti dell’immagine.
?   Private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    se le variabili _clicked e _insert sono settate a true vuol dire che l’utente sta cercando di inserire un
    nuovo pannello e lancia quindi la procedura dedicata.
?   Private void mouseDown(object sender, MouseEventArgs e)
    se è stato generato dalla pictureBox vuol dire che è stato cliccato uno spazio senza pannello quindi
    si sta cercando di inserire un pannello nuovo quindi setta le variabili _clicked e _insert a true
    aggiunge un pannello di dimensione minima
?   Private void mouseUp(object sender, MouseEventArgs e)
    riporta _cliked a false; se generato dalla pictureBox riporta anche _insert a false e termina
    l’inserimento del nuovo pannello calcolando la posizione del rettangolo corrispondente
?   Private void Form1_ResizeBegin(object sender, EventArgs e)
    evento generato quando inizia il resize del form; rende invisibili tutti i pannelli e setta _formResize
    a true
?   Private void Form1_ResizeEnd(object sender, EventArgs e)
        evento generato quando finisce il resize del form se _formResize è impostato a true lancia la
        procedura replacePanels e riporta_formResize a false
    ?   Private void pictureBox1_Resize(object sender, EventArgs e)
        se la pictureBox viene ridimensionata senza che siano lanciati gli eventi di resize legati al form (es.
        con il bottone maximize invece del trascinamento del bordo) lancia la procedura replacePanels
    ?   Private void replacePalens()
        cancella tutti i pannelli presenti e li ridispone prendendo come riferimento la lista _listRect
    ?   Public void ImageUpdated()
        per compatibilità con GECScan.
        Invalida la superficie del form e quindi ne determina il ridisegno
    ?   Private void button3_Click(object sender, EventArgs e)
        cancella tutte le liste e chiude il form (tasto annulla)
    ?   Private void button4_Click(object sender, EventArgs e)
        visualizza il popup con le istruzioni
    ?   Private void timer1_Tick(object sender, EventArgs e)
        riabilita il pulsante button1 finita l’esecuzione dovuta alla sua pressione.

    4.2.        Class ScontriniPanel
Classe derivata dalla classe Panel. Fornisce i pannelli ridimensionabili e modificabili.

        4.2.1.Variabili di classe
    ?   Private static ScontriniPanel selected
        il pannello che viene selezionato tramite pulsante destro
    ?   Private static List<ScontriniPanel> _listPanel
        lista che contiene tutti i pannelli attualmente visualizzati
    ?   Public List<ScontriniPanel> listpanel
        get restituisce la lista _listPanel permettendone l’accesso in lettura dall’esterno
    ?   Private static Point mouseDownP
        punto in cui viene premuto il pulsante del mouse
    ?   Private const int margine
        dimensione del margine in cui si può ridimensionare il pannello (default 8)
    ?   Private const int splitOffset
        lunghezza in dopo la quale il trascinamento interno diventa taglio del pannello (default 30)
    ?   Private bool _cliked
        Variabile per il coordinamento tra i metodi. Se true il pulsante del mouse è premuto
    ?   Private bool _resize
        Variabile per il coordinamento tra i metodi. Se true si sta cercando di fare il resize di un pannello
    ?   Private bool _cut
        Variabile per il coordinamento tra i metodi. Se ture si sta cercando di dividere un pannello
    ?   Private bool _insert
        Variabile per il coordinamento tra i metodi. Se ture si sta cercando di inserire un nuovo pannello
    ?   Private bool _left
        Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo sinistro
?    Private bool _right
     Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo destro
?    Private bool _top
     Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo superiore
?    Private bool _down
     Variabile per il coordinamento tra i metodi. Se ture si sta ridimensionando il bordo inferiore

     4.2.2.Costruttore
?    Public ScontriniPanel()
     costruttore “fasullo” per poter accedere alla parte pubblica senza dover creare un pannello reale
?    Public ScontriniPanel(Point e, int wid, int hei)
     costruttore reale che genera un nuovo pannello con la coordinata del punto in alto a sinistra
     corrispondente a “e”, di larghezza wid e altezza hei, oltre a definire i vari gestori di eventi connessi
     ad ogni pannello e le relative proprietà.

     4.2.3.Metodi
?   Public void insertNew(Point e)
    Metodo per ovviare al problema del feedback visivo dell’inserimento di un nuovo pannello quando
    si fa solo click e trascinamento invece di click e poi ridimensionamento del pannello di dimensioni
    minime
?   Public void insertNewStop()
    per terminare l’inserimento da usare in coppia a insertNew
?   Public void cleanAll()
    cancella tutti i pannelli esistenti e pulisce la lista _listPanel
?   Private void mouseClick(object sender, MouseEventArgs e)
    quando si clicca con il pulsante destro su un pannello si seleziona, se si ri-clicca con il pulsante
    destro sullo stesso pannello si deseleziona, se invece si clicca su un altro pannello si uniscono i due
    pannelli;
    con il pulsante centrale vengono visualizzate nella console informazioni sul pannello
?   Private void mouseDoppioClick(object sender, MouseEventArgs e)
    se si fa un doppio click con il pulsante sinistro si elimina il pannello
?   Private void mouseEnter(object sender, EventArgs e)
    cambia il colore del pannello quando il mouse entra nella superficie
?   Private void mouseLeave(object sender, EventArgs e)
    ripristina il colore del pannello quando il mouse esce dalla superficie
?   Private void mouseDown(object sender, MouseEventArgs e)
    imposta a true le variabili corrispondenti all’azione che si desidera compiere
?   Private void mouseUp(object sender, MouseEventArgs e)
    ? compie il taglio del pannello ridimensionandone uno e aggiungendo un altro a fianco se è stato
        rilasciato il pulsante sinistro e se la _cut è a true la direzione di taglio è decisa dal tipo di cursore
        che viene impostato in mouseMove e lancia l’evento OnPanModEvent
    ? se l’azione era un ridimensionamento al termine lancia l’evento OnPanResizeEvent
    ? ripristina le variabili booleane a false
? private void mouseMovi(object sender, MouseEventArgs e)
      ? setta l’aspetto del cursore in base all’azione che si andrà a compiere
      ? compie il resize del pannello in base alle coordinate del mouse (ATTENZIONE: le coordinate
         continuano ad aumentare verso destra e verso il basso anche dopo la fine del pannello. Nel
         stesso modo verso l’alto e verso sinistra vanno in negativo)
    ? public void resizeMethod(ScontriniPanel pan, Point e)
      compie il resize del pannello interessato.

        4.2.4.Eventi Generati
    ?   Public event EventHandler PanModEvent
        gestore dell’evento generato quando un pannello viene modificato
    ?   Protected void OnPanModEvent(EventArgs e)
        metodo per generare l’evento associato (PanModEvent)
    ?   Public event EventHandler PanResizeEvent
        gestore dell’evento generato quando un pannello viene ridimensionato
    ?   Protected void OnPanResizeEvent(EventArgs e)
        metodo per generare l’evento associato (PanResizeEvent)

    4.3.        Installazione del progetto
Per il corretto funzionamento del progetto è necessario copiare:
    ?   visual狠狠撸Show.dll (che andrà a sostituire quello preesistente)
    ?   AForge.dll
    ?   AForge.Imaging.dll
    ?   AForge.Math.dll
all’interno della cartella che contiene l’eseguibile DocRetriver.exe

5. Conclusioni
L’identificazione viene svolta in 3-4 secondi, molti meno di una nuova scansione.
A meno di una pessima qualità di scansione (molti disturbi) o documenti eccessivamente vicini o
sovrapposti, l’identificazione propone una divisione corretta senza bisogno di interazione da parte
dell’utente. Nel caso che sia necessario l’utente con un numero limitato di click può porre rimedio ad una
situazione di errore.
Una volta approvata la divisione l’immagine di partenza viene eliminata dalla slide show e viene sostituita
da tutte le immagini divise rendendo così la procedura completamente trasparente.

More Related Content

Documentazione

  • 1. Documentazione Class visual狠狠撸Show.FullShow Class visual狠狠撸Show.ScontriniPanel Sommario 1. Introduzione .................................................................................................................................. 1 2. Algoritmo ....................................................................................................................................... 1 3. Descrizione Interfaccia Grafica ...................................................................................................... 2 4. Implementazione ........................................................................................................................... 3 4.1. Class FullShow ............................................................................................................................... 3 4.1.1. Variabili di classe ........................................................................................................................... 3 4.1.2. Costruttore .................................................................................................................................... 4 4.1.3. Metodi ........................................................................................................................................... 4 4.2. Class ScontriniPanel ....................................................................................................................... 6 4.2.1. Variabili di classe ........................................................................................................................... 6 4.2.2. Costruttore .................................................................................................................................... 7 4.2.3. Metodi ........................................................................................................................................... 7 4.2.4. Eventi Generati .............................................................................................................................. 8 4.3. Installazione del progetto .............................................................................................................. 8 5. Conclusioni .................................................................................................................................... 8
  • 2. 1. Introduzione GEC_Scan è un programma che coopera con GEC (prodotto e mantenuto dalla Mida4), si occupa dell’archiviazione digitale di documenti acquisiti tramite scanner. L’acquisizione impone che sia scannerizzato un documento alla volta, operazione che diventa molto onerosa dal punto di vista temporale se si devono acquisire molti documenti di piccola dimensione come gli scontrini. Si è pensato quindi di acquisire tramite un’unica scansione più documenti e poi successivamente dividerli e farli risultare come documenti singoli. Queste operazioni devono risultare veloci e richiedere da parte dell’utente meno click possibili. Per l’aggiunta di questa funzionalità deve essere modificato GEC_Scan (precisamente il componente Visual狠狠撸Show) il meno possibile. 2. Algoritmo Una volta acquisita l’immagine con più documenti ne viene fatta una copia, tagliando 3 pixel per lato in modo da escludere imperfezioni che si creano sui bordi durante le scansioni, la copia dell’immagine sarà manipolata per l’identificazione dei documenti (tutte le operazioni vengono eseguite sulla copia dell’immagine così da non sporcare l’immagine originale). L’immagine viene ridimensionata a 827x1169 pixel in modo da avere un’immagine con risoluzione 100dpi in entrambe le direzioni (supponendo di avere in ingresso la scansione di un foglio in formato A4 con qualsiasi risoluzione). Successivamente viene eseguito 20 volte il filtro Erosion3x3 contenuto nelle librerie AForge1. Questo filtro espande i pixel di colore nero tramite un pennello di dimensione 3x3 pixel, cioè disegnando un quadrato di 3 pixel di lato per ogni pixel di colore nero presente nell’immagine. Dopo alcuni test si è scelto di applicare questo filtro in successione, invece del filtro Erosion generico in cui si può definire un pennello di dimensione e forma arbitraria ma risultava meno performante usare un pennello grande poche volte rispetto ad un pennello piccolo molte volte Immagine prima e dopo l’erosione 1 Pagina del progetto AForge http://code.google.com/p/aforge/
  • 3. Sull’immagine risultante che è composta da “macchie nere” viene eseguito l’algoritmo di flood fill (metodo Find_Rect, si rimanda alla sezione 4.1.3 per un maggior dettaglio sull’algoritmo di flood fill) esaminando un pixel ogni 10 così da testare meno pixel possibile, ma essendo certi di esaminare tutte le aree di rilevanza. Grazie a questo passaggio si ricavano le coordinate, sull’immagine modificata, delle aree nere connesse e tramite una semplice conversione si ricavano le coordinate corrispondenti sull’immagine originale, quindi la divisione dei documenti. Attenzione: il numero di volte che è necessario eseguire l’erode dipende strettamente dalla dimensione dell’immagine su cui si lavora, se si decide di ridimensionare l’immagine con altri valori, è necessario stabilire nuovamente quante volte viene applicato il filtro. 3. Descrizione Interfaccia Grafica I documenti trovati vengono messi in evidenza sull’interfaccia tramite pannelli di colore blu trasparente L’interfaccia si basa principalmente sull’uso del mouse per la modifica dei pannelli nel caso che l’identificazione abbia portato a qualche errore, e punta a ridurre al minimo il numero di click necessari per correggere l’eventuale errore. Gesture da mouse: ? Doppio click sul pannello: cancella il pannello ? Click destro sul pannello: o Seleziona il pannello o Se un pannello è selezionato unisci il pannello con quello selezionato ? Trascinamento bordo del pannello ridimensiona il pannello ? Trascinamento interno al pannello taglia il pannello nella direzione dello spostamento ? Click e trascinamento all’esterno dei pannelli, crea un nuovo pannello Scorciatoie da tastiera: ? Alt + D avvia la divisione ? Alt + S salva la selezione e chiude il form ? Alt + A annulla la selezione e chiude il form ? Alt + ? apre delle brevi istruzioni
  • 4. 4. Implementazione 4.1. Class FullShow Classe derivata dalla classe Form. Identifica il form nel quale verrà caricata l’immagine per la divisione dei documenti. Fornisce i metodi per la divisione e per il calcolo delle coordinate sull’immagine base. ? Per il corretto funzionamento c’è bisogno delle .dll di AForge tra i “Riferimenti” di visualStudio o comunque che siano presenti nella cartella che contiene visual狠狠撸Show.dll; nello specifico come riferimenti AForge e AForge.Imaging; come dll AForge, AForge.Imaging, AForge.Math 4.1.1.Variabili di classe ? Private Bitmap _originalImage Rappresenta l’immagine prima delle modifiche. ? Private Bitmap _modImage è l’immagine sulla quale verranno svolte le operazioni ? Private const int _dimX Numero di pixel in orizzontale per il ridimensionamento (827 porta un foglio A4 ad avere una risoluzione orizzontale di 100dpi) ? Private const int _dimY Numero di pixel in verticale per il ridimensionamento (1169 porta un foglio A4 ad avere una risoluzione orizzontale di 100dpi) ? Private double _fatX Fattore di conversione da dimensione X originale a dimensione _dimX ? Private double _fatY Fattore di conversione da dimensione Y originale a dimensione _dimY ? Private double _fatXY Fattore di conversione dalla dimensione originale alla dimensione del componete pictureBox. Per mantenere le proporzioni e non sformare l’immagine contenuta. Se l’immagine contenuta nella pictureBox “tocca” a destra e a sinistra Se “tocca” in alto e in basso ? Private bool[,] _visited Matrice di dimensioni pari all’immagine per velocizzare il floodfill. Il floodfill invece di settare il colore dei pixel visitati imposta a true gli elementi di questa matrice operazione che richiede meno tempo. ? Private int _span Rappresenta il valore di spazio “non immagine” tra il bordo del contollo (pictureBox) e il bordo effettivo dell’immagine in esso contenuto
  • 5. ? Private int _dimMinPanel ? la dimensione minima di un nuovo pannello aggiunto dall’utente (default 8 pixel) ? Private bool _clicked Variabile per il coordinamento tra i metodi. Se true un tasto del mouse è premuto sulla pictureBox ? Private bool _insert Variabile per il coordinamento tra i metodi. Se true si sta inserendo un nuovo pannello ? Private bool _formResize Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il Form ? Private Point _mouseDownP Coordinate del punto in cui il mouse è stato premuto (sul pictureBox) ? Private List<Rectangle> _listRect Lista di delle coordinate dei documenti sull’immagine originale ? Private int _picDimX Larghezza della pictureBox prima di ogni ridimensionamento ? Private int _picDimY Altezza della pictureBox prima di ogni ridimensionamento ? Private List<Image> _listNewImages Lista che contiene le nuove immagini ritagliate e pronte all’uso ? Public List<Image> listNewImages get restituisce la lista _listNewImages permettendone l’accesso in lettura dall’esterno della classe. 4.1.2.Costruttore ? Public Fullshow(Image img, String caption) img rappresenta l’immagine che deve essere elaborata se null verrà sollevata un’eccezione (null image) caption è il titolo della finestra 4.1.3.Metodi ? Private void button1_Click(object sender, EventArgs e) Inizializza le variabili che vengono coinvolte nel procedimento e lancia in successione i vari metodi per individuare i vari documenti ? Private void trovaScontrini() metodo che: o clona in _modImage _originalImage tagliando 3 pixel di contorno, o calcola i vari fattori che serviranno successivamente, o ridimensiona l’immagine a _dimX, _dimY (filtro AForge) o inizializza la matrice _visited o converte l’immagine a toni di grigio (filtro AForge) o esegue sull’immagine 20 volte l’erode (filtro AForge) o lancia il floodfill (find_Rect) ? Private void find_Rect (int xx, int yy) questo è l’algoritmo di floodfill, xx e yy sono le coordinate del punto di partenza del floodfill il colore obiettivo è il nero e non c’è un colore sostituto perché si usa la matrice _visited. Questo algoritmo procede in maniera verticale (inizialmente cerca la coordinata Y per cui sopra non c’è il colore cercato). Poi controlla a destra e a sinistra del punto e se non è stato visitato e corrisponde al colore cercato lo mette in coda (Q); per evitare che la coda aumenti troppo di
  • 6. dimensione le variabili booleane spanLeft e spanRight vengono settate a true quando viene aggiunto un punto e messe a false quando nella colonna vicina non c’è il colore cercato quindi rendendo possibile l’inserimento in coda di un altro punto se nella colonna adiacente si ripresenta il colore cercato. Questo procedimento viene ripetuto finché non vengono visitati tutti i punti presenti in Q, quindi visitate tutte le colonne che hanno almeno un punto del colore specificato. Quando viene settato a true il valore corrispondente al pixel nella matrice _visited si incrementa anche il valore di area e dopo gli spostamenti del punto di interesse vengono salvati gli estremi in maxN, maxE, maxS, maxW. Alla fine se l’area è maggiore di un certo valore di soglia (5000 pixel2) per eliminare le zone troppo piccole dovute all’espansione di imperfezioni del foglio viene aggiunto un pannello opportunamente dimensionato tramite i fattori di scala e tenuto conto dello spazio dal bordo del pictureBox al bordo dell’immagine. Le coordinate vengono salvate anche in _listRect gli opportuni riscaldamenti. ? Private void dipingi() setta l’immagine da visualizzare nella pictureBox a _originalImage e esegue un refresh della pictureBox ? Private void button2_Click(object sender, EventArgs e) procede al salvataggio delle immagini tramite la lista _listRect nella lista _listNewImages una volta completata l’operazione chiude il form ? Private void addMyPanel (Point e, int wid, int hei) colloca un pannello di tipo ScontriniPanel con l’angolo in alto a destra individuato dal punto e, e di larghezza wid e altezza hei. N.B. Queste grandezze devono essere proporzionate alla pictureBox e NON all’immagine in essa contenuta ? Private void pan_PanResizeEvent(object sender, EventArgs e) lancia il metodo replacePanels quando un pannello genera l’evento PanResizeEvent ? Private void aggiornaLista(object sender, EventArgs e) lancia il metodo popListRect quando un pannello lancia l’evento PanModEvent ? Private void popListRect() svuota la lista _listRect e la ripopola sulla base dei panelli esistenti controllando che ogni rettangolo (e quindi ogni pannello) sia dentro i limiti dell’immagine. ? Private void pictureBox1_MouseMove(object sender, MouseEventArgs e) se le variabili _clicked e _insert sono settate a true vuol dire che l’utente sta cercando di inserire un nuovo pannello e lancia quindi la procedura dedicata. ? Private void mouseDown(object sender, MouseEventArgs e) se è stato generato dalla pictureBox vuol dire che è stato cliccato uno spazio senza pannello quindi si sta cercando di inserire un pannello nuovo quindi setta le variabili _clicked e _insert a true aggiunge un pannello di dimensione minima ? Private void mouseUp(object sender, MouseEventArgs e) riporta _cliked a false; se generato dalla pictureBox riporta anche _insert a false e termina l’inserimento del nuovo pannello calcolando la posizione del rettangolo corrispondente ? Private void Form1_ResizeBegin(object sender, EventArgs e) evento generato quando inizia il resize del form; rende invisibili tutti i pannelli e setta _formResize a true
  • 7. ? Private void Form1_ResizeEnd(object sender, EventArgs e) evento generato quando finisce il resize del form se _formResize è impostato a true lancia la procedura replacePanels e riporta_formResize a false ? Private void pictureBox1_Resize(object sender, EventArgs e) se la pictureBox viene ridimensionata senza che siano lanciati gli eventi di resize legati al form (es. con il bottone maximize invece del trascinamento del bordo) lancia la procedura replacePanels ? Private void replacePalens() cancella tutti i pannelli presenti e li ridispone prendendo come riferimento la lista _listRect ? Public void ImageUpdated() per compatibilità con GECScan. Invalida la superficie del form e quindi ne determina il ridisegno ? Private void button3_Click(object sender, EventArgs e) cancella tutte le liste e chiude il form (tasto annulla) ? Private void button4_Click(object sender, EventArgs e) visualizza il popup con le istruzioni ? Private void timer1_Tick(object sender, EventArgs e) riabilita il pulsante button1 finita l’esecuzione dovuta alla sua pressione. 4.2. Class ScontriniPanel Classe derivata dalla classe Panel. Fornisce i pannelli ridimensionabili e modificabili. 4.2.1.Variabili di classe ? Private static ScontriniPanel selected il pannello che viene selezionato tramite pulsante destro ? Private static List<ScontriniPanel> _listPanel lista che contiene tutti i pannelli attualmente visualizzati ? Public List<ScontriniPanel> listpanel get restituisce la lista _listPanel permettendone l’accesso in lettura dall’esterno ? Private static Point mouseDownP punto in cui viene premuto il pulsante del mouse ? Private const int margine dimensione del margine in cui si può ridimensionare il pannello (default 8) ? Private const int splitOffset lunghezza in dopo la quale il trascinamento interno diventa taglio del pannello (default 30) ? Private bool _cliked Variabile per il coordinamento tra i metodi. Se true il pulsante del mouse è premuto ? Private bool _resize Variabile per il coordinamento tra i metodi. Se true si sta cercando di fare il resize di un pannello ? Private bool _cut Variabile per il coordinamento tra i metodi. Se ture si sta cercando di dividere un pannello ? Private bool _insert Variabile per il coordinamento tra i metodi. Se ture si sta cercando di inserire un nuovo pannello ? Private bool _left Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo sinistro
  • 8. ? Private bool _right Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo destro ? Private bool _top Variabile per il coordinamento tra i metodi. Se true si sta ridimensionando il bordo superiore ? Private bool _down Variabile per il coordinamento tra i metodi. Se ture si sta ridimensionando il bordo inferiore 4.2.2.Costruttore ? Public ScontriniPanel() costruttore “fasullo” per poter accedere alla parte pubblica senza dover creare un pannello reale ? Public ScontriniPanel(Point e, int wid, int hei) costruttore reale che genera un nuovo pannello con la coordinata del punto in alto a sinistra corrispondente a “e”, di larghezza wid e altezza hei, oltre a definire i vari gestori di eventi connessi ad ogni pannello e le relative proprietà. 4.2.3.Metodi ? Public void insertNew(Point e) Metodo per ovviare al problema del feedback visivo dell’inserimento di un nuovo pannello quando si fa solo click e trascinamento invece di click e poi ridimensionamento del pannello di dimensioni minime ? Public void insertNewStop() per terminare l’inserimento da usare in coppia a insertNew ? Public void cleanAll() cancella tutti i pannelli esistenti e pulisce la lista _listPanel ? Private void mouseClick(object sender, MouseEventArgs e) quando si clicca con il pulsante destro su un pannello si seleziona, se si ri-clicca con il pulsante destro sullo stesso pannello si deseleziona, se invece si clicca su un altro pannello si uniscono i due pannelli; con il pulsante centrale vengono visualizzate nella console informazioni sul pannello ? Private void mouseDoppioClick(object sender, MouseEventArgs e) se si fa un doppio click con il pulsante sinistro si elimina il pannello ? Private void mouseEnter(object sender, EventArgs e) cambia il colore del pannello quando il mouse entra nella superficie ? Private void mouseLeave(object sender, EventArgs e) ripristina il colore del pannello quando il mouse esce dalla superficie ? Private void mouseDown(object sender, MouseEventArgs e) imposta a true le variabili corrispondenti all’azione che si desidera compiere ? Private void mouseUp(object sender, MouseEventArgs e) ? compie il taglio del pannello ridimensionandone uno e aggiungendo un altro a fianco se è stato rilasciato il pulsante sinistro e se la _cut è a true la direzione di taglio è decisa dal tipo di cursore che viene impostato in mouseMove e lancia l’evento OnPanModEvent ? se l’azione era un ridimensionamento al termine lancia l’evento OnPanResizeEvent ? ripristina le variabili booleane a false
  • 9. ? private void mouseMovi(object sender, MouseEventArgs e) ? setta l’aspetto del cursore in base all’azione che si andrà a compiere ? compie il resize del pannello in base alle coordinate del mouse (ATTENZIONE: le coordinate continuano ad aumentare verso destra e verso il basso anche dopo la fine del pannello. Nel stesso modo verso l’alto e verso sinistra vanno in negativo) ? public void resizeMethod(ScontriniPanel pan, Point e) compie il resize del pannello interessato. 4.2.4.Eventi Generati ? Public event EventHandler PanModEvent gestore dell’evento generato quando un pannello viene modificato ? Protected void OnPanModEvent(EventArgs e) metodo per generare l’evento associato (PanModEvent) ? Public event EventHandler PanResizeEvent gestore dell’evento generato quando un pannello viene ridimensionato ? Protected void OnPanResizeEvent(EventArgs e) metodo per generare l’evento associato (PanResizeEvent) 4.3. Installazione del progetto Per il corretto funzionamento del progetto è necessario copiare: ? visual狠狠撸Show.dll (che andrà a sostituire quello preesistente) ? AForge.dll ? AForge.Imaging.dll ? AForge.Math.dll all’interno della cartella che contiene l’eseguibile DocRetriver.exe 5. Conclusioni L’identificazione viene svolta in 3-4 secondi, molti meno di una nuova scansione. A meno di una pessima qualità di scansione (molti disturbi) o documenti eccessivamente vicini o sovrapposti, l’identificazione propone una divisione corretta senza bisogno di interazione da parte dell’utente. Nel caso che sia necessario l’utente con un numero limitato di click può porre rimedio ad una situazione di errore. Una volta approvata la divisione l’immagine di partenza viene eliminata dalla slide show e viene sostituita da tutte le immagini divise rendendo così la procedura completamente trasparente.