10

我以前问过类似的问题,但没有找到直接的答案

有人可以提供示例代码,用于将对象渲染的深度缓冲区提取到 Matlab 中的图形中吗?

所以假设我加载了一个 obj 文件,甚至只是一个简单的 surf 调用,渲染它,现在想要到达它的深度缓冲区,那么使用 Matlab 和 OpenGL 的代码将为我做这件事。即我如何设置它然后访问实际数据?

我本质上希望能够使用 Matlabs 强大的绘图功能,然后能够访问底层图形上下文以获取深度缓冲区。

注意:赏金指定 JOGL,但这不是必须的。在 Matlab 中运行后可以为我提供深度缓冲区的任何代码就足够了)

4

2 回答 2

14

深度图的东西

今天和同事一起去喝酒,喝了五杯啤酒,喝了几杯龙舌兰酒后,我发现了这个问题,心想:“你好!” 所以我挣扎了一段时间,但后来我找到了一个使用 MEX 的简单解决方案。我推测,如果脚本在同一个线程中运行,则由最后一个窗口创建的 OpenGL 上下文可以保持活动状态,因此可以从“C”访问。

我创建了一个简单的“C”程序,它调用了一个名为“testofmyfilter”的matlab函数,它绘制了滤波器的频率响应(这是我手头唯一的脚本)。这是使用 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

测试.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;
}

尝试显示深度图.m:

function [] = trytodisplaydepthmap(depthMap)

figure(2);
imshow(depthMap, []);
% see what's 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”文件的路径。

最后只需在 matlab 控制台中键入“test”即可执行所有操作。它应该打开一个带有滤波器频率响应的窗口,以及另一个带有深度缓冲区的窗口。请注意,在“C”代码读取深度缓冲区时交换了前后缓冲区,因此可能需要运行脚本两次才能获得任何结果(因此现在包含结果的前缓冲区再次与后缓冲区交换,并且可以读出深度)。这可以通过“C”自动完成,或者您可以尝试包含 getframe(gcf); 在脚本的末尾(也从 OpenGL 读取,因此它会为您交换缓冲区或其他内容)。

这在 Matlab 7.6.0.324 (R2008a) 中对我有用。该脚本运行并吐出以下内容:

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

当然,它会显示图像。请注意,深度缓冲区范围取决于 Matlab,并且可能非常高,因此对生成的图像进行任何理解可能并不简单。

于 2012-01-18T18:27:36.723 回答
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;
}

然后,如果你在 Windows 上编译使用

mex mexGetDepth.c "path to OpenGL32.lib"

或者如果你使用的是 nix 系统

mex mexGetDepth.c "path to opengl32.a"

然后运行以下小脚本来测试新功能

peaks;
figure(1);
depthData=mexGetDepth;
figure
imshow(depthData);
于 2012-01-19T01:05:03.547 回答