martedì 2 gennaio 2018

Misurare distanze con realta' aumentata

Un piccolo esperimento sulla possibilita' di misurare distanze utilizzando la realta' aumentata e l'utilizzo di un semplice marker.

Per questa applicazione e' stato modificato l'esempio ARSimple di ARToolKit per Android.

Il codice puo' essere scaricato da GitHub


La cosa piu' difficile e' stato mostrare in tempo reale la distanza sulla interfaccia perche' con OpenGL su Android non esiste un modo semplice di renderizzare testo. La soluzione e' un po' contorta ma funziona. Dalla classe ARSimplerender viene scritta una sharedpreference con all'interno il valore della distanza in mm, nella classe ARSimple (che gestisce la UI) c'e' un timer che legge ogni 0.1 secondi il valore della sharedpreference e la mostra a video nella textview

Per avere un'idea della precisione di tale metodo si puo' consultare il seguente poster o l'articolo
Measuring ARTootKit accuracy in long distance tracking experiments (P. Malbezin,W. Piekarski,B.H. Thomas) 2002 Augmented Reality Toolkit, The First IEEE International Workshop

La massima distanza che sono riuscito a misurare e' stata di circa 2.6 m

ps : la applicazione e' stata provata su Nexus 5 e Nexus 5x, Sul 5x la applicazione NON funziona perche' il sensore della camera e' ruotata di 90° rispetto alla norma (questa cosa mi ha ovviamente fatto diventare pazzo per un paio di giorni)

ps: una cosa curiosa. Mentre stavo facendo le prove ho inquadrato senza volerlo la tastiera del Mac e ....e' comparso il cubetto ....in pratica ARToolkit ha confuso il marker Hiro con i simboli sulla tastiera





venerdì 29 dicembre 2017

Compilare ARToolKit su Android Studio 3

Le istruzioni per installare ARToolKit su Android Studio sono piuttosto vecchie e di fatto non funzionano nella configurazione attuale (sono state scritte nel 2016)

Per fare funzionare gli esempi, dopo avere compilato la libreria nell'NDK (come da istruzioni), si devono modificare i file di progetto come segue (vedi linee evidenziate in giallo)

---------------------------
buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath 'com.android.tools.build:gradle-experimental:0.11.1'

        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }
}

allprojects {
    repositories {
        jcenter()
    }
}
---------------------------


gradle.wrapper.properties
---------------------------
#Fri Dec 29 14:39:59 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
---------------------------


build.gradle (Module ArSimple)
---------------------------

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 23        buildToolsVersion = "23.0.2"
        defaultConfig.with {
            applicationId = "org.artoolkit.ar.samples.ARSimple"            minSdkVersion.apiLevel = 15            targetSdkVersion.apiLevel = 22            versionCode = 1            //Integer type incremented by 1 for every release, major or minor, to Google store            versionName = "1.0" //Real fully qualified major and minor release description
            buildConfigFields.with {
                //Defines fields in the generated Java BuildConfig class, in this case, for                create() {           //default config, that can be accessed by Java code                    type = "int"     //e.g. "if (1 == BuildConfig.VALUE) { /*do something*/}".                    name = "VALUE"                    //See: [app or lib]/build/generated/source/buildConfig/[package path]/                    value = "1"      //     BuildConfig.java                }
            }
        }
    }

    android.buildTypes {
        release {
            minifyEnabled = false            proguardFiles.add(file('proguard-rules.pro'))        }
    }

    android.productFlavors {
    }
    android.sources {
        main {
            jni {
                source {
                    srcDirs = ['src/main/nop']
                }
            }
        }
        main {
            jniLibs {
                source {
                    srcDirs = ['src/main/libs']
                }
            }
        }
    }
    
}

dependencies {
    //compile 'com.android.support:support-v4:23.0.1'    //compile 'com.android.support:appcompat-v7:23.0.1' //Only required when the target device API level is greater than    compile project(':aRBaseLib')
}     

------------------------------------------------------

martedì 28 novembre 2017

Maratona Firenze 2017

Il solito stupido giochino di ogni anno...quante volte sono finito su foto pubblicate da siti di giornali??
Quest'anno sono particolarmente riconoscibile per la pelata

In secondo piano




In ginocchio tenendo il nastro di partenza



Subito dopo la curva entrando in Piazza del Duomo

lunedì 20 novembre 2017

HAX emulator error per Android Studio su Mac High Sierra

Oggi ho ripreso dopo un po' di tempo il Mac per sviluppare su Android, in particolar modo dopo l'aggiornamento ad HIgh Sierra



La novita' e' che l'emulatore Android non ne voleva sapere di funzionare uscendo con Exit Code 0 dopo aver posto le rimostranze per non aver trovato l'accelerazione HAX

Dopo averne provate diverse la soluzione e' stata File->Invalidate Cache->Invalidate and Restart




giovedì 16 novembre 2017

Nexus 5x / RTKLib / Geo++ / DGPS

Stessa prova vista in questo post ma con un Nexus 5X.
L'applicazione Geo++ non e' quella presente sul market ma si tratta di una beta ricevuta dallo sviluppatore perche' Nexus 5x ha delle particolarita' (in realta' non e' molto chiaro se sia Nexus 5X oppure l'implementazione delle API perche' su Android Oreo stock la beta Geo++ non funziona mentre si ottengono risultati con Oreo beta)


Il punto topografico di riferimento e' sempre il solito come il post processing

Il punto calcolato risulta essere
43.833026632 11.307094997 201.0573

in precedenza i dati erano
dalla scheda del punto topografico
43.83304783 11.30706278 203.3

I dati post processati con RTKLib ed acquisiti con Nexus 9
43.833068271 11.307051667 184.74

da segnalare su questo argomento la seguente pubblicazione scientifica che riporta dei risultati decisamente interessanti

Precise GNSS Positioning Using Smart Devices
Eugenio Realini, Stefano Caldera Lisa Pertusini,Daniele Sampietro
Geomatics Research & Development s.r.l. (GReD), via Cavour 2, c/o ComoNExT, 22074 Lomazzo (Como), Italy

mercoledì 15 novembre 2017

Creare report PDF in Android

Ogni tanto (raramente) puo' essere necessario creare un report in una applicazione Android (anche se questa operazione e' piu' tipicamente indirizzata ad applicazione Desktop)

La soluzione piu' semplice e' appoggiarsi ad una libreria per la generazione di PDF come iTextPdf

per configurare le dipendenze si deve includere in build.gradle

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'    })
    compile 'com.android.support:appcompat-v7:26.+'    compile 'com.android.support.constraint:constraint-layout:1.0.2'    compile 'com.android.support:design:26.+'
    //dipendenza PDF    compile 'com.itextpdf:itextg:5.5.9'
    testCompile 'junit:junit:4.12'}

Fatto cio' si puo' procedere come in seguito. L'unico aspetto di interesse e' che quando si lancia l'intent per la visualizzazione del Pdf, a causa della gestione dei permessi, si deve gestire l'errore  android.os.FileUriExposedException

---------------------------------------------------------------------------------------

package com.example.lucainnocenti.photonotation;

import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ReportActivity extends AppCompatActivity {

    private Button pulsante;
    private FileOutputStream output;

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_report);

        pulsante = (Button) findViewById(R.id.buttonpdf);
        pulsante.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View view) {
                try {
                    try {
                        crea_pdf();
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (DocumentException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void crea_pdf() throws IOException, DocumentException {
        File pdfFolder = new File(Environment.getExternalStorageDirectory().getPath(), "Photonotation");
        if (!pdfFolder.exists()) {
            pdfFolder.mkdir();
            Log.i("Photonotation", "Pdf Directory created");
        }

        //Create time stamp        Date date = new Date() ;
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(date);

        String percorso = pdfFolder.getAbsolutePath() + "/" + timeStamp +".pdf";
        Log.i("Photonotation", percorso);

        File myFile = new File(percorso);

        output = new FileOutputStream(percorso);
        Document document = new Document(PageSize.A4);
        PdfWriter.getInstance(document, output);
        document.open();
        document.add(new Paragraph("Luca"));
        String path = "/storage/emulated/0/Photonotation/20171031_140238.jpg";
        Image image = Image.getInstance(path);
        document.add(image);

        document.close();

        // visualizza il pdf prodotto        
        // le prime righe servono ad evitare android.os.FileUriExposedException        
        if(Build.VERSION.SDK_INT>=24){
            try{
                Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
                m.invoke(null);
            }catch(Exception e){
                e.printStackTrace();
            }
        }


        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(myFile), "application/pdf");
        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        startActivity(intent);


    }
}

Nexus 9 / RTKLIB/ Geo++ / DPGS

Dopo la prova del precedente post ho provato ad usare l'applicazione Geo++ su Nexus 9 con RTKLIB in postprocessing per vedere se era possibile ottenere una correzione DGPS



Il punto trigonometrico di riferimento e' sempre il solito visto qui . La novita' e' che l'antenna GPS della Provincia di Firenze che usavo come antenna base per la correzione DGPS non fornisce piu' dati probabilmente a seguito della dismissione della Provincia stessa. Un sostituto e' stato trovato nell'antenna base dell'IGM posta in via Baracca a Firenze i cui dati possono essere scaricati a questo link

http://www.epncb.oma.be/_networkdata/siteinfo4onestation.php?station=IGMI00ITA

e piu' in dettaglio qui (la sigla della stazione e' igmi. i dati sono ordinati per cartelle del giorno dell'anno progressivo e dell'ora di acquisizione. I dati del giorno 311 per esempio ora T avranno un nome file del tipo igmi311t.17d.Z)

ftp://igs.bkg.bund.de/EUREF/nrt/

I dati relativi dalla scheda del punto topografico indicano una posizione di riferimento
43.83304783 11.30706278 203.3
I dati post processati con RTKLib vengono indicate le seguenti coordinate
43.833068271 11.307051667 184.74

La cosa che mi disturba e' che RTKLib non fornisce l'errore di posizionamento

I dati post processati dalla ditta che fornisce Geo ++ forniscono un punto (nessun errore di posizionamento fornito)
43,833042 11,307012 171.7541

Gli stessi dati processati con Leica GeoOffice di Leica portano una posizione completamente differente, in particolare e' completamente sballato il dato di quota
11° 22' 52".68555 -43° 49' 59".11283 1023.8346

considerando che le differenze nella posizione si trovano nella quinta posizione decimale dopo la virgola non sembra proprio male (lasciando perdere la quota che pero' non e' di mio interesse)

Aruco Tag e filtri Kalman

Usando gli Aruco tag in ambiente esterno con illuminazione solare a diverse ore e in diversi periodi dell'anno ho trovato un errore nell...