這還是一篇學習筆記,知識重點還是領會完再敲一遍比較好。
OpenEXR通過RgbaInputFile這個接口讀取RGBA ONLY圖像文件信息,該接口通過dataWindow()方法獲取圖像邊界坐標信息,通過該邊界坐標信息即可計算出圖像的heigth及width。
此時的圖像文件的數據還未以OpenEXR標准的方式存儲,OpenEXR是如何將這些數據標准化的呢?首先定義一個Array2D<Rgba>的模板&pixels,pixels是一個數組的引用,然后通過pixels.resizeErase(height,width)將該數組與圖像數據統一,設定該數組的寬高格式,pixels.resizeErase(height,width)就等於是在內存上為該數組分配了一個額定大小的空間,該數組的寬高與圖像的寬高一致。
下一步就是將pixels的每一個元素與圖像中的每一個像素建立映射關系了。通過file.setFrameBuffer(pixels,1,width),可以為每一個圖像像素建立一個指針,該指針存儲於pixels數組中,並且這些地址是連續的。當我們想訪問圖像數據某一部分時,我們就可以通過訪問這個數組中的指針來完成了。例如:pixels[x][y]就可以獲得一個坐標為(x,y)的像素的指針地址。這樣做既保護了圖像數據的原始性,又提高了訪問的靈活性。OpenEXR的設計確實到位。當然這種設計跟OpenGL也是如出一轍的~
接下來就是通過對file.readPixels(dw.min.y,dw.max.y)來調用並將高度在dw.min.y和dw.max.y之間的像素拷貝到buffer中了。由於數組中記錄的地址是連續的,這樣的設計更適合cpu的多級緩沖特質,這也是圖像能夠被高效處理的一個保證。
以上是OpenEXR的RgbaInputFile接口的最簡單的使用。在實際工作中,我們只想觀看圖像的某一部分,這時候就需要利用OpenEXR成族訪問的特點了。
在Reading an RGBA Image File in Chunks這個單元中給出了這樣的例子:
void readRgba2 (const char fileName[]) { RgbaInputFile file (fileName); Box2i dw = file.dataWindow(); int width = dw.max.x - dw.min.x + 1; int height = dw.max.y - dw.min.y + 1; Array2D<Rgba> pixels (10, width); while (dw.min.y <= dw.max.y) { file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width,1, width); file.readPixels (dw.min.y, min (dw.min.y + 9, dw.max.y));// processPixels (pixels) dw.min.y += 10; } }
下面分析這段代碼:
首先聲明一個RgbaInputFile函數,函數結構體中首先定義一個名為file的RgbaInputFile類用於讀取圖像信息。
然后定義一個名為dw的Box2i對象,該對象通過dataWindow()方法獲取圖像的邊界信息。
通過邊界信息進而計算得出圖像的寬高。
用Array2D<>模板定義了一個應用於Rgba結構體的數組。該數組名為pixels。同時我們注意到,該數組的高度范圍只有10,也就是說該數組只存儲十行圖像數據。這與之前建立一個儲存全部行的數組不一樣。現在建立的數組明顯占用更小的儲存空間,存入到buffer中更具靈活性。也就是說cpu緩存機制並不是那么強大的電腦依然可以很輕松的使用RgbaInputFile接口。
之后一段代碼引入了一個非常精妙的while循環,這個循環很有意思。dw.min.y這個值是可以修改的,在循環句尾有這樣一句:dw.min.y+=10,更新一下while語句中的判斷條件,同時也可以保證pixels在每一次循環中遞歸的為圖像中的十行像素分配地址,不得不感嘆ILM的工程師功力深厚。
以上。