NasaWorldWind: Mappare Webcam sul Terreno
Debiasi Alberto
Sommario
Descrizione Generale del Progetto: .................................................................................................................. 2
Scelta Formati: ................................................................................................................................................ 3
Oggetto WebCam: ............................................................................................................................................ 4
Aggiornamento immagine mappata:................................................................................................................ 5
Gestione Visibilità: ........................................................................................................................................... 7
Gli Stati di una WebCam:.................................................................................................................................. 7
Layer per le WebCam: ...................................................................................................................................... 8
Gestione Rotazione: ......................................................................................................................................... 9
Gestione Risoluzione WebCam: ..................................................................................................................... 11
Gestione Salvataggio/Caricamento WebCam:................................................................................................ 12
Interfaccia Grafica: ......................................................................................................................................... 14
Descrizione Generale del Progetto:
Il progetto è strutturato nel seguente modo:
Il package �������� contiene le immagini utilizzate
nei pulsanti. Il package ��� _Nasa contiene le classi java:
• Il package ������������� contiene la classe � ������� !�"#.java che si occupa di salvare e caricare le webcam mappate sul terreno.
• Il package $%&'() contiene le classi che gestiscono i pannelli e i relativi ascoltatori.
• Il package *+, -./0 contiene gli oggetti principali utilizzati; l’oggetto Clock viene utilizzato per “tenere” il tempo delle varia operazioni, l’oggetto WebCam rappresenta una webcam (verrà descritto in seguito), mentre l’oggetto WebCamSer contiene gli attributi della webcam utilizzati per salvare e caricare le webcam.
• Il package WebCamFormatManagement contiene delle classi che saranno utilizzate come thread per gestire la connessione a una webcam.
Scelta Formati:
In internet i principali formati utilizzati delle webcam sono due:
• MJPEG: è un formato video
• JPG: è un formato immagine
In questo progetto ho gestito i due formati in modo diverso.
Formato MJPEG:
1. Connettersi a WebCam 2. Se l’immagine è nuova:
a. acquisisco l’immagine b. aggiorno l’immagine in
NasaWorlWind. 3. …. 4. …. 5. Se l’immagine è nuova:
a. acquisisco l’immagine b. aggiorno l’immagine in
NasaWorlWind. 6. Disconnettersi da WebCam
Formato JPG:
1. Connettersi a WebCam 2. Acquisisco l’immagine 3. Se l’immagine acquisita è nuova:
a. aggiorno l’immagine in NasaWorldWind.
4. Disconnettersi da WebCam 5. …. 6. …. 7. Connettersi a WebCam 8. Acquisisco l’immagine 9. Se l’immagine acquisita è nuova:
a. aggiorno l’immagine in NasaWorldWind.
10. Disconnettersi da WebCam
In genere il formato migliore è MJPEG poiché l’aggiornamento della webcam remota è molto più frequente,
inoltre è necessario connettersi solo la prima volta.
Ogni webcam in formato MJPEG viene gestita da un thread di tipo ManagementsJPEG, mentre le webcam
in formato JPG vengono gestite da un thread di tipo ManagementsJPG.
Oggetto Webcam:
Tutte le informazioni riguardanti le webcam remote utilizzate sono contenute in un arrayList di
WebCamObject, quest’ultima contiene i seguenti campi:
/*gli stati della WebCam*/
Boolean isActive; Boolean isStarted; Boolean isRunning;
/*le informazioni generali della WebCam*/
String nameWebCam; String url; String type; int index; float quality; double rotAngle;
/*le informazioni sul punto di vista*/
double headingAngle; double pitchAngle; double distance;
/*gli oggetti collegati alla WebCam*/
MySurfaceImage surfaceImage; SurfaceCircle surfaceCircle; GlobeAnnotation annotation; Thread thread;
/*le informazioni sul tempo di aggiornamento della webCam*/
long frameRate; long currFrameRate; long currDelay; long lifeTime;
/*le informazioni sulla dimensione dell'immagine */
int imageHeight; int imageWidht; int rotatedImageHeight; int rotatedImageWidht; int originalImageHeight; int originalImageWidht;
/*le informazioni sul settore */
double sectorLatitude; double sectorLongitude; double sectorHeight;
/*le informazioni sui vertici della WebCam*/
double xUpLeft; double yUpLeft; double xUpRight; double yUpRight; double xDownLeft; double yDownLeft; double xDownRight; double yDownRight;
Gestione Aggiornamento immagine:
E’ importante decidere ogni quanto aggiornare l’immagine mappata; se l’intervallo di tempo è troppo
breve, le prestazioni ne possono risentire.
Ho utilizzato i seguenti attributi per ogni webcam per gestire l’aggiornamento dei quest’ultima:
• Il frameRate è il valore di tempo (in millisecondi) impostato dall’utente che si attende prima di
aggiornare l’immagine sul terreno. Non è detto che il frameRate corrisponda al currFrameRate
poiché le webcam remote possono essere aggiornate con minor frequenza (ad esempio se una
webcam si aggiorna ogni 5 sec e si imposta un frameRate di 1sec).
• Il currFrameRate è il valore di tempo (in millisecondi) reale che il programma attende prima di
connettersi alla webcam remota.
• Il delay è l’intervallo di tempo da quando il programma acquisisce l’immagine a quando la mappa
sul terreno. Questo valore è influenzato dalla connessione, dalla risoluzione dell’immagine da
mappare e dalla rotazione dell’immagine.
• Lo standBy è il tempo nel quale il processo che gestisce la webcam è attivo. Passato questo tempo il
processo viene interrotto. Si azzera ogni volta che la webcam sul terreno è visibile. Viene introdotto
questo attributo per rendere più efficiente il programma interrompendo momentaneamente i
processi che gestiscono le webcam non utilizzate.
Prima di prendere l’immagine e mapparla si fanno i seguenti controlli:
1. Controllare se non è tempo di mettere in standBy il processo.
2. Controllare se la webcam sul terreno è visibile.
3. Attendere che il tempo sia maggiore del currFrameRate.
Il seguente codice viene utilizzato dai processi che gestiscono le webcam in formato MJPEG, in particolare
quando la webcam remota è stata aggiornata.
public void stateChanged(ChangeEvent e) { //se il tempo è maggiore del tempo di standBy if (SurfaceImages.ListWebCamObject.get(index).getLifeTime() < currFrameRate.leggi()) { //sostendo il processo new VideoManagement().suspendWebCam(index); currFrameRate.avanzaDaCapo(); } // se la webcam è visibile if (new VideoManagement().videoIsVisible(index) == 2) { //se è ancora presto cioè il tempo è minore di frameRate si aspetta long wait = frame - currFrameRate.leggi(); if (wait > 0) { try { Thread.sleep(wait); } catch (Exception ex) { } } SurfaceImages.ListWebCamObject.get(index).setCurrFrameRate(currFrameRate.leggi()); currDelay.avanzaDaCapo(); byte[] segment = parser.getSegment(); if (segment.length > 0) { try { // ricavo l'immagine image = ImageIO.read(new ByteArrayInputStream(segment)); } catch (Exception o) { } // mappo l'immagine sul terreno new VideoManagement().insertImage(image, index, rotGrade, scale_reduce); // salvo il ritardo SurfaceImages.ListWebCamObject.get(index).setCurrDelay(currDelay.leggi()); currFrameRate.avanzaDaCapo(); } }
Gestione Visibilità:
Per aumentare le prestazioni, i processi che gestiscono la connessione alle Webcam devono essere
interrotti quando la Webcam mappata sul terreno non è visibile.
Per essere visibile deve rispettare due condizioni:
1. Deve essere sul (o vicino al) punto di vista dell’utente.
2. L’utente deve essere a una distanza tale da poterla vedere in modo chiaro.
Per la gestione del punto 1. utilizzo dei cerchi sul terreno; ogni webcam ha un cerchio , che chiamo cerchio
di visibilità, che ha diametro pari alla diagonale dell’immagine mappata sul terreno. Il punto di vista
dell’utente , che chiamo cerchio di vista, è rappresentato da un cerchio di dimensione variabile sul terreno
ma di dimensione fissa per numero di pixel del monitor. Quando il cerchio di vista e il cerchio della webcam
si intersecano, la condizione 1. è rispettata.
Per la gestione del punto 2. utilizzo la dimensione della webcam sul monitor, infatti una immagine è visibile
solo se ha una dimensione in pixel maggiore di un determinato valore.
Il cerchio di vista e il cerchio di visibilità di ogni webcam ha tre stati:
1. NON ATTIVO: Il cerchio non interseca nessuna webcam sul terreno.
2. QUASI ATTIVO:Il cerchio interseca una o più webcam sul terreno ma quest’ultima è troppo distante.
3. ATTIVO: Il cerchio interseca una o più webcam e quest’ultima è ben visibile.
Queste immagini mostrano i diversi stati del cerchio di vista: nella prima immagine il cerchio è non attivo,
nella seconda il cerchio di vista è quasi attivo, mentre nella terza il cerchio è attivo.
La maggior parti delle operazioni che riguardano la visibilità sono gestite dalla classe
VisibleWebCamListener.
Gli Stati di una Webcam:
Ogni webcam mappata sul terreno può avere i seguenti stati:
• isActive: se questo valore è true significa che la webcam è considerata dal programma, cioè viene
settato appena la webcam è creata. Diventa false solo quando la webcam viene eliminata.
• isStarted: questo valore è true quando la webcam viene “fatta partire” cioè quando il cerchio di
vista dell’utente interseca il cerchio di visibilità della webcam.
• isRunning: se questo valore è true significa che il processo di gestione della webcam è in
esecuzione. Diventa false quando la webcam non viene vista dall’utente per un tempo maggiore del
tempo di standBy.
Layer per le Webcam:
Ci sono 3 layer per gestire le webcam:
• Annotation Layer: è utilizzato per contenere le informazioni sullo stato delle webcam e sul tempo di
aggiornamento. Fa riferimento all’oggetto annotation presente in ogni oggetto WebCamObject.
• Surface WebCam: è il layer principale, contiene le webcam inserite dall’utente. Fa riferimento
all’oggetto surfaceImage presente in ogni oggetto WebCamObject.
• Surface Objects: è utilizzato per contenere il cerchio di vista dell’utente, il cerchio di visibilità delle
webcam, l’oggetto per l’inserimento di una nuova webcam. Fa riferimento all’oggetto surfaceCircle
presente in ogni oggetto WebCamObject.
In particolare l’AnnotationLayer è strutturato nel seguente modo:
• La prima parte contiene il nome o lo stato della Webcam.
• La seconda parte contiene il frameRate corrente.
• La terza parte contiene il frameRate impostato dell’utente.
• La quarta parte contiene il delay corrente.
Queste immagini mostrano diverse annotazioni di una webcam: nella prima immagine la webcam è stata
inserita ma il processo di gestione non è ancora stato attivato. Nella seconda immagine il processo di
gestione si sta connettendo alla webcam remota. Nella terza immagine il processo di gestione è in
esecuzione, mentre nella quarta il processo è entrato in standBy, cioè è stato interrotto.
In queste immagini si vedono i 3 layer: nella prima sono presenti tutti e tre, nella seconda il webcam layer e
l’annotation layer, e nella terza solo il webcamLayer.
Gestione Rotazione:
Poiché NasaWorldWind non gestisce la rotazione di immagini, ho introdotto una procedura per ruotare
l’immagine e ridimensionarla. Inoltre questa procedura mantiene le proporzioni altezza/larghezza
dell’immagine.
1. Inserisco l’altezza (in metri) sell’immagine sul terreno.
2. Creo un settore quadrato (con lato uguale all’altezza della immagine).
3. Prendo l’immagine, la ruoto.
4. Modifico le dimensioni del settore in base alla dimensione dell’immagine ruotata.
Il seguente codice descrive il punto3. :
public BufferedImage rotateImage(BufferedImage image, double rotGrade,int index ) { double angleRad=rotGrade; angleRad=Math.toRadians(angleRad); double sin = Math.abs(Math.sin(angleRad)); double cos = Math.abs(Math.cos(angleRad)); int w = image.getWidth(); int h = image.getHeight(); int neww = (int)Math.floor(w*cos+h*sin); int newh = (int)Math.floor(h*cos + w*sin); BufferedImage result=null; try{ result = new BufferedImage(neww, newh, BufferedImage.TYPE_INT_ARGB); //NOTE *A*RGB }catch(Exception e){ System.err.println("ERRORE! "+index); } catch(OutOfMemoryError o){ System.err.println("ERRORE! MEMORIA "+index); } Graphics2D g = result.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.translate((neww-w)/2, (newh-h)/2); g.rotate(angleRad, w/2, h/2); g.drawRenderedImage(image, null); return result; }
In queste immagini si può notare la rotazione di una webcam: nella prima di 0°, nella seconda di 70° e nella
terza di 300°.
Gestione Proporzioni Webcam:
Dopo aver inserito una webcam è possibile cambiarne l’altezza e la lunghezza.
In queste immagini si possono notare le differenti dimensioni della stessa webcam.
Gestione Forma Webcam:
E’ possibile modificare la forma della webcam sul terreno in modo da renderla compatibile con la
prospettiva di chi la osserva. Per svolgere questa operazione si possono spostare i quattro vertici della
webcam. Inoltre è possibile rendere trasparente l’immagine per facilitare il corretto posizionamento della
webcam.
Queste immagini descrivono le fasi per modificare la forma di una webcam: prima si rende trasparente, poi
si spostano i vertici a piacimento e infine si toglie la trasparenza .
Gestione Risoluzione Webcam:
Ci sono molte webcam di alta risoluzione, e questo può influire sulle prestazioni del programma. Per questo
ho introdotto una procedura per ridimensionare l’immagine.
public static Image getScaledInstanceAWT(BufferedImage source, double factor) { int w = (int) (source.getWidth() * factor); int h = (int) (source.getHeight() * factor); return source.getScaledInstance(w, h, Image.SCALE_SMOOTH); }
Queste immagini mostrano la stessa webcam con diverse risoluzioni.
Gestione Punto di Vista WebCam: Ogni webcam ha un proprio punto di vista, cioè la posizione nella quale è collocata la webcam. È possibile
posizionare per ogni webcam il suo punto di vista, in modo da avere la giusta prospettiva. Bisognerà
salvare l’angolazione, l’altezza e la distanza dalla webcam.
Queste immagini mostrano la stessa webcam con diversi punti di vista: la prima immagine mostra la
webcam con il punto di vista perpendicolare, mentre nella seconda il punto di vista è stato modificato per
avere la giusta prospettiva.
Gestione Salvataggio/Caricamento WebCam: Dopo aver inserito una o più webcam nel programma, è possibile salvare lo stato corrente in un file di
estensione .nwc (NasaWebCam).
Questa procedura utilizza l’oggetto WebCamObjectSer, è simile all’oggetto WebCamObject con la differenza
che non contiene gli oggetti dinamici:
/*gli oggetti collegati alla WebCam*/
MySurfaceImage surfaceImage; SurfaceCircle surfaceCircle; GlobeAnnotation annotation; Thread thread;
Inoltre questa classe è serializzata.
Le operazioni di salvataggio/caricamento delle webcam utilizzano la serializzazione. Le fasi sono le
seguenti:
1. Per ogni WebCamObject (cioè per ogni webcam), viene creato un oggetto WebCamObjectSer .
2. L’arrayList di WebCamObjectSer viene serializzato in un file a scelta dell’utente.
3. Per caricare si deserializza dal file l’arrayList di WebCamObjectSer .
4. Si converte ogni WebCamObjectSer in un WebCamObject.
Questa parte di codice viene utilizzata per salvare le webcam nel file:
public void saveWebCams(File file) { try { // Apriamo il file ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file)); oos.writeObject(new Integer(SurfaceImages.ListWebCamObject.size())); // Salviamo tutte le webCam for (int i = 0; i < SurfaceImages.ListWebCamObject.size(); i++) { WebCamObjectSer webC = new WebCamObjectSer(SurfaceImages.ListWebCamObject.get(i)); oos.writeObject((WebCamObjectSer) webC); } // Chiudiamo il file oos.close(); } catch (Exception e) { e.printStackTrace(); } }
Interfaccia Grafica:
L’interfaccia di questo programma è composta da questo pannello laterale:
Questo pannello
gestisce il punto
di vista della
webcam
Nella parte File si possono
caricare oppure salvare le
webcam inserite.
Nella parte SELECTED
WEBCAM INFO vengono
visualizzate tutte le
informazioni relative alla
webcam selezionata,
inoltre è possibile
modificare le
caratteristiche della
webcam.
Nella parte LAYERS si
possono scegliere i layer da
visualizzare
Nella parte WEBCAMS
vengono visualizzate
tutte webcam con il loro
nome
Nella parte NEW
WEBCAM INFO si
settano gli attributi
per inserire una nuova
webcam.
Questo
pulsante
permette di
andare alla
webcam
Questo pulsante
permette di
rimuovere la
webcam
selezionata
Questo
pulsante
permette di
aggiungere
una nuova
webcam
con i
settaggi
impostati
Top Related