第四章 系統設計
4.1.2 Image Library 影像資料結構
在 Image Library 當中,影像的格式分為兩種,分別為二維的 Image 與三維 的 Volume Data,並以未經壓縮的點陣圖 (uncompressed bitmap) 格式存放。
影像由像素組成,一個像素表示一個顯示於任何顯示裝置的一個點(dot)。我 們先介紹在 Image Library 當中,兩種影像資料的表示方式:
a. 二維影像表示法
二維影像稱作 Image 由像素組成。影像中的所有像素以矩陣的方式排列而 成,因此具備了最基本的兩項屬性:寬與高(Width and Height)。令寬為 w,
高為 h 的影像,則具有 w * h 個像素(pixel)。一個像素由 1 至 4 個 byte 表示 (8 至 32 bit),數值越大表示亮度越高。因此該張影像所佔的位元組個數為 w
* h * 一個像素所佔的位元組。表示法的部分請見下圖:
圖 4.1 Image 資料結構表示法 (a) image pointer (b) pointers to rows (c) real image data
假設目前有一張 width * height 的影像,正如圖 4.1 所述,width = height
= 8,每個像素為 8-bit (因此亮度可表示的範圍為 0 至 255)。則此張影
像共 8 * 8 = 64 個像素,佔用 64 個位元組。在 Image Library 當中,該 影像以大小為 8*8 = 64 個元素的一維陣列 (在此每個像素的型態為 unsigned char)儲存。
除此之外,為了便利影像資料的定址(addressing),在此影像範例 中,有一組大小為 8 (即 height)的一維陣列,其中每個元素存放 image 當中各個 row(列)的起始位址,稱為 pointers to rows。亦即,pointers to rows 當中第 k 個元素表示影像中第 k 列的起始位址。而 pointers to rows 此陣列的起始位址的指標記為 image pointer。因此,存取該影像第 r 列 的第 c 個像素,可以 imagePointer[r][c]表示,如圖 4.1。
補充說明:圖 4.1(c)的影像排成方形,實際上是 64 個元素的一維 陣列。另外,imagePointer 是一個指標變數,記錄 pointers to rows 的起 始位址;imagePointer[k]表示 pointers to rows 的第 k 個元素,即影像中 第 k 列的起始位址。另外,二維影像資料結構的記憶體配置法如下,以 C++語法寫成:
unsigned char* imageData = new unsigned char[height * width * bytesPerPixel];
unsigned char** imagePointers = new unsigned char* [height];
for (int row = 0; row < height; row++, imageData += width * bytesPerPixel)
imagePointers[row] = imageData;
Code Listing 4.1 Allocating an image object b. 三維影像表示法
一組三維影像(volume data),由多張二維影像堆疊而成。因此,除了 Image 既有的寬(width)與高(height)以外,另外又多了切面數(在此記為 depth)屬 性。一組切面為 d,寬與高分別為 w 與 h 的三維影像,佔用記憶體的空間則 為 d * w * h * 一個像素的位元組數(bytesPerVoxel)。三維影像的像素記為 voxel,而二維的影像像素則為 pixel。表示法的部分請見下圖:
圖 4.2 Volume 資料結構表示法
圖 4.2 的上半部與圖 4.1 相似,只是在二維影像存放像素的陣列當中每個元 素由 unsigned char 型態以 unsigned char* (即指標)取代,成為這個 volume 各 個 row(列)的起始位址。因此,對於一組由 d 張寬 w 高 h 的影像所堆疊而成 的 volume data 而言,共有 d * h 個 rows(列)與 s 張 slices。
在上圖中,此 volume data 將會有 d * h 個 row pointers 與 s 個 slice pointers。最靠近 volume data 的一維陣列,是 d * h 個 row pointers,頭 h 個 row pointers 屬於第一張 slice (slice 0)的 h 個 row 的起始位址,第 h + 1 至第 2h 個 row pointers 則屬於第二張 slice,以此類推。
而每一張 slice 所屬的 h 個 row pointers,均有一個 slice pointer 指向該 row pointers 的起始位址,因此 slice pointer 應該有 d 個,稱為 slice pointers。而 這些 slice pointers 的起始位址則由 volume pointer 存放。
影像資料的存取方式
若要存取在上圖中第三張 slice (即 slice 2,編號均由 0 開始計算),當中 的位於第三條 row (即編號 2)的第 1 個像素 (即編號 0),則
1. 首先查閱 volume pointer 取得 slice pointers 的起始位址
2. 接著從 volumePointer[2] (即是 slice pointers 的第 3 個元素) 取得該 slice 的 row pointers 之起始位址(此時比照二維影像)
3. 接下來從 volumePointer[2][2](即該 slice 的 row pointers 第 3 個元素) 取得第三條 row 的起始位址。
4. 最後以 volumePointer[2][2][0]取得 volume 當中 slice 2 位於 row 2 的 pixel 0 的數值。
多組 Volume Data 的影像資料
若影像資料為多組的 volume data,例如一組果蠅腦細胞(以共軛焦顯微鏡拍 攝的一組 volume data)隨著時間的變化情形,可能需要以多組的 volume data 記錄,因此這種 volume data 除了 depth 以外,又多了畫面數(nFrames 即 number of frames)屬性。若有一組畫面數為 f,切面數為 d 的 volume data,
則有 f * d 張 slices,因此 slice pointers 共有 f * d 個元素;而在此 volume data 中,亦有 f 個 frame pointers 個別指向各 frames 的 slice pointers 之起始位址。
因此,若要存取 frame i, slice j, row r, column c 的像素內容,則需以 volumePointer[i][j][r][c]存取之。
以上介紹二維與三維影像資料的表示法。在 4.1.2 中,我們將介紹 Image Library 當中,Image/Volume Data 之設計方式。