Était-ce utile?

La solution

depthmap thing

Aujourd'hui, je suis allé boire avec mes collègues, et après cinq bières et quelques tequillas, j'ai trouvé cette question et je me suis dit "à vous!" J'ai donc eu du mal pendant un moment, mais j'ai trouvé une solution simple en utilisant MEX. J'ai émis l'hypothèse que le contexte OpenGL, créé par la dernière fenêtre, pouvait rester actif et donc être accessible à partir de "C", si le script s'exécutait dans le même fil.

J'ai créé un simple programme "C" qui appelle une fonction matlab, appelée "testofmyfilter" qui trace la réponse en fréquence d'un filtre (c'était le seul script que j'avais sous la main). Ceci est rendu en utilisant OpenGL. Ensuite, le programme utilise glGetViewport () et glReadPixels () pour accéder aux tampons OpenGL. Ensuite, il crée une matrice, la remplit avec les valeurs de profondeur et la transmet à la deuxième fonction, appelée "trytodisplaydepthmap". Il affiche simplement la carte de profondeur en utilisant la fonction imshow. Notez que la fonction MEX est également autorisée à renvoyer des valeurs, donc peut-être que le post-traitement ne devrait pas être une autre fonction, mais je ne suis pas en état de comprendre comment cela se fait. Cela devrait être trivial, cependant. Je travaille avec MEX pour la première fois aujourd'hui.

Sans plus attendre, j'ai utilisé des codes sources:

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

Enregistrez tout cela dans le même répertoire, compilez test.c avec (tapez-le sur la console Matlab):

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

Où "Q: \ MATLAB \ R2008a \ sys \ lcc \ lib \ opengl32.lib" est le chemin du fichier "opengl32.lib".

Et enfin, exécutez tout cela en tapant simplement "test" dans la console matlab. Il devrait faire apparaître une fenêtre avec la réponse en fréquence du filtre et une autre fenêtre avec le tampon de profondeur. Notez que les tampons avant et arrière sont échangés au moment où le code "C" lit le tampon de profondeur, il peut donc être nécessaire d'exécuter le script deux fois pour obtenir des résultats (donc le tampon avant qui contient maintenant les résultats échange à nouveau avec le tampon arrière, et la profondeur peut être lue). Cela pourrait être fait automatiquement par "C", ou vous pouvez essayer d'inclure getframe (gcf); à la fin de votre script (qui lit également OpenGL pour qu'il échange les tampons pour vous, ou quelque chose du genre).

Cela fonctionne pour moi dans Matlab 7.6.0.324 (R2008a). Le script s'exécute et crache ce qui suit:

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

Et bien sûr, il affiche les images. Notez que la plage de tampon de profondeur dépend de Matlab et peut être assez élevée, donc donner un sens aux images générées peut ne pas être simple.

Autres conseils

La réponse de

le porc est la bonne. Voici une version légèrement formatée et plus simple qui est multiplateforme.

Créez un fichier appelé 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;
}

Ensuite, si vous êtes sur Windows, compilez en utilisant

mex mexGetDepth.c "path to OpenGL32.lib"

ou si vous êtes sur un système nix

mex mexGetDepth.c "path to opengl32.a"

Ensuite, exécutez le petit script suivant pour tester la nouvelle fonction

peaks;
figure(1);
depthData=mexGetDepth;
figure
imshow(depthData);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top