歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenGL超級寶典學習筆記——操作像素

OpenGL支持放大,縮小,旋轉圖像。下面將舉例介紹這些像素的操作。下面的例子是從tga文件中讀取圖片並顯示,而且可以通過右鍵菜單來選擇圖像的顯示模式和保存圖片的快照到磁盤命名為screenshot.tga。完整的代碼示例如下:

#include "gltools.h" #include <math.h> static GLbyte *pImage = NULL; static GLint iRenderMode = 0; static GLint iWidth, iHeight, iComponents; static GLenum eFormat; void ProcessMenu(int value)
{ if (value == 1)
    { //保存圖像的快照 gltWriteTGA("screenshot.tga");
    } else {
        iRenderMode = value;
    }

    glutPostRedisplay();

} void RenderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (!pImage)
    { return;
    } //設置光柵位置 glRasterPos2i(0, 0); //修改的圖像,和用於反轉的映射數組 GLbyte *pModifyImage = NULL;
  GLfloat invertMap[256]; switch (iRenderMode)
    { case 2: //圖像倒轉 glPixelZoom(-1.0f, -1.0f); //倒轉後的圖像的,渲染方向也倒轉過來了,變成了從右上角開始往左下角渲染,所以設置倒轉後的光柵位置為圖像的寬高。 glRasterPos2i(iWidth, iHeight); break; case 3: //讓圖像填充滿屏幕 GLint viewport[4]; //取得視口的大小 glGetIntegerv(GL_VIEWPORT, viewport); //按比例縮放 glPixelZoom((GLfloat)viewport[2]/iWidth, (GLfloat)viewport[3]/iHeight); break; case 4: //只保留紅色 glPixelTransferf(GL_RED_SCALE, 1.0f);
    glPixelTransferf(GL_GREEN_SCALE, 0.0f);
    glPixelTransferf(GL_BLUE_SCALE, 0.0f); break; case 5: //只保留綠色 glPixelTransferf(GL_RED_SCALE, 0.0f);
    glPixelTransferf(GL_GREEN_SCALE, 1.0f);
    glPixelTransferf(GL_BLUE_SCALE, 0.0f); break; case 6: //只保留藍色 glPixelTransferf(GL_RED_SCALE, 0.0f);
    glPixelTransferf(GL_GREEN_SCALE, 0.0f);
    glPixelTransferf(GL_BLUE_SCALE, 1.0f); break; case 7: //先渲染圖像到顏色緩沖區中 glDrawPixels(iWidth, iHeight, eFormat, GL_UNSIGNED_BYTE, pImage); //NTSC標准,轉成黑白圖像  glPixelTransferf(GL_RED_SCALE, 0.3f);
    glPixelTransferf(GL_GREEN_SCALE, 0.59f);
    glPixelTransferf(GL_BLUE_SCALE, 0.11f); //申請臨時空間來保存修改後的圖像 pModifyImage = (GLbyte *)malloc(iWidth * iHeight * 3); if (!pModifyImage)
    { return;
    } //從顏色緩沖區中讀取圖像的亮度數據 glReadPixels(0, 0, iWidth, iHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, pModifyImage); //還原 glPixelTransferf(GL_RED_SCALE, 1.0f);
    glPixelTransferf(GL_GREEN_SCALE, 1.0f);
    glPixelTransferf(GL_BLUE_SCALE, 1.0f); break; case 8: //設置反轉的顏色映射 invertMap[0] = 1.0f; for(int i = 0; i < 256; ++i)
    {
      invertMap[i] = 1.0f - (1.0f / 255.0f * (GLfloat)i);
    } //映射 glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 255, invertMap);
    glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 255, invertMap);
    glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 255, invertMap); //開啟顏色映射 glPixelTransferi(GL_MAP_COLOR, GL_TRUE); default: break;
    } if (pModifyImage)
  { //畫黑白圖像 glDrawPixels(iWidth, iHeight, GL_RGB, GL_UNSIGNED_BYTE, pModifyImage);
    free(pModifyImage);
  } else {
      glDrawPixels(iWidth, iHeight, eFormat, GL_UNSIGNED_BYTE, pImage);
  } //還原 glPixelTransferf(GL_RED_SCALE, 1.0f);
  glPixelTransferf(GL_GREEN_SCALE, 1.0f);
  glPixelTransferf(GL_BLUE_SCALE, 1.0f);
  glPixelZoom(1.0f, 1.0f);
  glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
    glutSwapBuffers();
} void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //設置像素的存儲格式 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //加載圖像數據 pImage = gltLoadTGA("horse.tga", &iWidth, &iHeight, &iComponents, &eFormat);

} //釋放圖像數據占用的內存空間 void ShutdownRC()
{ if (pImage)
    {
        free(pImage);
        pImage = NULL;
    }
} void ChangeSize(GLsizei w, GLsizei h)
{ if (h == 0)
        h = 1;

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glutPostRedisplay();
} int main(int args, char **argv)
{
    glutInit(&args, argv);
    glutInitDisplayMode(GL_RGB | GL_DOUBLE);
    glutInitWindowSize(800, 600);
    glutCreateWindow("pixel operation");
    
    glutDisplayFunc(RenderScene);
    glutReshapeFunc(ChangeSize); //設置菜單 int menuID = glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Save Image", 1);
    glutAddMenuEntry("Flip", 2);
    glutAddMenuEntry("zoom pixel fill window", 3);
  glutAddMenuEntry("Just Red", 4);
  glutAddMenuEntry("Just Green", 5);
  glutAddMenuEntry("Just Blue", 6);
  glutAddMenuEntry("black & white", 7);
  glutAddMenuEntry("invert map", 8);
    glutAttachMenu(GLUT_RIGHT_BUTTON);

    SetupRC();
    glutMainLoop();
    ShutdownRC(); return 0;
}

SetupRC函數用於加載圖像數據,保存圖像數據,圖像的寬高和格式等信息。

glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //設置像素的存儲格式 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //加載圖像數據 pImage = gltLoadTGA("horse.tga", &iWidth, &iHeight, &iComponents, &eFormat);

在程序退出時,記得釋放為圖像數據分配的內存,在ShutdownRC中釋放圖像數據

if (pImage)
{
    free(pImage);
    pImage = NULL;
}

在main函數中,創建菜單,為每個菜單項分配鍵值,然後綁定到右鍵上。

//設置菜單 int menuID = glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("Save Image", 1);
    glutAddMenuEntry("Flip", 2);
    glutAddMenuEntry("zoom pixel fill window", 3);
  glutAddMenuEntry("Just Red", 4);
  glutAddMenuEntry("Just Green", 5);
  glutAddMenuEntry("Just Blue", 6);
  glutAddMenuEntry("black & white", 7);
  glutAddMenuEntry("invert map", 8);
    glutAttachMenu(GLUT_RIGHT_BUTTON);

根據所選擇的菜單進行相應的操作,默認情況下是通過glDrawPixels函數把圖像放置在窗口的左下角顯示。第一個菜單項Save Image是保存圖像的快照。

像素縮放

常見的圖像操作,放大和縮小圖像。OpenGL提供了一個對圖像進行縮放的函數:

void glPixelZoom(GLfloat xfactor, GLfloat yfactor);

xfactor,yfactor指定了在x,y方向上縮放的倍數。圖像的縮放包括了放大,縮小和反轉。例如:如果x方向上的縮放因子為2,那麼圖像在x方向上會放大2被。在本例中選擇第三項菜單可以把圖像填滿窗口:

//讓圖像填充滿屏幕 GLint viewport[4]; //取得視口的大小 glGetIntegerv(GL_VIEWPORT, viewport); //按比例縮放 glPixelZoom((GLfloat)viewport[2]/iWidth, (GLfloat)viewport[3]/iHeight);

如果縮放因子為負值,效果就是沿縮放方向進行反轉。此時不僅僅反轉了圖像中像素的排列順序,而且也翻轉圖像根據光柵位置在屏幕上繪制的方向。例如,一般是圖像的左下角放置在當前光柵位置,如果兩個縮放因子都為負值則圖像的右上角被放置在當前光柵位置處:

//圖像倒轉 glPixelZoom(-1.0f, -1.0f); //倒轉後的圖像的,渲染方向也倒轉過來了,變成了從右上角���始往左下角渲染,所以設置倒轉後的光柵位置為圖像的寬高。 glRasterPos2i(iWidth, iHeight);

像素變換

除了像素的縮放之外,OpenGL還支持對圖像進行一些簡單的數學操作。把像素轉移到顏色緩沖區或者從顏色緩沖區轉移出來。可以調用下面兩個函數來實現:

void glPixelTransferi(GLenum pname, GLint param);

void glPixelTransferf(GLenum pname, GLfloat param);

pname的枚舉值如下表:

縮放和偏轉參數允許縮放和偏轉單獨的顏色通道。縮放因子將與顏色成分值相乘,偏轉值則與顏色成分值相加。公式如下:

新值 = (舊值 * 縮放因子)+偏轉值

默認情況下縮放因子是1.0,偏轉值是0.0。如果想讓圖像只顯示紅色成分值,則可以設置綠色和藍色的縮放因子為0.0.

glPixelTransferf(GL_GREEN_SCALE, 0.0f);

glPixelTransferf(GL_BLUE_SCALE, 0.0f);

例子中,分別顯示紅色,綠色,藍色成分值的代碼:

case 4: //只保留紅色 glPixelTransferf(GL_RED_SCALE, 1.0f);
  glPixelTransferf(GL_GREEN_SCALE, 0.0f);
  glPixelTransferf(GL_BLUE_SCALE, 0.0f); break; case 5: //只保留綠色 glPixelTransferf(GL_RED_SCALE, 0.0f);
  glPixelTransferf(GL_GREEN_SCALE, 1.0f);
  glPixelTransferf(GL_BLUE_SCALE, 0.0f); break; case 6: //只保留藍色 glPixelTransferf(GL_RED_SCALE, 0.0f);
  glPixelTransferf(GL_GREEN_SCALE, 0.0f);
  glPixelTransferf(GL_BLUE_SCALE, 1.0f); break;

在繪制完成後把各個顏色通道的縮放因子復原。

//還原 glPixelTransferf(GL_RED_SCALE, 1.0f);
   glPixelTransferf(GL_GREEN_SCALE, 1.0f);
   glPixelTransferf(GL_BLUE_SCALE, 1.0f);

我們還可以把一幅彩色圖像轉成黑白顏色來顯示。首先把彩色圖像渲染到顏色緩沖區中: glDrawPixels(iWidth, iHeight, eFormat, GL_UNSIGNED_BYTE, pImage); 然後分配一個用來保存每個像素亮度值的內存空間: pModifyImage = (GLbyte *)malloc(iWidth * iHeight); 亮度圖像只有一個通道,所以我們只分配一個字節來存儲亮度值。把當前顏色緩沖區中的顏色通道進行變換:使用NTSC(美國國家電視系統委員會)標准轉成黑白圖像

glPixelTransferf(GL_RED_SCALE, 0.3f);
glPixelTransferf(GL_GREEN_SCALE, 0.59f);
glPixelTransferf(GL_BLUE_SCALE, 0.11f);

然後通過glReadPixel來從顏色緩沖區中讀取圖像的亮度值到pModifyImage指向的內存區域中。 glReadPixel(0, 0, iWidth, iHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, pModifyImage); 最後把pModifyImage的數據寫會顏色緩沖區中: glDrawPixel(iWidth, iHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, pModifyImage);   OpenGl把彩色圖像轉換成亮度圖,只是把各個顏色通道的值相加得到亮度值,超過1.0的設置為1.0,這樣得到的效果不是很好: 為了得到更好的效果,我們可以通過NTSC標准把彩色圖像轉換成灰度圖。從RGB顏色空間轉換到黑白色彩空間的轉換公式是: 亮度 = (0.3 * 紅色) + (0.59 * 綠色) + (0.11 * 藍色);
//NTSC標准  glPixelTransferf(GL_RED_SCALE, 0.3f);
    glPixelTransferf(GL_GREEN_SCALE, 0.59f);
    glPixelTransferf(GL_BLUE_SCALE, 0.11f);

得到的效果是更好看的灰度圖:

OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見  http://www.linuxidc.com/Linux/2013-10/91413.htm

OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm

OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm

Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm

OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm

Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm

如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm 

更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581

Copyright © Linux教程網 All Rights Reserved