2012-01-14 17 views
10

Ive ha fatto una domanda simile prima e non è riuscita a trovare un numero diretto answer.Utilizzo di OpenGL in Matlab per ottenere il buffer di profondità

Qualcuno potrebbe fornire un codice di esempio per estrarre il buffer di profondità del rendering di un oggetto in una figura in Matlab?

Quindi diciamo che carico un file obj o anche solo una semplice chiamata surf, lo renderò e ora voglio arrivare al suo buffer di profondità quindi quale codice lo farà per me usando sia Matlab che OpenGL. Cioè come posso configurarlo e quindi accedere ai dati reali?

In sostanza, voglio essere in grado di utilizzare le potenti funzioni di plottaggio di Matlabs e quindi essere in grado di accedere al contesto grafico sottostante per ottenere il buffer di profondità.

NOTA: La taglia specifica JOGL ma non è obbligatorio. Qualsiasi codice che agisce come sopra e in grado di fornire me con il buffer di profondità dopo l'esecuzione in Matlab è sufficiente)

+1

si può sempre provare a offrire una taglia per aumentare l'attenzione che riceve una domanda. – PeterT

+0

Intendo, ma ho scoperto solo quando ho postato la domanda che ho bisogno di aspettare due giorni fino a quando questa domanda attuale diventa ammissibile. – twerdster

+0

Accettate le risposte che riguardano solo Matlab? Non ho idea di JOGL. –

risposta

13

depthmap thing

Oggi, sono andato a bere con i miei colleghi, e dopo cinque birre e alcuni tequillas ho trovato questo domanda e pensiero, "ho a voi!" Così ho sofferto per un po 'ma poi ho trovato una soluzione semplice usando MEX. Ho teorizzato che il contesto OpenGL, creato dall'ultima finestra, potrebbe essere lasciato attivo e quindi potrebbe essere accessibile da "C", se lo script è eseguito nello stesso thread.

Ho creato un semplice programma "C" che chiama una funzione MATLAB, chiamata "testofmyfilter", che traccia la risposta in frequenza di un filtro (che era l'unico script che avevo a portata di mano). Questo è reso utilizzando OpenGL. Quindi il programma utilizza glGetViewport() e glReadPixels() per ottenere i buffer OpenGL. Quindi crea una matrice, la riempie con i valori di profondità e la passa alla seconda funzione, chiamata "trytodisplaydepthmap". Mostra solo la mappa di profondità usando la funzione imshow. Si noti che la funzione MEX può anche restituire valori, quindi forse la postelaborazione non dovrebbe essere un'altra funzione, ma non sono in grado di capire come è fatta. Dovrebbe essere banale, però. Oggi sto lavorando con MEX per la prima volta.

Senza ulteriore ritardo, ci sono codici sorgenti I usati:

testofmyfilter.m

imp = zeros(10000,1); 
imp(5000) = 1; 
% impulse 

[bwb,bwa] = butter(3, 0.1, 'high'); 
b = filter(bwb, bwa, imp); 
% filter impulse by the filter 

fs = 44100; % sampling frequency (all frequencies are relative to fs) 
frequency_response=fft(b); % calculate response (complex numbers) 
amplitude_response=20*log10(abs(frequency_response)); % calculate module of the response, convert to dB 
frequency_axis=(0:length(b)-1)*fs/length(b); % generate frequency values for each response value 
min_f=2; 
max_f=fix(length(b)/2)+1; % min, max frequency 

figure(1); 
lighting gouraud 
set(gcf,'Renderer','OpenGL') 

semilogx(frequency_axis(min_f:max_f),amplitude_response(min_f:max_f),'r-') % plot with logarithmic axis using red line 
axis([frequency_axis(min_f) frequency_axis(max_f) -90 10]) % set axis limits 

xlabel('frequency [Hz]'); 
ylabel('amplitude [dB]'); % legend 

grid on % draw grid 

test.c

//You can include any C libraries that you normally use 
#include "windows.h" 
#include "stdio.h" 
#include "math.h" 
#include "mex.h" //--This one is required 

extern WINAPI void glGetIntegerv(int n_enum, int *p_value); 

extern WINAPI void glReadPixels(int  x, 
    int  y, 
    int  width, 
    int  height, 
    int  format, 
    int  type, 
    void *  data); 

#define GL_VIEWPORT      0x0BA2 
#define GL_DEPTH_COMPONENT    0x1902 
#define GL_FLOAT       0x1406 

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
    int viewport[4], i, x, y; 
    int colLen; 
    float *data; 
    double *matrix; 
    mxArray *arg[1]; 

    mexCallMATLAB(0, NULL, 0, NULL, "testofmyfilter"); 
    // call an .m file which creates OpenGL window and draws a plot inside 

    glGetIntegerv(GL_VIEWPORT, viewport); 
    printf("GL_VIEWPORT = [%d, %d, %d, %d]\n", viewport[0], viewport[1], viewport[2], viewport[3]); 
    // print viewport dimensions, should be [0, 0, m, n] 
    // where m and n are size of the GL window 

    data = (float*)malloc(viewport[2] * viewport[3] * sizeof(float)); 
    glReadPixels(0, 0, viewport[2], viewport[3], GL_DEPTH_COMPONENT, GL_FLOAT, data); 
    // alloc data and read the depth buffer 

    /*for(i = 0; i < 10; ++ i) 
     printf("%f\n", data[i]);*/ 
    // debug 

    arg[0] = mxCreateNumericMatrix(viewport[3], viewport[2], mxDOUBLE_CLASS, mxREAL); 
    matrix = mxGetPr(arg[0]); 
    colLen = mxGetM(arg[0]); 
    printf("0x%08x 0x%08x 0x%08x %d\n", data, arg[0], matrix, colLen); // debug 
    for(x = 0; x < viewport[2]; ++ x) { 
     for(y = 0; y < viewport[3]; ++ y) 
      matrix[x * colLen + y] = data[x + (viewport[3] - 1 - y) * viewport[2]]; 
    } 
    // create matrix, copy data (this is stupid, but matlab switches 
    // rows/cols, also convert float to double - but OpenGL could have done that) 

    free(data); 
    // don't need this anymore 

    mexCallMATLAB(0, NULL, 1, arg, "trytodisplaydepthmap"); 
    // pass the array to a function (returnig something from here 
    // is beyond my understanding of mex, but should be doable) 

    mxDestroyArray(arg[0]); 
    // cleanup 

    return; 
} 

trytodisplaydepthmap.m:

function [] = trytodisplaydepthmap(depthMap) 

figure(2); 
imshow(depthMap, []); 
% see what's inside 

Salva tutto di th ese nella stessa directory, compilare test.c con (tipo quella di console Matlab):

mex test.c Q:\MATLAB\R2008a\sys\lcc\lib\opengl32.lib 

Dove "D: \ MATLAB \ R2008a \ sys \ LCC \ lib \ opengl32.lib" è percorso a "opengl32 .lib "file.

Infine, eseguire tutto semplicemente digitando "test" nella console matlab. Dovrebbe far apparire una finestra con la risposta in frequenza del filtro e un'altra finestra con il buffer di profondità. Si noti che i buffer fronte e retro sono scambiati nel momento in cui il codice "C" legge il buffer di profondità, quindi potrebbe essere necessario eseguire lo script due volte per ottenere qualsiasi risultato (quindi il buffer frontale che ora contiene nuovamente i risultati con back buffer, e la profondità può essere letta).Questo potrebbe essere fatto automaticamente da "C", oppure puoi provare includendo getframe (gcf); alla fine del tuo script (che si legge anche da OpenGL, quindi scambia i buffer per te, o qualcosa del genere).

Questo funziona per me in Matlab 7.6.0.324 (R2008a). Lo script esegue e sputa quanto segue:

>>test 
GL_VIEWPORT = [0, 0, 560, 419] 
0x11150020 0x0bd39620 0x12b20030 419 

E ovviamente visualizza le immagini. Notare che la gamma del buffer di profondità dipende da Matlab e può essere piuttosto elevata, quindi non è facile dare un senso alle immagini generate.

+0

oh, ho perso i requisiti. ovviamente funziona anche con surf(). Ho appena provato il codice su: http://www.mathworks.com/help/techdoc/ref/surf.html e ho ottenuto: http://www.luki.webzdarma.cz/up/depthmap.png l'ovvio –

+3

Ti meriti una medaglia, un'altra birra e i 300 rappresentanti. – twerdster

+1

Posso raccomandare di mettere tutto insieme e renderlo una bella presentazione di matematica? Non sono l'unico a trovarlo utile. – twerdster

2

la risposta suina è quella corretta. Ecco una versione leggermente più semplice e formattata che è multipiattaforma.

Creare un file chiamato mexGetDepth.c

#include "mex.h" 

#define GL_VIEWPORT      0x0BA2 
#define GL_DEPTH_COMPONENT    0x1902 
#define GL_FLOAT       0x1406 

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
    int viewport[4], i, x, y; 
    int colLen; 
    float *data; 
    double *matrix; 

    glGetIntegerv(GL_VIEWPORT, viewport); 
    data = (float*)malloc(viewport[2] * viewport[3] * sizeof(float)); 
    glReadPixels(0, 0, viewport[2], viewport[3], GL_DEPTH_COMPONENT, GL_FLOAT, data); 

    plhs[0] = mxCreateNumericMatrix(viewport[3], viewport[2], mxDOUBLE_CLASS, mxREAL); 
    matrix = mxGetPr(plhs[0]); 
    colLen = mxGetM(plhs[0]); 

    for(x = 0; x < viewport[2]; ++ x) { 
     for(y = 0; y < viewport[3]; ++ y) 
      matrix[x * colLen + y] = data[x + (viewport[3] - 1 - y) * viewport[2]]; 
    } 

    free(data); 
    return; 
} 

Quindi se siete su Windows compilazione usando

mex mexGetDepth.c "path to OpenGL32.lib" 

o se sei su un sistema nix

mex mexGetDepth.c "path to opengl32.a" 

quindi eseguire il seguente piccolo script per testare la nuova funzione

peaks; 
figure(1); 
depthData=mexGetDepth; 
figure 
imshow(depthData); 
+0

abbiamo bisogno di dichiarare glGetIntegerv e glReadPixels fucntions da qualche parte? Nel codice originale, è fatto usando il vuoto WINAPI extern ..., ma non sono sicuro di come lo faremo in linux –