app

SLAMCam: Tracciamento della posizione tramite immagini

Laboratorio didattico di Ingegneria dell'Informazione

Studenti: Eros Reato, Leonardo Vianello, Massimiliano Biason





Parte Client

Il lato client viene eseguito su smartphone ed è costituito da due blocchi fondamentali:

  • La parte di rete, ovvero di download posizioni, aquisizione e stream immagini.
  • La parte di visualizzazione delle nuove posizioni e del percorso complessivo.

Parte di rete

All'avvio dell'applicazione vengono inizializzate le strutture che permettono di salvare i punti scaricati dal server, la finestra dove verrà visualizzata la telecamera e la classe in OpenGL che permette la visualizzazione delle nuove posizioni. Attraverso un menù in alto si può accedere alle impostazioni riguardanti l'indirizzo IP del server e le porte usate per la comunicazione TCP e UDP.

AndroidSetting
Una volta premuto il tasto start, vengono avviati i thread di invio immagini e download posizioni.

  1. Thread UDP
  2. Si tratta di una classe figlia della classe Thread di java. All'avvio essa preleva dal buffer della preview dello schermo lo stream di byte relativi all'immagine corrente mostrata. Viene fatta quindi una codifica dell'immagine in JPEG, ottenendo lo stream di byte che deve essere inviato al server. E' stato deciso di limitare la dimensione dei pacchetti trasmessi a 4096 byte per evitare problemi di perdite dati eccessive attraverso la rete WLAN: lo stream viene quindi diviso per 4096, viene inviato il numero di datagram che formano l'immagine al server (in modo che riesca a ricostruirla correttamente) ed infine tramite un ciclo viene trasmesso l'intero frame.

       while (true) {
          try{
    
            JPGBytes = mCameraPreview.getFrameJPG(mCameraPreview.getImageBuffer());
            Integer totalPack = 1 + (JPGBytes.length - 1) / PACK_SIZE;
            byte[] iBuf = intToByteArray(totalPack);
    
            datagramPacket = new DatagramPacket(iBuf, iBuf.length, inetAddress, mPort);
    
            mSocket.send(datagramPacket); // Invio lunghezza pacchetto JPG
    
            for (int i = 0; i < totalPack; i++) {
               toSend = Arrays.copyOfRange(JPGBytes, i * PACK_SIZE, (i + 1) * PACK_SIZE);
               if (toSend.length <= PACK_SIZE) {
                  mSocket.send(new DatagramPacket(toSend, PACK_SIZE, inetAddress, mPort));
               } else {
                  break;
               }
            }
            try {
               Thread.sleep(FRAME_INTERVAL);
           } catch (InterruptedException e) {
              e.printStackTrace();
              break;
           }
    
           if (Thread.currentThread().isInterrupted())
              break;
    
           nextCycle = System.currentTimeMillis();
           duration = nextCycle - lastCycle;
           fps = (1 / duration) * 1000;
           kbps = PACK_SIZE * totalPack / duration / 1024 * 8;
           String timeLog = "\teffective FPS: " + fps + " \tkbps: " + kbps;
           Log.d("CONTR_FPS", timeLog);
           lastCycle = nextCycle;
    
          } catch(IOException e){
             e.printStackTrace();
          } catch(IllegalArgumentException e){
             e.printStackTrace();
          }
       }
    		
    	

  3. Thread TCP
  4. Il funzionamento di questo thread ha richiesto un funzionamento asincrono rispetto all'invio immagini della parte UDP, poiché c'era il rischio che uno bloccasse l'altro nelle fasi più critiche. Per questo motivo la classe del client TCP viene fatta girare in un task asincrono che si avvia alla pressione del tasto start. L'unico compito di questo task è quello di restare in ascolto sulla porta TCP impostata. Alla pressione del tasto stop questo task viene terminato.
    La classe TCP_client implementa il socket, il quale è un semplice ricevitore di stringhe che vengono passate subito alla classe di gestione delle camere per la determinazione della posizione.

       protected class PositionReceiver extends AsyncTask {
          private TcpClient tcpThread = null;
          @Override
          protected String doInBackground(String... params) {
    
             if(isDefaultStart) { //default init
                tcpThread = new TcpClient(new TcpClient.OnMessageReceived() {
                   @Override
                   //here the messageReceived method is implemented
                   public void messageReceived(String message) {
                      //this method calls the onProgressUpdate
                      publishProgress(message);
                   }
                });
             }
             else{
                tcpThread = new TcpClient(new TcpClient.OnMessageReceived() {
                   @Override
                   public void messageReceived(String message) {
                      publishProgress(message);
                   }
                },params[0], params[1]);
             }
             tcpThread.run();
             if(isCancelled()) tcpThread.stopClient();
                return null;
          }
    
          @Override
          protected void onProgressUpdate(String... values) {
             super.onProgressUpdate(values);
             //response received from server
             Log.d("test", "posizione ricevuta:  " + values[0]);
          }
       }
    					
    

Parte di visualizzazione delle posizioni

Per dare un senso grafico alle posizioni della camera sul display dello smartphone, si è deciso di usare le librerie OpenGL ES (un sottoinsieme delle librerie grafiche OpenGL pensato per dispositivi integrati).
Questa scelta si è dimostrata vincente per poter rappresentare facilmente in un spazio 3D degli oggetti, potendo definire agilmente una vista della scena.
La rappresentazione delle camere è stata fatta con dei triangoli orientati nella direzione in cui si guarda con lo smarthphone. L'ultima camera aggiunta definisce le posizioni e le orientazioni relative delle camere precedenti. Delle linee rosse collegano le camere per mostrare più in chiaro un percorso. Un altro motivo per cui è stata scelta OpenGl ES è l'utilizzo dell'accelerazione grafica della Gpu, permettendo fluidità anche in dispositivi obsoleti.

Triangoli