今天,我和同事们一起喝酒,喝了五杯啤酒和一些龙舌兰后,我发现了这个问题,并想着“来试试吧!”我挣扎了一段时间,但后来我使用了MEX找到了一个简单的解决方案。我假设由最后一个窗口创建的OpenGL上下文可能仍然处于活动状态,因此如果脚本在同一线程中运行,则可以从“C”中访问。
我创建了一个简单的“C”程序,调用一个名为“testofmyfilter”的matlab函数,该函数绘制滤波器的频率响应(这是我手头唯一的脚本)。这是使用OpenGL渲染的。然后程序使用glGetViewport()和glReadPixels()来获取OpenGL缓冲区。然后它创建一个矩阵,填充深度值,并将其传递给第二个函数,称为“trytodisplaydepthmap”。它只是使用imshow函数显示深度图。请注意,MEX函数也可以返回值,因此后处理可能不需要另一个函数,但我现在无法理解如何完成。不过应该很简单。今天是我第一次使用MEX。
没有更多的延迟,这是我使用的源代码:
testofmyfilter.m
imp = zeros(10000,1);
imp(5000) = 1;
[bwb,bwa] = butter(3, 0.1, 'high');
b = filter(bwb, bwa, imp);
fs = 44100;
frequency_response=fft(b);
amplitude_response=20*log10(abs(frequency_response));
frequency_axis=(0:length(b)-1)*fs/length(b);
min_f=2;
max_f=fix(length(b)/2)+1;
figure(1);
lighting gouraud
set(gcf,'Renderer','OpenGL')
semilogx(frequency_axis(min_f:max_f),amplitude_response(min_f:max_f),'r-')
axis([frequency_axis(min_f) frequency_axis(max_f) -90 10])
xlabel('frequency [Hz]');
ylabel('amplitude [dB]');
grid on
test.c
#include "windows.h"
#include "stdio.h"
#include "math.h"
#include "mex.h"
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");
glGetIntegerv(GL_VIEWPORT, viewport);
printf("GL_VIEWPORT = [%d, %d, %d, %d]\n", viewport[0], viewport[1], viewport[2], viewport[3]);
data = (float*)malloc(viewport[2] * viewport[3] * sizeof(float));
glReadPixels(0, 0, viewport[2], viewport[3], GL_DEPTH_COMPONENT, GL_FLOAT, data);
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);
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);
mexCallMATLAB(0, NULL, 1, arg, "trytodisplaydepthmap");
mxDestroyArray(arg[0]);
return;
}
trytodisplaydepthmap.m:
function [] = trytodisplaydepthmap(depthMap)
figure(2);
imshow(depthMap, []);
请将所有这些内容保存到同一个目录中,使用以下命令在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,并且可能非常高,因此理解生成的图像可能并不直观。