我以前问了一个类似的问题,并没有找到直接的answer。
有人可以提供示例代码,用于将对象渲染的深度缓冲区提取到Matlab中的图形中吗?
所以我想说我加载了一个obj文件,甚至只是一个简单的冲浪调用,渲染它,现在想要到达它的深度缓冲区,然后使用Matlab和OpenGL为我做什么代码。即如何设置然后访问实际数据?
我本质上希望能够使用Matlabs强大的绘图功能,然后能够访问底层图形上下文以获取深度缓冲区。
注意:赏金指定JOGL,但这不是必须的。任何代码如上所述,并且在Matlab中运行后可以为我提供深度缓冲区就足够了)
答案 0 :(得分: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
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
将所有这些保存到同一目录,使用(输入Matlab控制台)编译test.c:
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,并且可能非常高,因此对生成的图像有任何意义可能并不简单。
答案 1 :(得分: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);