Autore Topic: Inserire immagine 3D e ruotarla  (Letto 2521 volte)

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Inserire immagine 3D e ruotarla
« il: 15 Febbraio 2014, 19:46:08 CET »
0
Salve,
sto progettando un'applicazione che prevede la presenza di un corpo umano in 3d che puo essere ruotato, ingrandito, rimpicciolito dall'utente. Il modello in file .obj già ce l'ho.. Il problema grosso è che non riesco a trovare nessuna guida che mi indirizzi in questo processo! Avete qualche consiglio (anche qualche vecchio post che magari mi è sfuggito)?
Inoltre avevo intenzione di fare in modo che premendo sulle varie parti del corpo, venisse fuori un menu a tendina dove scegliere varie opzioni.. Secondo voi è proibitivo come lavoro (tenete conto che deve essere tutto pronto tra un mesetto)?

Offline Rino63

  • Utente normale
  • ***
  • Post: 167
  • Respect: +3
    • Mostra profilo
Re:Inserire immagine 3D e ruotarla
« Risposta #1 il: 15 Febbraio 2014, 21:20:54 CET »
0
tra un mesetto la vedo dura. io partirei cercando di capire come disegnare il file obj e come trattarlo. partirei andando sul sito di makehuman e cercherei di scaricare i sorgenti(credo siano in c) per rendermi almeno conto di che tipo di lavoro si dovrebbe fare. cmq auguri!!!!!! (ne hai bisogno!)

Offline iceweasel

  • Moderatore globale
  • Utente senior
  • *****
  • Post: 878
  • Respect: +147
    • Mostra profilo
  • Dispositivo Android:
    LGE P990 - Google Nexus 5
  • Sistema operativo:
    Linux Debian Sid
Re:Inserire immagine 3D e ruotarla
« Risposta #2 il: 15 Febbraio 2014, 21:22:36 CET »
0
Per ruotare in modo corretto un oggetto 3D devi come minimo conosce i quaternioni:

Quaternions and spatial rotation - Wikipedia, the free encyclopedia

non sono semplici, alternative più intuitive e con meno calcoli, come gli angoli di Eulero, falliscono miseramente e non sono adatti.

Il picking di oggetti 3D anche qui non è semplice, sono calcoli di algebra lineare, si basano sulle coordinate 2D della view port riportate con una serie di trasformazioni inverse e una ricerca nello spazio 3D. Un minimo di teoria:

Mouse Picking with Ray Casting - Anton's OpenGL 4 Notes
adb logcat | tee /tmp/logcat | grep TAG

Offline arlabs

  • Utente normale
  • ***
  • Post: 434
  • Respect: +49
    • Mostra profilo
  • Dispositivo Android:
    GalaxyS6, Nexus5
  • Play Store ID:
    AR Labs
  • Sistema operativo:
    Windows 10
Re:Inserire immagine 3D e ruotarla
« Risposta #3 il: 16 Febbraio 2014, 11:43:10 CET »
0
In un mesetto lo potrebbe fare qualcuno che fa quste cose tutti i giorni, da come parli tu mi sembri un po' a digiuno.

Per quanto riguarda rototraslazioni, sempre e solo matrici 4x4 e lavora sempre in coordinate omogenee.

I quaternioni sono più complicati, da usare solo in caso di animazioni di uno scheletro.

Per trovare info però mi orienterei più su forum specifici per videogiochi come indivault.

Ciao.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Inserire immagine 3D e ruotarla
« Risposta #4 il: 16 Febbraio 2014, 11:52:10 CET »
0
Io partirei quasi dalle tue stesse condizioni, non avendo mai realizzato niente con grafica 3D.

Se veramente tra un mesetto deve esserci qualcosa di pronto, molto praticamente io partirei subito con qualcosa di basso profilo: visualizzerei immagini 2D statiche del corpo umano, da varie angolazioni e implementerei zoom e picking con visualizzazione delle opzioni di cui parli; il tempo che ti rimane lo dedichi a sostituire le immagini 2D con quelle 3D ruotabili a piacimento, così male che vada hai qualcosa di provvisorio da presentare.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Re:Inserire immagine 3D e ruotarla
« Risposta #5 il: 05 Marzo 2014, 16:25:28 CET »
0
Ok allora, vi aggiorno:
Ho abbandonato l'idea del 3d, troppo complicato e per ora fuori dalla mia portata. Ho inserito due immagini in 2D del corpo (lato A e lato B), ho inserito di proposito delle immagini 800*1280 e implementato lo spanning (successivamente implementerò anche il pinch-zoom).
A questo punto ho bisogno che, ad esempio, cliccando sulla testa del mio modello l'applicazione riconosca che effettivamente quella sia la testa del mio modello. Seguendo questa guida quà

Android Images With Clickable Areas – Part 1 | More Is Not Always Better

sono arrivato al codice che riporto qua sotto che semplicemente riconosce il tocco sulla testa e manda un toast dicendo se è la testa o no.

Codice (Java): [Seleziona]
    public boolean onTouch (View v, MotionEvent ev) {
         final int action = ev.getAction();
         switch (action) {
         case MotionEvent.ACTION_UP :
                 final int X = (int) ev.getX();
                 final int Y = (int) ev.getY();
                 int result = guardamask(1, X, Y);
         if (result == 1){
                 Toast t=Toast.makeText(this,"Capoccia",Toast.LENGTH_SHORT);
             t.show();
             break;
         }
         else {
                 Toast c=Toast.makeText(this,"Non Capoccia",Toast.LENGTH_SHORT);
             c.show();
             break;
         }
         default:
                 return false;
         }
        return true;
         }
   
   
   
   
    public int guardamask (int masktype, int coordx, int coordy){
               
                switch(masktype) {
                case 1: //caso uomo frontale
                       
                        ImageView img = (ImageView)findViewById(R.id.boymask);
                        img.setDrawingCacheEnabled(true);
                        Bitmap hotspots = Bitmap.createBitmap(img.getDrawingCache());
                        img.setDrawingCacheEnabled(false);
                        int compare = hotspots.getPixel(coordx, coordy);
                        switch(compare){
                        case 0x87ceeb:
                                return 1;
                        }
                        default: return 0;
                       
                }
   
}

0x87ceeb è il colore attribuito alla testa nella maschera che ho creato per l'immagine (boymask nel codice).

Il problema è che non succede proprio un bel nulla quando clicco sulla testa.. ma nemmeno quando clicco da qualsiasi altra parte! La parte di codice che ho riportato si trova sotto la stringa che gestisce il panning.. Lo so che è un po incasinata come situazione, qualcuno sa aiutarmi?

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Inserire immagine 3D e ruotarla
« Risposta #6 il: 05 Marzo 2014, 18:13:39 CET »
0
Tralascio i commenti cosmetici e vado sul pratico di cosa farei per fare "debug".

Al tocco sullo schermo fai uscire sul toast le coordinate X,Y dell'evento. Visto che usi direttamente quelle per accedere alla bitmap, vai in un editori di immagini e segnati che valore c'è a quelle coordinate (non dare per scontato che sia dove vorresti che sia, verifica). Poi torna sull'app, all'evento tocco, con un Toast fai uscire il valore corrispondente della bitmap di mask, che nelle tue intenzioni deve essere il valore che hai detto, ma in realtà è qualcos'altro... vediamo cosa è.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Inserire immagine 3D e ruotarla
« Risposta #7 il: 05 Marzo 2014, 18:20:14 CET »
0
Codice (Java): [Seleziona]
case 0x87ceeb:
Occhio al canale alpha. Con canale alpha il colore non è 0x87ceeb bensì 0xFF87ceeb.

Poi giusto una cosa visto che questo thread mi era sfuggito. I quaternioni hanno tanti pregi ma ruotare un oggetto singolo si può fare benissimo anche senza. 
Per lo skinning invece o quaternioni o nulla. :-P

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Re:Inserire immagine 3D e ruotarla
« Risposta #8 il: 06 Marzo 2014, 17:10:23 CET »
0
Ho cambiato completamente il codice e ora è così:

Codice (Java): [Seleziona]
Resources res = getResources();
                        image = BitmapFactory.decodeResource(res,R.drawable.boymask);
                        int colormask = image.getPixel(coordx, coordy);
                        int tolerance = 50;
                        if (image == null){
                                Toast t = Toast.makeText(getContext(), "Non carica la mask", Toast.LENGTH_SHORT);
                        t.show();
                        }
                        else if (Math.abs(colormask - color.SkyBlue) < tolerance){
                                Toast t = Toast.makeText(getContext(), "Testa", Toast.LENGTH_SHORT);
                        t.show();
                        }
                        else if (Math.abs(colormask - color.Purple) < tolerance){
                                Toast t = Toast.makeText(getContext(), "Gola", Toast.LENGTH_SHORT);
                        t.show();
                        }
                       
                        else {
                                Toast t = Toast.makeText(getContext(), "niente", Toast.LENGTH_SHORT);
                        t.show();
                        }

E ora il problema che mi da è che restituisce sempre la stringa "niente" nonostante che clicco nelle zone color purple e skyblue.
Nel logcat non ci viene scritto niente, non da errori.. Secondo me ho qualche problema la stringa:
Codice (Java): [Seleziona]
image = BitmapFactory.decodeResource(res,R.drawable.boymask);
naturalmente nel codice c'è anche
Codice (Java): [Seleziona]
private static Bitmap image = null;
qualcuno sa aiutarmi?

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Inserire immagine 3D e ruotarla
« Risposta #9 il: 06 Marzo 2014, 18:37:56 CET »
0
Hai fatto la prova che ti avevo suggerito? Che è successo?

Riguardo al nuovo codice che hai postato non puoi fare semplicemente un Math.abs(mask-colore).

Questo perchè se il colore è AARRGGBB, tu potresti avere un blu definito da 0xFF0000FF. Se però il blu avesse anche una sola impercettibile puntina di verde avresti: 0xFF0001FF.
Peccato che quel 01 valga 256 quindi la tua tolerance sarebbe superata. Può funzionare solo con l'ultimo componente.

In teoria dovresti leggere rosso, verde e blu.
Dopodichè fare

Rdelta = maskred-imgred;
Gdelta = maskgreen- imggreen;
Bdelta = maskblue- imgblue;

Una volta trovate le differenze non stare a fare abs, calcola la tolleranza con:

tolerance = Math.sqrt(Rdelta*Rdelta+Gdelta*Gdelta+Bdelta*Bdelta);

Poi se ti interessa a livello teorico quello che ti ho appena descritto è semplicemente:
- hai due punti nello spazio a 3 dimensioni (il colorspace RGB)
- calcoli il vettore partendo da quei due punti.
- calcoli la lunghezza di quel vettore

Intuitivamente maggiore è la lunghezza del vettore più distanti sono i due punti.

Ricorda però che questo sistema, lavorando in RGB, è abbastanza grezzo.

Per risultati migliori dovresti cambiare colorspace da RGB a uno come HSV.

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Re:Inserire immagine 3D e ruotarla
« Risposta #10 il: 06 Marzo 2014, 19:08:18 CET »
0
Innanzi tutto grazie per le risposte, siete tutti molto gentili, spero un giorno (quando avrò fatto esperienza) di poter ricambiare.
Riguardo a quello che mi avevi suggerito, ovvero di aggiungere 0xFF.... purtroppo non è cambiato nulla.
In compenso calcolando i valori di rosso, verde e blu come mi hai consigliato qualcosina inizia a cambiare; prima quando ho fatto la prova e cliccando sulla testa è uscito fuori il toast con scritto testa..ho rischiato di piangere di gioia, poi mi sono accorto che cliccando sulle ginocchia mi dava 'testa' ugualmente :)
Continuerò con le mie prove e riprove e quando funzionerà tutto condividerò il codice in modo da avere un riferimento abbastanza importante su un image mapping che supporta panning e soprattutto un menu a tendina per ogni punto dell'immagine. ;) grazie ancora!

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Inserire immagine 3D e ruotarla
« Risposta #11 il: 07 Marzo 2014, 12:47:53 CET »
0
In compenso calcolando i valori di rosso, verde e blu come mi hai consigliato qualcosina inizia a cambiare; prima quando ho fatto la prova e cliccando sulla testa è uscito fuori il toast con scritto testa..ho rischiato di piangere di gioia, poi mi sono accorto che cliccando sulle ginocchia mi dava 'testa' ugualmente :)
Continuerò con le mie prove e riprove e quando funzionerà tutto condividerò il codice in modo da avere un riferimento abbastanza importante su un image mapping che supporta panning e soprattutto un menu a tendina per ogni punto dell'immagine. ;) grazie ancora!
Ci sono due errori:
1- dovresti provare ad usare colori più distanti. skyblue e purple sono probabilmente troppo vicini.
2- non usare gli else perché se uno va sotto alla tolleranza gli altri non li testi. paradossalmente se il primo colore è distante 49 viene selezionato quello anche se il colore successivo è quello esatto.

fai così:

Codice (Java): [Seleziona]
int distance= 10000; // valore grande di riferimento;
int selected= -1; // nessuno selezionato;

if( distanzatesta < distance ){
distance = distanzatesta;
selected = 0;
}
if( distanzagambe < distance ){
distance = distanzagambe;
selected = 1;
}
if( distanzabraccia < distance ){
distance = distanzabraccia;
selected = 2;
}

if( distance < tolleranza ){
 // in selected hai la parte del corpo più vicina!
}

Post unito: 07 Marzo 2014, 12:58:58 CET
Ora ritorno su quello che ti dicevo prima degli spazi di colore.

Il problema dello spazio di colori rgb è facilmente spiegabile. Tu hai una zona rossa e una zona verde. La zona rossa e la zona verde sono equidistanti dalla zona blu. A livello macroscopico non cambia niente (il rosso non è blu e il verde non è blu. Essendo i colori fondamentali RGB il problema non sussiste), ma quando si tratta di tonalità differenti (marrone, giallo, arancio) gli errori vengono fuori eccome.

Se tu provi a prendere un rossastro e un bluastro e provi a fare una interpolazione lineare ti accorgi che tra i due colori vengono fuori altri colori che non c'entrano un bel niente. Cioè in pratica tu non puoi scurire/schiarire a piacimento in quello spazio di colore, quindi il concetto di distanza di colore è estremamente relativo (può funzionare nel tuo caso ma per ogni altro sistema no).

La classe Color ha un metodo per convertire un colore in HSV (hue, saturation, value cioè tinta, saturazione, valore (luminosità) ). Utilizzando questo sistema dovresti essere in grado di separare meglio colori visivamente differenti (giallo, rosso, verde, blu e così via).

Color | Android Developers, int, int, float[])

In pratica convertendo il tuo colore in HSV dovresti essere in grado di calcolare meglio la distanza della TINTA semplicemente facendo quello che facevi all'inizio, cioè math.abs col valore HUE (che è un angolo da 0 a 360°).

 ;-)
« Ultima modifica: 07 Marzo 2014, 12:58:58 CET da undead, Reason: Merged DoublePost »

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Re:Inserire immagine 3D e ruotarla
« Risposta #12 il: 07 Marzo 2014, 15:23:50 CET »
0
Ma il codice che hai postato esattamente a cosa mi serve.. Non capisco bene cosa sono distanzatesta, distanzagambe e distanza braccia. Ti faccio vedere quello che ho creato utilizzando la lunghezza dei vettori
Codice (Java): [Seleziona]
image = BitmapFactory.decodeResource(getResources(),R.drawable.boymask);
int colormask = image.getPixel(coordx, coordy);
ColorTool ct = new ColorTool ();
                       
if (image == null){
         Toast t = Toast.makeText(getContext(), "Non carica la mask", Toast.LENGTH_SHORT);
          t.show();
}

if (ct.closeMatch (colormask, color.SkyBlue)){
         Toast t = Toast.makeText(getContext(), "testa", Toast.LENGTH_SHORT);
          t.show();
 }
if (ct.closeMatch (colormask, color.Purple)){
          Toast t = Toast.makeText(getContext(), "collo", Toast.LENGTH_SHORT);
           t.show();
}
                       
else {
          Toast t = Toast.makeText(getContext(), "niente", Toast.LENGTH_SHORT);
           t.show();
}
                       

Dove la classe ColorTool è:
Codice (Java): [Seleziona]
public class ColorTool {

public boolean closeMatch (int color1, int color2) {
       
        double distanzarilevata = Math.sqrt((Color.red(color1)*Color.red(color1))+(Color.green(color1)*Color.green (color1))+(Color.blue (color1)*Color.blue (color1)));
        double distanzamask = Math.sqrt((Color.red(color2)*Color.red(color2))+(Color.green(color2)*Color.green (color2))+(Color.blue (color2)*Color.blue (color2)));
       
        double lung = Math.abs(distanzarilevata-distanzamask);
        double test = 100;
       
        if( lung < test ) return true;
       
        return false;
       

ovviamente ancora non funziona  :-\

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Inserire immagine 3D e ruotarla
« Risposta #13 il: 07 Marzo 2014, 16:28:03 CET »
0
Non funziona per il motivo che ti ho detto.

Tu fai il test con la testa (scusa il gioco di parole) ma se la distanza è minore della tolleranza il tuo codice ti dice che è la testa. A prescindere dal fatto che sia più vicino al colore del collo rispetto a quello della testa).

Modifica il codice in modo da riportare lung invece di un boolean.

Dopodichè fai:

Codice (Java): [Seleziona]
int distance= 10000; // valore grande di riferimento;
int selected= -1; // nessuno selezionato;
distanzacorrente = ct.closeMatch (colormask, color.SkyBlue);
if( distanzacorrente < distance ){
distance = distanzacorrente;
selected = 0;
}
distanzacorrente = ct.closeMatch (colormask, color.Purple);
if( distanzacorrente < distance ){
distance = distanzacorrente;
selected = 1;
}

Offline Marco Malinverno

  • Nuovo arrivato
  • *
  • Post: 10
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Alcatel One Touch
  • Sistema operativo:
    Windows7
Re:Inserire immagine 3D e ruotarla
« Risposta #14 il: 07 Marzo 2014, 17:37:11 CET »
0
Ecco il codice modificato come mi hai consigliato:
Codice (Java): [Seleziona]
image = BitmapFactory.decodeResource(getResources(),R.drawable.boymask);
                        int colormask = image.getPixel(coordx, coordy);
                        ColorTool ct = new ColorTool ();

                        double distance= 10000; // valore grande di riferimento;
                                               
                        double distanzacorrente = ct.closeMatch (colormask, color.SkyBlue);
                        if( distanzacorrente < distance ){
                        distance = distanzacorrente;
                        Toast t=Toast.makeText(getContext(),"testa",Toast.LENGTH_SHORT);
                    t.show();
                        }
                       
                        distanzacorrente = ct.closeMatch (colormask, color.Purple);
                        if( distanzacorrente < distance ){
                        distance = distanzacorrente;
                        Toast t=Toast.makeText(getContext(),"collo",Toast.LENGTH_SHORT);
                    t.show();
                        }

con la nuova classe ColorTool:

Codice (Java): [Seleziona]
public class ColorTool {

public double closeMatch (int color1, int color2) {
       
        double distanzarilevata = Math.sqrt((Color.red(color1)*Color.red(color1))+(Color.green(color1)*Color.green (color1))+(Color.blue (color1)*Color.blue (color1)));
        double distanzamask = Math.sqrt((Color.red(color2)*Color.red(color2))+(Color.green(color2)*Color.green (color2))+(Color.blue (color2)*Color.blue (color2)));
       
        double lung = Math.abs(distanzarilevata-distanzamask);
       
        return lung;
       

} // end match

} // end class


Ora, essendo la lunghezza distance troppo grande, entrambi gli 'if' risultano soddisfatti e escono cosi 2 toast. Decrementando il valore di distance a livelli accettabili nessuno dei due toast appare. Ti allego anche un immagine della mask che utilizzo x il confronto:


Sto seriamente pensando di abbandonare questa strada e provare a mappare l'immagine con le coordinate..