Upload
truongdat
View
222
Download
1
Embed Size (px)
Citation preview
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
LaboratorioDispense del corso di Elaborazione di Immagini e Audio Digitali
http://imagelab.ing.unimo.it
Prof. Roberto Vezzani
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Agenda
• Programmazione ad oggetti (C++): – Classi e oggetti
– Ereditarietà
– Overloading - Polimorfismo
• Programmazione sotto Window– Programmazione ad eventi
– Gestione delle finestre
• Libreria Imglib– Classi elaborazione
– Classi interfaccia grafica
• Framework VA
• Ambiente Visual Studio (demo)
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
PROGRAMMAZIONE AD OGGETTI IN C++
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Classe
• Può essere vista come una “estensione” del concetto di struct
• Composta da attributi (dati) e da metodi (funzioni)
class Nome {
int Metodo1 (int x, int y);
int Attributo1;char Attributo2;
};
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Interfaccia e Visibilità
• Gli attributi e i metodi privati sono visibili solo dai metodi della classe
• Gli attributi e i metodi pubblici sono visibili anche dall’esterno
class NomeClasse {public:
int i;…
private:int j;…
};
…
NomeClasse Obj;
Obj.i=3;Obj.j=4; ERRORE…
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Costruttori e distruttore
• Costruttore: funzione che viene richiamata automaticamente in fase di allocazione di un oggetto;
• Posso avere più di un costruttore per ogni classe, ciascuno distinguibile per il numero/tipo di parametri
• Prima della deallocazione viene richiamato invece il distruttore
• Il costruttore ha lo stesso nome della classe, può avere parametri e non restituisce niente
• Il distruttore ha lo stesso nome della classe preceduto da ~.
class CProva{
CProva(); // costruttore di default
CProva(int a, int b); // costruttore parametrico
~CProva(); // distruttore
};
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Sintassi
• Tutte le dichiarazioni dei metodi vanno inserite all’interno della dichiarazione della classe
• Le definizioni dei metodi possono essere messe sia nella dichiarazione della classe che fuori
• In questo caso la sintassi è:
tipoOutput NomeClasse::NomeMetodo (parametri){…
}
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Convenzioni sui prefissiIl prefisso del nome di una entità serve ad indicarne il tipo
(convenzione ungherese) . Esempi:
Prefisso Significato
C nome della classe
m_ attributo della classe
p puntatore
i int
b bool
ch char
int iContatore;
char chCarattere;
bool bFlag;
class CPunto{
int m_iX;
int m_iY;
};
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Oggetti composti
• Come attributi di un oggetto posso avere degli oggetti
• L’inizializzazione degli attributi, obbligatoria quando l’oggetto-attributo ha un costruttore parametrico, va specificata nel costruttore dell’oggetto contenitore:
class Contenitore{public:
Contenitore (…);private:
TipoCont Contenuto1;TipoCont Contenuto2;
};
Contenitore::Contenitore (…) : Contenuto1(…), Contenuto2(…), …
{ …}
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Ereditarietà
• Una classe può essere definita come derivata da un’altra classe.
• Il meccanismo dell'ereditarietà permette di modellare una relazione di tipo Is-a.
• L'idea è quella di dire al compilatore che una nuova classe (detta classe derivata) è ottenuta da una preesistente (detta classe base) "copiando" il codice di quest'ultima nella classe derivata eventualmente sostituendone una parte qualora una qualche funzione membro venisse ridefinita.
class ClasseBase {
ClasseBase(int x);
…
};
class ClasseDerivata:
public ClasseBase
{
ClasseDerivata(…): ClasseBase(x)
{ … }
…
};
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Tipi di ereditarietà
• Per default l'ereditarietà è privata, tutti i membri ereditati diventano cioè membri privati della classe derivata e non sono quindi parte della sua interfaccia.
• Posso usare un’ereditarietà pubblica, ma non si può comunque allentare il grado di protezione di un membro ereditato (i membri privati rimangono dunque privati e comunque non accessibili alla classe derivata).
– Soluzione: visibilità protected
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
“protected”
• E’ uno qualificatore di visibilità, insieme a private e public• attributo / metodo private: visibile solo dalla classe base ma non dalla
classe derivata• attributo / metodo public: visibile dalla classe base, dalla classe
derivata e dall’esterno
• attributo / metodo protected: visibile dalla classe base e dalla classe derivata e ma non dall’esterno
• Con l'ereditarietà pubblica i membri ereditati mantengono lo stesso grado di protezione che avevano nella classe da cui si eredita: i membri public rimangono public e quelli protected continuano ad essere protected;
• Con l'ereditarietà protetta i membri public della classe base divengono membri protected della classe derivata; quelli protected rimangono tali.
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Overloading
• Una classe derivata può avere attributi e metodi propri che si vanno ad aggiungere a quelli ereditati.
• Una classe derivata può anche ridefinire metodi. In tale caso, se non specificato, viene eseguita la nuova versione.
• Posso anche ridefinire gli operatori che agiscono sulla classe
• Fondamentale la ridefinizione dell’operatore di assegnamento, che di default esegue una copia bit a bit degli attributi; se tra gli attributi c’è un vettore allocato dinamicamente ottengo una copia del puntatore e non del vettore
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Esempio:
class Stringa {
…
Stringa& operator= (const Stringa &s2){
memcpy(pStringa, s2.pStringa, strlen(s2.pStringa));
return *this;
}
private:
char * pStringa;
};
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Polimorfismo
• L'ereditarietà pone nuove regole circa la compatibilità dei tipi, in particolare se Ptr è un puntatore di tipo T, allora Ptr può puntare non solo a istanze di tipo T ma anche a istanze di classi derivate da T
• Applicazione: posso facilmente realizzare una lista per contenere una serie di istanze di una gerarchia di classi
• Esempio:
• Ho due classi CImmagineAColori e CImmagineBN che derivano da CImmagine
• Ad un puntatore di tipo CImmagine* posso assegnare anche puntatori ad oggetti di tipo CImmagineAColori e CImmagineBN
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Funzioni virtuali
• Problema: se assegno ad un puntatore di tipo CImmagine il puntatore ad una immagine di tipo CImmagineAColori, e richiamo su di essa una funzione f definita in CImmagine e ridefinita in CImmagineAColori, viene eseguita la versione presente in CImmagine.
• Soluzione: dichiarare la funzione f come virtual
• Specificando f come virtual viene eseguita la versione corretta grazie ad una risoluzione run-time.
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Template
• Un template altro non è che codice parametrico, dove i parametri possono essere sia valori, sia nomi di tipo.
• In fase di compilazione viene fatta la sostituzione
template <class TInfo> class TList {
public: TList(); ~TList(); void Store(TInfo Object);
/* ... */ };
TList<int> lista;
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
PROGRAMMAZIONE SOTTO WINDOWS
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Concetti base programmazione ad eventi
• Programmazione strutturata: – ho un main che viene richiamato come prima funzione;
– normalmente si crea un menu che, associato ad un costrutto switch richiama la funzione desiderata
– ho un ciclo del tipo “fino a quando viene premuto il tasto Q”
• Programmazione ad eventi:– Set di funzioni che vengono eseguite ciascuna al verificarsi di un
particolare evento
– Loop dei messaggi che riceve un messaggio per ogni evento e lo smista alla relativa funzione
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Loop dei messaggi
while (TRUE){
if (GetMessage (&msg,NULL,0,0,PM_REMOVE)){// se è il quit esco
if (msg.message == WM_QUIT)
break;
if (!TranslateMDISysAccel(m_hwndClient, &msg) &&
!TranslateAccelerator(m_hwndFrame, m_hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Formato dei messaggi
• Un messaggio è composto da quattro campi:– hWnd: handle della finestra a cui il messaggio è destinato
– iMsg: identificativo del messaggio
– wParam: primo parametro del messaggio
– lParam: secondo parametro del messaggio
• ESEMPIO:– hWnd: finestra attiva
– iMsg: WM_LBUTTONDOWN pressione del tasto sinistro del mouse
– wParam: parametri, ad esempio se il tasto SHIFT è premuto
– lParam: posizione (x,y) del mouse
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Alcuni messaggi importanti
• WM_COMMAND– Comandi del menu
– Bottoni della toolbar
• WM_SIZE– resize di una finestra
• WM_PAINT– Ridisegnare il contenuto di una finestra
• WM_LBUTTONUP, WM_RBUTTONUP, WM_MOUSEMOVE, …– Spostamento del mouse
– Click, doppio click, …
• WM_KEYUP, …– Eventi dalla tastiera
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Windows: tutto è una “finestra”!
Finestra Child
Finestra client
Finestra Frame
Finestra Toolbar
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Windows
• Ad ogni finestra è associato un Handle univoco (hWnd)
• Una finestra viene creata a partire da una classe, che funge da “modello”. Per creare una finestra nuova si può usare una classe esistente oppure registrarne una nuova.
• Ad ogni classe di finestre è associata una funzione callback, che contiene le routine di risposta agli eventi delle relative finestre– Funzione callback della finestra frame: riceve, ad esempio, i messaggi
provenienti dal menu
– Funzione callback delle finestre child: ricevono, ad esempio, i messaggi di repaint
• Anche un controllo button è una finestra, generata da una classe già esistente (BUTTON), con un suo hWnd, una sua callback function…
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Gestione dei Menu
• I menu possono essere creati dinamicamente COMPLESSO
• Modalità “statica”: tramite il file di risorse
• Il menù viene caricato all’inizio e rimane inalterato durante l’esecuzione della applicazione
• Ad ogni voce di menu corrisponde un identificativo numerico
• Alla pressione di una voce del menu viene inviato un messaggio WM_COMMAND alla finestra Frame con parametro l’ID della voce di menu scelta
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
LIBRERIA IMGLIB
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Contenuto della libreria
• La versione scaricabile è una parte della libreria Imglib++ sviluppata dal laboratorio Imagelab. Sono presenti alcune sezioni:
• Utilitylib: classi di utilità generale (vettori, matrici, numeri complessi, …)
• Imglib: classi per la gestione delle immagini a colori, a livelli di grigio e per le maschere binarie
• Graphiclib: classi per l’interfaccia grafica
• JpegLib: apertura e salvataggio di immagini in formato JPEG
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Classi per le immagini• E’ stata definita una gerarchia di classi • CImage: classe base astratta• CImageGray: immagini a livello di grigio• CImageRGB: Immagini a colori RGB• CImageMask: Immagini binarie
CImage
CImageGray CImageRGB
CImageMask
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CImage
• E’ la classe base. Definisce le caratteristiche comuni a tutte le immagini e l’interfaccia che una classe immagine deve avere (tramite funzioni virtual)
• Vantaggi:– interfaccia comune a tutti i tipi di immagine– posso creare, ad esempio, liste di immagini
• Attributi:– int m_iWidth; // larghezza – int m_iHeight; // altezza– int m_iDim; // w * h
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CImage (2)
• Metodi principali:– int GetHeight();– int GetWidth(); – int GetDim();– bool WriteToFile(FILE* f);– bool ReadFromFile(FILE* f);
• Per recuperare il tipo di immagine– int GetType();
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CImageRGB e CImageGray
• Prevedono metodi per leggere e modificare i valori dei singoli pixel:– valore = GetPoint(x,y);
– valore = GetPoint(i);
– SetPoint(x,y,valore);
– SetPoint(i,valore);
• Posso recuperare il puntatore all’area dati– BYTE* GetPixMap();
– Crgb* GetPixMap();
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CApplication
• Classe base per la creazione di una applicazione:– Win32– MDI– Con Toolbar e StatusBar
• L’applicazione è vuota; per aggiungere contenuto è consigliato derivare da essa una nuova classe (Es.: CMyApplication)
• Contiene già il loop dei messaggi, che pertanto non deve essere riscritto. E’ inserito nel metodo Start(), che deve essere richiamato dopo aver istanziato un oggetto di tipo CApplication.
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CMyApplication
• Attributi: variabili e oggetti che definiscono lo stato della vostra applicazione
• Costruttore: inizializzazione dello stato, inizializzazione e creazione della barra di stato, della toolbar, della barra dei menu,
• FrameWndProc: è la ridefinizione della Window Procedure della finestra frame. Va completata con la risposta ai messaggi di interesse, in particolare con le risposte ai comandi del menu
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Classi Window• Per la gestione dell’output a video è stata creata una gerarchia di
classi finestra• La classe base definisce le funzioni di creazione, distruzione,
ridimensionamento
CBaseWindow
CColorWindow CLogWindow
CImageWindow
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CColorWindow: uso
• Usata per visualizzare oggetti CImage
• Nel costruttore devo specificare il titolo della finestra, l’hwnd della finestra parent (di norma la finestra client) e l’hwnd della finestra client
• Per visualizzare la finestra devo invocare il metodo Show()
• Per aggiornare la finestra con una immagine devo invocare la funzione UpdateWithImage()
• Per togliere dalla finestra l’immagine uso UpdateWithNoImage()
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CColorWindow: uso (2)
• L’immagine usata per aggiornare la finestra non viene salvata all’interno della finestra stessa
• Posso anche disegnare e scrivere sulla finestra tramite i metodi:– bool DrawLine(…);– bool DrawRectangle(…);– bool WriteText(…);– bool DrawVector(…);– bool DrawRegion(…);
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CImageWindow
• Deriva da CColorWindow
• Memorizza l’immagine usata per l’aggiornamento della finestra
• Se si modifica l’immagine memorizzata, è necessario aggiornare la finestra con il metodo UpdateWithStoredImage()
• Posso recuperare il puntatore all’immagine memorizzata con il metodo GetImagePointer
• ATTENZIONE: Non usare mai il metodo UpdateWithImage passando come parametro il puntatore all’immagine già contenuta nella finestra
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
UtilityLib
• Contiene diverse classi di utilità generale:– CMatrix<tipo> : template per la creazione di matrici
– CVector<tipo> : template per la creazione di matrici
– CListOf<tipo>: template per liste di oggetti
– CPointerList<tipo>: template per liste di puntatori ad oggetti
– CFileCSV: apertura, lettura e scrittura di file di testo CSV
– CComplex: numeri complessi
– CStr: classe stringa
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CPointerList
• Usa operatori simili a quelli usati per l’accesso ai database:– MoveFirst()
– MoveNext()
– MovePrev()
– MoveLast()
– GetItem()
– Insert()
– RemoveItem() elimina il puntatore ma non distrugge l’oggetto
– DeleteItem() elimina il puntatore e distrugge l’oggetto
– Purge()
– PurgeAndDelete() vuota la lista e distrugge gli oggetti
– EOL()
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
CListOfWindows
• Deriva da CPointerList<CBaseWindow>
• Permette la creazione di un menu da cui aprire le finestre che contiene
• Si possono usare le funzioni per l’aggiunta di nuove finestre:– CColorWindow* AddNewColorWindow(char* szWindowTitle);
– CImageWindow* AddNewImageWindow(char* szWindowTitle);
– CLogWindow* AddNewLogWindow(char* szWindowTitle);
• Le finestre create non sono visualizzate. Per visualizzarle si può usare la voce del menu (se creato) oppure il metodo:– bool Show(char* szWindowTitle);
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
FRAMEWORK EIA
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Elenco dei file presenti
• application.h
• OperazioniPuntuali.h
• resource.h
• Application.cpp
• Main.cpp
• MenuCommand.cpp
• OperazioniPuntuali.cpp
• VideoProcessing.cpp
• Librerie ImgLib, UtilityLib, GraphicLib, JpegLib
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Aggiunta di una nuova operazione puntuale• OperazioniPuntuali.h : dichiarazione (prototipo) della
funzionebool Mirror(CImageRGB* pimgRGB);
• OperazioniPuntuali.cpp : definizione della funzionebool Mirror(CImageRGB* pimgRGB){Crgb rgb1, rgb2;int x,y,w,h;…
for (y=0;y<h/2;y++) for (x=0;x<w;x++) …
}
• Resource: inserimento di una voce del menu e settaggio IDID: IDM_OPERATION_MIRROR
liih i d ll di hi i d ll f i
Roberto Vezzani - Imagelab – Università di Modena e Reggio Emilia
Aggiunta di una nuova operazione puntuale (2)
• MenuCommands.cpp: aggiunta della definizione della funzionebool OnOperationMirror (HWND hwnd){
…
Mirror(pimgRGB);
…
}
• Application.cpp: modifica della callback function della funzione frame per gestire il messaggio del menu:
case IDM_OPERATION_MIRROR:
OnOperationThreshold(hwnd);
return 0;