2012-01-14 12 views
10

Ive đã hỏi một câu hỏi tương tự trước đây và không quản lý để tìm trực tiếp answer.Sử dụng OpenGL trong Matlab để lấy bộ đệm sâu

Ai đó có thể cung cấp mã mẫu để trích xuất bộ đệm độ sâu của kết xuất đối tượng thành một hình trong Matlab? Vì vậy, cho phép nói rằng tôi tải một tập tin obj hoặc thậm chí chỉ là một cuộc gọi lướt đơn giản, làm cho nó và bây giờ muốn để có được bộ đệm sâu của nó sau đó mã sẽ làm điều đó cho tôi bằng cách sử dụng cả Matlab và OpenGL. I E. làm cách nào để thiết lập và sau đó truy cập dữ liệu thực tế?

Tôi về cơ bản muốn có thể sử dụng các chức năng âm mưu mạnh mẽ của Matlabs và sau đó có thể truy cập bối cảnh đồ họa cơ bản để nhận được bộ đệm độ sâu.

LƯU Ý: Tiền thưởng chỉ định JOGL nhưng điều đó không phải là điều bắt buộc. Bất kỳ mã đóng vai trò như trên và có thể cung cấp cho tôi với depth buffer sau khi chạy nó trong Matlab là đủ)

+1

bạn luôn có thể thử cung cấp tiền thưởng để tăng sự chú ý mà một câu hỏi nhận được. – PeterT

+0

Tôi dự định nhưng chỉ phát hiện ra khi tôi đăng câu hỏi mà tôi cần phải đợi hai ngày cho đến khi câu hỏi hiện tại này đủ điều kiện. – twerdster

+0

Bạn có chấp nhận câu trả lời liên quan đến Matlab không? Tôi không biết gì về JOGL. –

Trả lời

13

depthmap thing

Hôm nay, tôi đã đi uống rượu với đồng nghiệp của tôi, và sau năm bia và một số tequillas Tôi thấy điều này câu hỏi và suy nghĩ, "có lúc ya!" Vì vậy, tôi đã đấu tranh một thời gian nhưng sau đó tôi tìm thấy một giải pháp đơn giản bằng cách sử dụng MEX. Tôi giả định rằng bối cảnh OpenGL, được tạo ra bởi cửa sổ cuối cùng, có thể được để lại hoạt động và do đó có thể truy cập từ "C", nếu kịch bản chạy trong cùng một luồng.

Tôi đã tạo một chương trình "C" đơn giản gọi một hàm matlab, được gọi là "testofmyfilter" biểu thị phản hồi tần số của bộ lọc (đó là tập lệnh duy nhất tôi có trong tay). Điều này được hiển thị bằng cách sử dụng OpenGL. Sau đó, chương trình sử dụng glGetViewport() và glReadPixels() để truy cập vào bộ đệm OpenGL. Sau đó, nó tạo ra một ma trận, điền nó với các giá trị độ sâu, và chuyển nó đến hàm thứ hai, được gọi là "trytodisplaydepthmap". Nó chỉ hiển thị độ sâu bằng cách sử dụng hàm imshow. Lưu ý rằng hàm MEX cũng được phép trả về các giá trị, vì vậy có lẽ quá trình hậu xử lý sẽ không phải là một hàm khác, nhưng tôi không có trạng thái nào để có thể hiểu được nó được thực hiện như thế nào. Nên là tầm thường, mặc dù. Tôi đang làm việc với MEX lần đầu tiên ngày hôm nay.

Không chậm trễ hơn nữa, có những mã nguồn tôi đã sử dụng:

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 

Lưu tất cả ese vào cùng thư mục, biên dịch test.c với (gõ đó để Matlab console):

mex test.c Q:\MATLAB\R2008a\sys\lcc\lib\opengl32.lib 

đâu "Q: \ MATLAB \ R2008a \ sys \ lcc \ lib \ opengl32.lib" là đường dẫn đến "opengl32 .lib "tệp.

Và cuối cùng thực hiện tất cả bằng cách chỉ cần nhập "kiểm tra" trong bảng điều khiển MATLAB. Nó sẽ mang đến một cửa sổ với đáp ứng tần số bộ lọc và một cửa sổ khác với bộ đệm độ sâu. Lưu ý các bộ đệm trước và sau được hoán đổi tại thời điểm mã "C" đọc bộ đệm độ sâu, vì vậy có thể cần chạy kịch bản hai lần để nhận bất kỳ kết quả nào (vì vậy bộ đệm phía trước hiện có chứa các kết quả hoán đổi với bộ đệm sau) và chiều sâu có thể được đọc).Điều này có thể được thực hiện tự động bằng "C", hoặc bạn có thể thử bao gồm getframe (gcf); ở cuối kịch bản của bạn (mà đọc lại từ OpenGL cũng như vậy nó hoán đổi bộ đệm cho bạn, hoặc một cái gì đó).

Điều này phù hợp với tôi trong Matlab 7.6.0.324 (R2008a). Tập lệnh chạy và phun ra như sau:

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

Và tất nhiên nó sẽ hiển thị hình ảnh. Lưu ý phạm vi bộ đệm độ sâu phụ thuộc vào Matlab, và có thể khá cao, do đó, làm cho bất kỳ ý nghĩa của hình ảnh được tạo ra có thể không được đơn giản.

+0

oh, tôi đã bỏ lỡ các yêu cầu. tất nhiên điều này làm việc với surf() quá. vừa thử mã tại: http://www.mathworks.com/help/techdoc/ref/surf.html và nhận: http://www.luki.webzdarma.cz/up/depthmap.png rõ ràng là –

+3

Bạn xứng đáng một huy chương, một loại bia khác và 300 đại diện. – twerdster

+1

Tôi có thể khuyên bạn nên đặt tất cả những thứ đó lại với nhau và biến nó thành một bài nộp tốt cho toán học? Im không phải là người duy nhất thấy điều này hữu ích. – twerdster

2

số lợn là câu trả lời đúng. Đây là phiên bản được định dạng và đơn giản hơn một chút, là nền tảng đa nền tảng.

Tạo một tập tin gọi 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; 
} 

Sau đó, nếu bạn đang ở trên cửa sổ biên dịch sử dụng

mex mexGetDepth.c "path to OpenGL32.lib" 

hoặc nếu bạn đang ở trên một hệ thống nix

mex mexGetDepth.c "path to opengl32.a" 

Sau đó chạy sau tập lệnh nhỏ để kiểm tra chức năng mới

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

chúng ta có cần khai báo glGetIntegerv và glReadPixels fucntions ở đâu đó không? Trong mã ban đầu, nó được thực hiện bằng cách sử dụng extern WINAPI void ..., nhưng tôi không chắc chắn làm thế nào chúng ta sẽ làm điều đó trong linux –