Использование OpenGL в Matlab для получения буфера глубины

Ive задал аналогичный вопрос раньше и не смог найти прямой ответ .

Может ли кто-нибудь предоставить пример кода для извлечения буфера глубины рендеринга объекта в фигуру в Matlab?

Итак, скажем, я загружаю файл obj или даже просто обычный вызов серфинга, визуализирую его и теперь хочу получить его буфер глубины, а какой код сделает это для меня, используя как Matlab, так и OpenGL. То есть как мне установить это, а затем получить доступ к фактическим данным?

Я по сути хочу иметь возможность использовать мощные функции построения Matlabs, а затем иметь доступ к основному графическому контексту для вывода буфера глубины.

ПРИМЕЧАНИЕ. Баунти указывает JOGL, но это не обязательно. Любой код, который действует как указано выше и может предоставить мне буфер глубины после его запуска в Matlab, достаточен)

Ответ 1

depthmap thing

Сегодня я попил с моими коллегами, а после пяти сортов пива и некоторых текилл я нашел этот вопрос и подумал: "У тебя есть!" Таким образом, я боролся некоторое время, но затем я нашел простое решение с использованием MEX. Я предположил, что контекст OpenGL, созданный последним окном, может быть оставлен активным и поэтому может быть доступен из "C" , если script работает в одном потоке.

Я создал простую программу "C" , которая вызывает одну функцию matlab, называемую "testofmyfilter", которая отображает частотную характеристику фильтра (это был единственный script, который я имел под рукой). Это отображается с помощью OpenGL. Затем программа использует glGetViewport() и glReadPixels() для доступа к буферам OpenGL. Затем он создает матрицу, заполняет ее значениями глубины и передает ее во вторую функцию, называемую "trytodisplaydepthmap". Он просто отображает карту глубины, используя функцию imshow. Обратите внимание, что функции MEX также могут возвращать значения, поэтому, возможно, постпроцессинг не должен быть другой функцией, но я не в состоянии понять, как это делается. Однако должно быть тривиально. Я работаю с MEX в первый раз сегодня.

Без дополнительной задержки используются исходные коды:

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 inside

Сохраните все эти файлы в одном каталоге, скомпилируйте test.c(введите его в консоль Matlab):

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

Где "Q:\MATLAB\R2008a\sys\lcc\lib\opengl32.lib" - это путь к файлу "opengl32.lib".

И, наконец, выполните все это, просто набрав "test" в консоли matlab. Он должен вызывать окно с фильтрующим частотным откликом и другое окно с буфером глубины. Обратите внимание, что передний и задний буферы заменяются в тот момент, когда код "С" считывает буфер глубины, поэтому может потребоваться дважды запустить script, чтобы получить какие-либо результаты (поэтому передний буфер, который теперь содержит свопы результатов с обратным буфером снова, и глубина может быть считана). Это можно сделать автоматически с помощью "C" , или вы можете попробовать включить getframe (gcf); в конце вашего script (который также читается из OpenGL, поэтому он меняет ваши буферы или что-то в этом роде).

Это работает для меня в Matlab 7.6.0.324 (R2008a). script запускает и выдает следующее:

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

И, конечно, он отображает изображения. Обратите внимание, что диапазон буфера глубины зависит от Matlab и может быть довольно высоким, поэтому любое ощущение сгенерированных изображений может быть несложным.

Ответ 2

ответ свиньи правильный. Вот немного отформатированная и более простая версия, которая кросс-платформенная.

Создайте файл 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;
}

Затем, если youre на windows компилируется с помощью

mex mexGetDepth.c "path to OpenGL32.lib"

или если вы используете систему nix

mex mexGetDepth.c "path to opengl32.a"

Затем запустите следующую небольшую script, чтобы проверить новую функцию

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