Ответ 1
Сегодня я попил с моими коллегами, а после пяти сортов пива и некоторых текилл я нашел этот вопрос и подумал: "У тебя есть!" Таким образом, я боролся некоторое время, но затем я нашел простое решение с использованием 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 и может быть довольно высоким, поэтому любое ощущение сгенерированных изображений может быть несложным.