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中釋放圖像數據 oop

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

在main函數中,建立菜單,爲每一個菜單項分配鍵值,而後綁定到右鍵上。 spa

//設置菜單 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是保存圖像的快照。 .net

image

像素縮放

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

void glPixelZoom(GLfloat xfactor, GLfloat yfactor); orm

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

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

image

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

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

像素變換

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

void glPixelTransferi(GLenum pname, GLint param);

void glPixelTransferf(GLenum pname, GLfloat param);

pname的枚舉值以下表:

image

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

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

默認狀況下縮放因子是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,這樣獲得的效果不是很好:
image
爲了獲得更好的效果,咱們能夠經過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);

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

image

相關文章
相關標籤/搜索