matlab opengl 3d jogl zbuffer

Usando OpenGL en Matlab para obtener un buffer de profundidad



3d jogl (2)

He hecho una pregunta similar antes y no he logrado encontrar una respuesta directa.

¿Podría alguien proporcionar un código de muestra para extraer el búfer de profundidad de la representación de un objeto en una figura en Matlab?

Así que digamos que cargué un archivo obj o incluso una simple llamada de surf, lo rendericé y ahora quiero llegar a su búfer de profundidad, y luego qué código hará eso para mí usando tanto Matlab como OpenGL. Es decir, ¿cómo configuro esto y luego accedo a los datos reales?

Básicamente, quiero poder usar las potentes funciones de gráficos de Matlabs y luego poder acceder al contexto de gráficos subyacente para sacar el búfer de profundidad.

NOTA: El bounty especifica JOGL pero eso no es obligatorio. Cualquier código que actúe como el anterior y pueda proporcionarme el búfer de profundidad después de ejecutarlo en Matlab es suficiente)


Hoy, fui a beber con mis colegas, y después de cinco cervezas y algunas tequillas encontré esta pregunta y pensé "¡ya te tengo!" Así que estuve luchando por un tiempo, pero luego encontré una solución simple usando MEX. Teoricé que el contexto de OpenGL, creado por la última ventana, podría permanecer activo y, por lo tanto, podría accederse desde "C", si el script se ejecutó en el mismo hilo.

Creé un sencillo programa "C" que llama a una función de matlab, llamada "testofmyfilter", que traza la respuesta de frecuencia de un filtro (que era el único script que tenía a mano). Esto se representa usando OpenGL. Luego, el programa usa glGetViewport () y glReadPixels () para acceder a los búferes de OpenGL. Luego crea una matriz, la rellena con los valores de profundidad y la pasa a la segunda función, llamada "trytodisplaydepthmap". Simplemente muestra el mapa de profundidad con la función imshow. Tenga en cuenta que la función MEX también puede devolver valores, por lo que tal vez el postprocesamiento no tenga que ser otra función, pero no estoy en condiciones de poder entender cómo se hace. Sin embargo, debería ser trivial. Estoy trabajando con MEX por primera vez hoy.

Sin más demora, hay códigos fuente que utilicé:

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

Guarde todos estos en el mismo directorio, compile test.c con (escriba eso a la consola de Matlab):

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

Donde "Q: / MATLAB / R2008a / sys / lcc / lib / opengl32.lib" es la ruta al archivo "opengl32.lib".

Y finalmente ejecútelo simplemente escribiendo "test" en la consola de matlab. Debería mostrar una ventana con respuesta de frecuencia de filtro y otra ventana con el búfer de profundidad. Tenga en cuenta que los búferes anterior y posterior se intercambian en el momento en que el código "C" lee el búfer de profundidad, por lo que puede ser necesario ejecutar el script dos veces para obtener resultados (por lo que el búfer frontal que ahora contiene los intercambios se intercambia con búfer de nuevo, y la profundidad se puede leer). Esto se puede hacer automáticamente con "C", o puede intentar incluir getframe (gcf); al final de su script (que también se lee desde OpenGL para que intercambie los buffers por usted, o algo así).

Esto funciona para mí en Matlab 7.6.0.324 (R2008a). La secuencia de comandos se ejecuta y escupe lo siguiente:

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

Y, por supuesto, muestra las imágenes. Tenga en cuenta que el rango del búfer de profundidad depende de Matlab, y puede ser bastante alto, por lo que tener sentido de las imágenes generadas puede no ser sencillo.


la respuesta de los cerdos es la correcta. Aquí hay una versión ligeramente formateada y más simple que es multiplataforma.

Crea un archivo llamado 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; }

Entonces, si estás en Windows compila usando

mex mexGetDepth.c "path to OpenGL32.lib"

o si estás en un sistema nix

mex mexGetDepth.c "path to opengl32.a"

Luego ejecute el siguiente script pequeño para probar la nueva función

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