2009-02-08 98 views
4

我正在製作一些自定義圖像處理應用程序。該程序將由控制檯中的簡單菜單驅動。用戶將輸入圖像的文件名,該圖像將在窗口中使用openGL顯示。當用戶選擇對圖像進行一些處理時,處理完成,openGL窗口應該重新繪製圖像。控制檯菜單更新OpenGL窗口

我的問題是我的圖像從來沒有繪製到窗口,而是窗口始終是黑色的。我認爲這可能與我在程序中組織線程的方式有關。主執行線程處理菜單輸入/輸出和圖像處理,並調用Display方法,而第二個線程運行openGL主循環。

這裏是我的主要代碼:

#include <iostream> 
#include <GL/glut.h> 
#include "ImageProcessor.h" 
#include "BitmapImage.h" 

using namespace std; 

DWORD WINAPI openglThread(LPVOID param); 
void InitGL(); 
void Reshape(GLint newWidth, GLint newHeight); 
void Display(void); 

BitmapImage* b; 
ImageProcessor ip; 


int main(int argc, char *argv[]) { 
    DWORD threadID; 
    b = new BitmapImage(); 

    CreateThread(0, 0, openglThread, NULL, 0, &threadID); 

    while(true) { 
     char choice; 
     string path = "TestImages\\"; 
     string filename; 
     cout << "Enter filename: "; 
     cin >> filename; 
     path += filename; 
     b = new BitmapImage(path); 
     Display(); 

     cout << "1) Invert" << endl; 
     cout << "2) Line Thin" << endl; 
     cout << "Enter choice: "; 
     cin >> choice; 

     if(choice == '1') { 
      ip.InvertColour(*b); 
     } 
     else { 
      ip.LineThinning(*b); 
     } 
     Display(); 
    } 

    return 0; 
} 


void InitGL() { 
    int argc = 1; 
    char* argv[1]; 
    argv[0] = new char[20]; 
    strcpy(argv[0], "main"); 

    glutInit(&argc, argv); 

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
    glutInitWindowPosition(0, 0); 
    glutInitWindowSize(800, 600); 
    glutCreateWindow("ICIP Program - Character recognition using line thinning, Hilbert curve, and wavelet approximation"); 

    glutDisplayFunc(Display); 
    glutReshapeFunc(Reshape); 

    glClearColor(0.0,0.0,0.0,1.0); 

    glEnable(GL_DEPTH_TEST); 
} 


void Reshape(GLint newWidth, GLint newHeight) { 
    /* Reset viewport and projection parameters */ 
    glViewport(0, 0, newWidth, newHeight); 
} 


void Display(void) { 
    glClear (GL_COLOR_BUFFER_BIT); // Clear display window. 
    b->Draw(); 
    glutSwapBuffers(); 
} 


DWORD WINAPI openglThread(LPVOID param) { 
    InitGL(); 
    glutMainLoop(); 
    return 0; 
} 

這裏是我的BitmapImage抽獎方法:

void BitmapImage::Draw() { 
    cout << "Drawing" << endl; 
    if(_loaded) { 
     glBegin(GL_POINTS); 
      for(unsigned int i = 0; i < _height * _width; i++) { 
       glColor3f(_bitmap_image[i*3]/255.0, _bitmap_image[i*3+1]/255.0, _bitmap_image[i*3+2]/255.0); 
       // invert the y-axis while drawing 
       glVertex2i(i % _width, _height - (i/_width)); 
      } 
     glEnd(); 
    } 
} 

任何想法的問題?

編輯:問題在技術上通過從每500毫秒調用glutPostRedisplay()的openglThread啓動glutTimer來解決。現在可以,但我更喜歡一種解決方案,在每次更改位圖時只需重新顯示(以節省處理時間),另一種解決方案不需要運行另一個線程(定時器是另一個線程我假設)。這主要是因爲主要的處理線程將進行大量的密集工作,我想將大部分資源投入到這個線程中,而不是其他任何東西。

+0

投票關閉,爲什麼不是這段代碼工作。 – 2016-05-01 09:25:04

回答

3

我以前有過這個問題 - 這很煩人。問題是所有的OpenGL調用都必須在您啓動OpenGL上下文的線程中完成。所以當你想要你的主(輸入)線程改變OpenGL線程中的某些東西時,你需要以某種方式告訴線程它需要做什麼(設置一個標誌或某物)。

注意:我不知道你的BitmapImage加載函數(這裏是你的構造函數)的作用,但它可能有一些OpenGL調用。以上也適用於此!所以你需要發信號給另一個線程來爲你創建一個BitmapImage,或者至少做一下創建位圖的OpenGL相關部分。

+0

這並不完全準確,但要求OpenGL上下文只能針對任何單個線程。但是,上下文可以在與當前不同的線程中創建。例如,這對於屏幕外渲染非常有用。 – codelogic 2009-02-08 08:30:24

+0

只是爲了澄清,這種情況下的問題絕對是多線程渲染,因爲OP使用相同的上下文從不同的線程進行gl調用,或者更確切地說是一個不存在的上下文(在主線程中)。 – codelogic 2009-02-08 08:34:14

0

您的問題可能在該行

B->繪製在顯示器()();

我看不到b被傳入Display()的範圍。

1

的幾點:

  • 一般來說,如果你要多線程的路線,這是最好,如果你的主線程是您的GUI線程,即它不會最小的任務保持GUI響應。在你的情況下,我建議將密集的圖像處理任務移動到一個線程中,並在主線程中進行OpenGL渲染。

  • 爲了繪製圖像,您使用的是頂點而不是紋理四邊形。除非你有很好的理由,否則使用單個紋理四邊形(處理後的圖像就是紋理)的速度會更快。檢查出glTexImage2DglTexSubImage2D

  • 如果您使用加速的OpenGL實現(在任何現代系統上幾乎可以保證),並且如果您使用的是以2fps(500ms,如您所述)的渲染速率,對資源的影響可以忽略不計紋理四邊形而不是每個像素的頂點。

0

您需要在創建上下文的線程(glutInitDisplayMode)上進行OpenGL調用。因此,在不同線程中的Display方法中的glXX調用將不會被定義。您可以通過轉儲函數地址輕鬆地看到它,希望它可以是未定義的或NULL。

0

這聽起來像500毫秒計時器定期調用顯示()後,2調用它填充後緩衝區和前緩衝區具有相同的呈現。 Display()繼續被調用,直到用戶輸入OpenGL線程永遠不會知道的東西,但由於全局變量b現在不同,所以線程會盲目地使用Display()中的內容。

那麼,如何做Jesse Beder所說的,並使用全局int,稱之爲標誌,來標記用戶輸入內容的時間。例如:

set flag = 1;在你做完b = new BitmapImage(path)之後;

然後設置標誌= 0;從OpenGL線程調用Display()之後。

您在定時器上循環,但現在檢查標誌是否爲1.您只需在flag = 1時調用glutPostRedisplay(),即用戶輸入了某些內容。

似乎沒有使用睡眠/喚醒機制的好方法。在多個線程中訪問全局變量也可能是不安全的。我認爲在這裏可能發生的最糟糕的情況是OpenGL線程在讀取flag = 1時發生錯誤讀取標誌= 0。然後它應該在不超過幾次迭代後捕獲它。如果您遇到奇怪的行爲,請進行同步。

隨着您顯示的代碼,您可以在main()中調用Display()兩次。實際上,main()甚至不需要調用Display(),OpenGL線程就可以做到這一點。