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);
glPixelTransferf(GL_RED_SCALE, 0.3f);
glPixelTransferf(GL_GREEN_SCALE, 0.59f);
glPixelTransferf(GL_BLUE_SCALE, 0.11f);
//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