CG15
OpenGL緩沖區、讀寫操作以及混合(Blending)
一、OpenGL緩沖區概述
OpenGL中的緩沖區是用于存儲像素數據的內存區域,主要包括以下類型:
- 顏色緩沖區(Color Buffer):存儲每個像素的顏色值。
- 深度緩沖區(Depth Buffer):存儲每個像素的深度信息,用于深度測試。
- 模板緩沖區(Stencil Buffer):用于復雜的像素操作,如遮罩和多重渲染通道控制。
- 累積緩沖區(Accumulation Buffer):用于圖像的累積操作,如抗鋸齒、模糊等。
- 輔助緩沖區(Auxiliary Buffer):提供額外的渲染目標。
- 覆蓋緩沖區(Overlay Buffer):用于顯示覆蓋內容,如HUD界面。
這些緩沖區共同構成了幀緩沖區(Frame Buffer),是OpenGL渲染管線的核心部分。
二、緩沖區的定義
一個緩沖區由以下參數定義:
- 空間分辨率:寬度(n)×高度(m),例如1920×1080。
- 顏色深度(k):每個像素的位數,決定顏色或數據的精度。例如,8位/像素表示256種灰度級別,24位/像素(RGB各8位)表示16.7百萬種顏色。
這些參數決定了緩沖區的存儲容量和顯示精度。
三、OpenGL幀緩沖區結構
幀緩沖區是OpenGL中用于存儲最終渲染圖像的內存區域,由多個子緩沖區組成:
- 前緩沖區(Front Buffer):當前顯示在屏幕上的內容。
- 后緩沖區(Back Buffer):用于后臺渲染,完成后與前緩沖區交換,避免閃爍。
- 深度緩沖區(Depth Buffer):用于深度測試,決定像素的可見性。
- 模板緩沖區(Stencil Buffer):用于控制像素是否被繪制,常用于復雜渲染效果。
通過這些緩沖區的協同工作,OpenGL實現了高效的圖形渲染。
四、緩沖區的讀寫操作
寫入前讀取目標像素,使用組合函數:
d ′ = f ( s , d ) d' = f(s, d) d′=f(s,d)
- s s s:源像素(來自CPU或紋理)
- d d d:目標像素(幀緩沖區已有)
- f f f:如替換、加法、XOR等邏輯運算
1. 寫入緩沖區
OpenGL提供了多種函數用于將數據寫入緩沖區:
// 設置清除顏色
glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);// 清除顏色緩沖區
glClear(GL_COLOR_BUFFER_BIT);
對于更復雜的寫入操作,可以使用以下函數:
// 寫入像素數據
glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
2. 讀取緩沖區
從緩沖區讀取數據的函數包括:
// 讀取像素數據
glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
在讀取之前,可以指定讀取的緩沖區:
// 指定讀取的緩沖區
glReadBuffer(GLenum mode); // 例如:GL_FRONT, GL_BACK
這些操作允許在應用程序中獲取渲染結果,用于后續處理或保存。
五、混合(Blending)技術
混合是指在渲染時將源顏色(即將要繪制的顏色)與目標顏色(即當前緩沖區中的顏色)按照一定規則進行組合的過程,常用于實現透明效果或顏色疊加。
1. 啟用混合
在使用混合功能前,需要啟用混合:
glEnable(GL_BLEND);
2. 設置混合函數
混合函數定義了源顏色和目標顏色的組合方式:
glBlendFunc(GLenum sfactor, GLenum dfactor);
常用的參數包括:
- GL_ZERO:因子為0。
- GL_ONE:因子為1。
- GL_SRC_ALPHA:源顏色的alpha值。
- GL_ONE_MINUS_SRC_ALPHA:1減去源顏色的alpha值。
例如,實現標準的alpha混合:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3. 混合公式
混合的數學公式如下:
C r e s u l t = C s r c × F s r c + C d s t × F d s t C_{result} = C_{src} \times F_{src} + C_{dst} \times F_{dst} Cresult?=Csrc?×Fsrc?+Cdst?×Fdst?
其中:
- C r e s u l t C_{result} Cresult?:混合后的顏色。
- C s r c C_{src} Csrc?:源顏色。
- C d s t C_{dst} Cdst?:目標顏色。
- F s r c F_{src} Fsrc?:源因子。
- F d s t F_{dst} Fdst?:目標因子。
通過調整混合函數的參數,可以實現多種視覺效果。
六、邏輯操作(Logical Operations)
-
XOR交換機制(三次異或可以無損交換兩塊數據):
S = S ⊕ M; M = S ⊕ M; S = S ⊕ M;
OpenGL提供了邏輯操作功能,用于在像素級別進行位操作,如異或(XOR)、與(AND)、或(OR)等。
1. 啟用邏輯操作
在使用邏輯操作前,需要啟用該功能:
glEnable(GL_COLOR_LOGIC_OP);
2. 設置邏輯操作模式
使用glLogicOp
函數設置邏輯操作模式:
glLogicOp(GLenum opcode);
常用的操作碼包括:
- GL_COPY:直接復制源顏色。
- GL_XOR:源顏色與目標顏色進行異或操作。
- GL_AND:源顏色與目標顏色進行與操作。
- GL_OR:源顏色與目標顏色進行或操作。
例如,使用異或操作:
glLogicOp(GL_XOR);
需要注意,啟用邏輯操作后,混合功能將被禁用。
七、位圖(Bitmap)操作
位圖(bitmap)是 1位圖像,作為掩碼使用:
- 0 → 不修改幀緩沖區
- 1 → 用當前光柵顏色繪制
典型用途:
- 文本渲染(GLUT字體)
- 光標顯示
OpenGL提供了glBitmap
函數,用于繪制1位像素的位圖,常用于渲染文本或簡單圖形。
1. 使用glBitmap
繪制位圖
函數定義:
void glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
參數說明:
- width, height:位圖的寬度和高度。
- xorig, yorig:位圖原點相對于當前光柵位置的偏移。
- xmove, ymove:繪制位圖后,光柵位置的移動量。
- bitmap:位圖數據。
使用示例:
glRasterPos2f(x, y); // 設置光柵位置
glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap);
這將在指定位置繪制位圖,并更新光柵位置。
文本繪制與像素操作
一、OpenGL中文本繪制(第19頁)
1. 文本渲染方式
OpenGL 支持兩種主要文本渲染方式:
- 光柵文本(Raster Text):
- 使用位圖(bitmap)表示字符;
- 渲染速度快,適合實時應用;
- 不能放大縮小(不具備矢量特性);
- 實現函數:
glutBitmapCharacter()
。
- 向量文本(Vector Text):
- 使用輪廓曲線或多邊形定義字符;
- 可縮放和旋轉,但渲染開銷大;
- 常用于打印、高質量文本展示;
- 實現函數:如
glutStrokeCharacter()
。
2. 字體與字號
- 示例字體:
Times
,Courier
,Computer Modern
; - 字體大小使用 點(pt) 表示,1 英寸 = 72 點;
- 10pt、24pt 等常用;
- 24pt 在72DPI的顯示器上約高1/3英寸。
二、位圖圖形與繪制示例
棋盤格位圖示例
GLubyte wb[2] = {0x00, 0xFF}; // 黑白色像素
GLubyte check[512]; // 512字節,表示64×64位圖for (i = 0; i < 64; i++) {for (j = 0; j < 8; j++) {check[i * 8 + j] = wb[(i / 8 + j) % 2];}
}
glBitmap(64, 64, 0.0, 0.0, 0.0, 0.0, check);
- 每字節表示8個像素(1個位 = 1像素);
- 使用
glBitmap
繪制此圖案。
三、圖像格式支持(第21~25頁)
OpenGL與圖像格式
OpenGL 只處理原始像素數據,不直接支持如 JPEG、TIFF 等格式。
格式 | 特點 | OpenGL處理方式 |
---|---|---|
JPEG | 有損壓縮,壓縮率高 | 解碼為RGB數組 |
TIFF | 無損壓縮,適合高質量圖像 | 解碼為像素數組 |
GIF | 256色索引圖像,支持簡單動畫 | 解碼為RGB或灰度 |
PS/EPS | 矢量格式,常用于出版 | 不能直接使用,需轉為像素 |
PPM | 原始像素格式,易解析 | 適合教學或快速測試 |
結論:需借助第三方庫如 SOIL、stb_image、FreeImage 進行圖像加載。
四、圖像扭曲與矢量化引導
圖像的數學定義(第26頁)
- 圖像是二維函數 I ( x , y ) I(x, y) I(x,y),每個坐標點對應顏色值;
- 在計算機中是離散的,即 f ( i , j ) f(i, j) f(i,j);
- 這種定義為圖像處理與分析提供數學基礎。
五、圖像大小與格式壓縮對比(第32頁)
- 示例圖像:1200 × 1200 像素(RGB,每像素3字節);
- 原始未壓縮大小 ≈ 4.12 MB;
- 使用 TIFF(無損壓縮)后 ≈ 1.37 MB;
- 說明:壓縮格式顯著降低存儲大小,但需轉換為原始數據才能在 OpenGL 中使用。
六、OpenGL像素圖像處理流程
像素基本概念
- OpenGL 支持的圖像類型:
- 灰度圖:1字節/像素;
- RGB 圖:3字節/像素;
- 支持三種像素操作:
- 繪制像素(glDrawPixels)
- 讀取像素(glReadPixels)
- 復制像素(glCopyPixels)
像素格式與類型
- 像素格式:
GL_RGB
,GL_RGBA
,GL_COLOR_INDEX
; - 數據類型:
GL_UNSIGNED_BYTE
,GL_FLOAT
; - 函數:
glPixelMap
可實現像素值的映射與替換(顏色替換、亮度調整等)。
像素讀寫函數
// 讀取像素
glReadPixels(x, y, width, height, format, type, data);// 繪制像素
glDrawPixels(width, height, format, type, data);
- 用于圖像保存、截圖或離屏處理。
圖像數據縮放
glPixelTransferf(GL_RED_SCALE, s);
glPixelTransferf(GL_GREEN_SCALE, s);
glPixelTransferf(GL_BLUE_SCALE, s);
- 調整顏色通道的縮放因子 s s s,用于圖像增強;
- 開啟字節交換以適應不同平臺字節序:
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
像素讀取示例
glReadPixels(200, 200, 200, 200, GL_RGB, GL_UNSIGNED_BYTE, p);
- 將中心區域200×200像素讀取到內存,存入
char p[120000]
。
像素繪制示例
glRasterPos2f(-1.0, -1.0);
glDrawPixels(200, 200, GL_RGB, GL_UNSIGNED_BYTE, p);
- 將剛才讀取的數據繪制到窗口左下角,實現“像素復制”。
圖像縮放(第39頁)
glPixelZoom(xscale, yscale);
-
控制
glDrawPixels
的縮放比例; -
xscale/yscale:
-
1:放大;
-
<1:縮小;
-
<0:翻轉;
-
示例:
glPixelZoom(2.0, 2.0); // 放大2倍
glPixelZoom(0.5, 0.5); // 縮小1/2
顯示回調函數
void display() {glClear(GL_COLOR_BUFFER_BIT);glRasterPos2i(0, 0);glDrawPixels(n, m, GL_RGB, GL_UNSIGNED_INT, image);glFlush();
}
- 用于注冊到 GLUT 顯示回調;
- 核心流程包括:清屏 → 設置光柵位置 → 繪圖 → 刷新
Convex and Compact Superpixels byEdge-Constrained Centroidal Power Diagram
一、基本背景:什么是“超像素”?
在圖像處理中,**像素(pixel)**是圖像的最小單元,每個像素表示一個顏色值。但是像素是按網格排列的,不攜帶高級結構信息。
于是人們提出了**超像素(superpixel)**的概念:
- 將相鄰、顏色或紋理相似的像素聚合成一個區域。
- 每個區域就稱為一個“超像素”。
- 好處是:更緊湊的表示、更少的計算、更易于分析。
舉例:
- 100x100像素圖像有1萬個像素。
- 用200個超像素表示它,可以顯著減少處理開銷。
- 在目標檢測、分割、壓縮中,超像素是常用的預處理步驟。
二、動機:為什么要“凸且緊湊”的超像素?
“凸”(convex)意味著一個區域中任意兩點之間的直線仍在區域內部,這種形狀:
- 更規則,邊界清晰。
- 更適合后續矢量化或對象檢測。
“緊湊”(compact)意味著區域面積小,形狀接近圓形或正方形:
- 降低冗余。
- 保持每個區域的信息集中。
三、傳統方法:Voronoi圖與質心Voronoi圖(CVT)
**Voronoi圖(Voronoi Diagram)**是一個經典的幾何工具:
給定一組點(稱為“站點”),它把空間劃分為若干個區域,使得:
每個區域包含所有離某個站點最近的點。
數學定義:
v i = { x ∈ Ω ∣ ∥ x ? x i ∥ ≤ ∥ x ? x j ∥ , ? j ≠ i } v_i = \{ x \in \Omega \mid \|x - x_i\| \leq \|x - x_j\|,\ \forall j \neq i \} vi?={x∈Ω∣∥x?xi?∥≤∥x?xj?∥,??j=i}
進一步優化后,就得到:
質心Voronoi圖(Centroidal Voronoi Tessellation, CVT):
- 每個站點位于其區域的“質心”上。
- 實現區域形狀優化,使區域更規則、對稱。
但問題是:CVT無法直接控制區域大小,不利于圖像復雜區域的自適應劃分。
四、改進:功率圖(Power Diagram)與質心功率圖(CPD)
**功率圖(Power Diagram)**是在Voronoi圖上加權:
數學形式:
v i pow = { x ∈ Ω ∣ ∥ x ? x i ∥ 2 ? w i ≤ ∥ x ? x j ∥ 2 ? w j } v_i^{\text{pow}} = \{ x \in \Omega \mid \|x - x_i\|^2 - w_i \leq \|x - x_j\|^2 - w_j \} vipow?={x∈Ω∣∥x?xi?∥2?wi?≤∥x?xj?∥2?wj?}
特點:
- 每個站點x_i有一個權重w_i。
- 權重越大,對應的區域越小。
- 可以控制每個超像素的大小。
結合CVT與功率圖,就得到:
質心功率圖(Centroidal Power Diagram, CPD)
- 站點位于其功率區域的質心。
- 引入權重,使區域大小可調節。
五、ECCPD算法:論文核心方法
ECCPD = Edge-Constrained Centroidal Power Diagram
(1)優化目標函數:
E ( X , W ) = ∑ i = 1 N ∫ P W i ∥ x ? x i ∥ 2 d σ + λ ∑ i = 1 N ( w i ? Weight ( x i ) ) 2 E(X, W) = \sum_{i=1}^{N} \int_{P_{W_i}} \|x - x_i\|^2 d\sigma + \lambda \sum_{i=1}^N (w_i - \text{Weight}(x_i))^2 E(X,W)=i=1∑N?∫PWi???∥x?xi?∥2dσ+λi=1∑N?(wi??Weight(xi?))2
解釋:
- 第一項:區域內點到站點的距離平方和 → 控制緊湊性。
- 第二項:當前權重與圖像特征(如邊緣、顏色)的偏差平方和 → 控制適應性。
- λ:平衡這兩部分的系數。
最終目標:調整站點位置x_i和權重w_i,使E最小。
六、ECCPD算法流程
- 初始化:
- 輸入圖像。
- 設定初始站點位置(隨機或邊緣引導)。
- 分配初始權重(可設為常數或邊緣相關)。
- 迭代優化:
- 計算每個區域的質心。
- 調整站點到質心。
- 更新權重。
- 后處理:
- 使邊界與圖像邊緣對齊。
- 修正區域形狀以提高凸性。
七、權重函數的設計:結合圖像內容自適應
使用了距離場函數:
Dist ( p ) = v ? Eudist ( p ) \text{Dist}(p) = v \cdot \text{Eudist}(p) Dist(p)=v?Eudist(p)
含義:
- Eudist§:點p到最近邊緣的歐氏距離。
- v:縮放因子(越大則邊緣區域更小)。
效果:
- 邊緣區域(Eudist小)→ 超像素小 → 保留邊緣細節。
- 內部區域(Eudist大)→ 超像素大 → 減少不必要的細節。
還結合了顏色差異,調整相鄰區域顏色差異大的權重,增強內容敏感性。
八、實驗分析與結果可視化
- 數據集:BSDS500, PASCAL-S。
- 評估指標:
- COM:緊湊性(越高越好)。
- BR:邊界召回率。
- USE:未分割率(越低越好)。
- ASA:平均分割精度(越高越好)。
結果顯示:ECCPD在保持高精度的同時,緊湊性領先于所有對比方法。
九、應用舉例
1. 圖像壓縮:
- 用幾千個凸超像素替代十幾萬像素。
- 減少存儲或傳輸成本。
2. 多邊形輪廓提取:
- 每個凸超像素是多邊形 → 可直接提取對象輪廓。