2012-01-14 131 views
10

我之前問過類似的問題,沒有設法找到直接的answer在Matlab中使用OpenGL獲取深度緩衝區

可能有人用於提取對象的渲染的深度緩衝器中在Matlab的圖提供示例代碼?

因此,可以說我加載OBJ文件,甚至只是一個簡單的衝浪呼叫,使其現在想要得到它的深度緩衝然後什麼樣的代碼將同時使用Matlab和OpenGL的爲我做的。即我該如何設置,然後訪問實際數據?

我基本上希望能夠使用Matlabs強大的繪圖功能,然後才能夠訪問底層圖形上下文用於獲取深度緩衝的。

注:賞金指定JOGL,但不是必須的。它充當上方,在Matlab運行它後能爲我提供深度緩衝的任何代碼就足夠了)

+1

你總是可以試着提供賞金來增加對問題的關注。 – PeterT 2012-01-14 13:48:59

+0

我打算,但只有當我發佈的問題,我只需要等待兩天,直到這個當前問題成爲合格。 – twerdster 2012-01-14 15:49:52

+0

你接受只涉及Matlab的答案嗎?我不知道JOGL。 – 2012-01-16 16:09:18

回答

13

depthmap thing

今天,我和我的同事們喝酒,經過五年的啤酒和一些tequillas我發現這問題和想法,「有在!」所以我掙扎了一會兒,但後來我發現了一個使用MEX的簡單解決方案。我推斷,由最後一個窗口創建的OpenGL上下文可以保持活動狀態,因此如果腳本運行在同一個線程中,則可以從「C」訪問。

我創建了一個簡單的「C」程序它調用一個matlab函數,稱爲「testofmyfilter」圖表的過濾器(這是我在手的唯一腳本)的頻率響應。這是使用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 

保存所有的ESE到同一目錄,編譯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控制檯鍵入「測試」執行的這一切。它應該調出一個帶有濾波器頻率響應的窗口,以及另一個帶有深度緩衝區的窗口。請注意,在「C」代碼讀取深度緩衝區時,正面和背面緩衝區會被交換,因此可能需要兩次運行該腳本才能獲得任何結果(因此現在包含結果的前端緩衝區會再次與後端緩衝區交換,並且深度可以被讀出)。這可以通過「C」自動完成,或者你可以嘗試包括getframe(gcf);在腳本的結尾(也可以從OpenGL讀回,因此它會替換掉你的緩衝區,或者其他的東西)。

這適用於Matlab 7.6.0.324(R2008a)。腳本運行並吐出以下內容:

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

當然它顯示圖像。請注意,深度緩衝區範圍取決於Matlab,並且可能相當高,因此,對生成的圖像的任何意義可能都不太直觀。

+0

哦,我錯過了要求。當然這也適用於surf()。只是嘗試了代碼:http://www.mathworks.com/help/techdoc/ref/surf.html並得到:http://www.luki.webzdarma.cz/up/depthmap.png明顯的 – 2012-01-18 18:33:25

+3

你應得的一枚獎牌,另一支啤酒和300名代表。 – twerdster 2012-01-18 22:00:38

+1

我可以推薦你把所有這些放在一起,並把它變成一個不錯的mathworks提交?我不是唯一認爲有用的人。 – twerdster 2012-01-18 22:01:36

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" 

,或者如果你是一個尼克斯系統

mex mexGetDepth.c "path to opengl32.a" 

然後運行下面的上小腳本測試出新功能

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

我們是否需要在某處聲明glGetIntegerv和glReadPixels函數?在原始代碼中,它使用extern WINAPI void ...完成,但我不確定我們如何在Linux中執行此操作 – 2014-02-03 16:38:13