MINC/軟體開發/MINC1-volumeio-程式設計師參考
本文件描述了蒙特利爾神經病學研究所麥康奈爾大腦成像中心 (BIC) 可用的例程庫。它是由 David MacDonald 作為醫學影像軟體測試平臺的一部分開發的,原始碼和相當多的輸入來自該中心的 Peter Neelin、Louis Collins 和其他人。
該庫,被稱為 BIC 體積 IO 庫,包含一組用於讀取和寫入醫學影像資料的體積,以及對許多程式設計任務有用的通用支援例程。大腦成像中心的影像以一種稱為 *MINC* 的格式儲存在磁碟上,它代表 *醫學影像網路 CDF*。有關此格式和用於讀取和寫入 MINC 檔案的 MINC 例程庫的更多資訊,請參見相關文件。
BIC 體積 IO 庫建立在 MINC 庫之上,為大多數一般操作提供對 MINC 檔案的輕鬆訪問,而無需學習太多 MINC 庫的細節,MINC 庫是一個用於處理大多數可想而知的情況的綜合系統。BIC 體積 IO 庫提供了用於內部儲存體積的結構和例程,用於訪問和修改體積。此外,它還提供了例程來操作標籤點和變換,並在大腦成像中心的標準格式下對這些物件執行輸入和輸出。
本文件描述了 BIC 體積 IO 庫的查詢位置、提供的功能以及如何將其整合到使用者的程式中。該庫是用 C 原始碼編寫的,旨在與 C 原始碼連結。它呼叫了另外兩個庫:MINC(BIC 檔案格式庫)和 netcdf(一個可移植檔案格式管理器)。
用於連結的庫是 libvolume_io.a,它位於 /usr/local/lib 中,相關的包含檔案位於 /usr/local/include 下的 volume_io 目錄中。這兩個目錄通常都在編譯器搜尋路徑中。呼叫體積 IO 函式的原始檔必須在頂部包含以下行,以包含相關的型別定義和原型
#include <volume_io/volume_io.h>
為了與 BIC 體積 IO 庫連結,必須指定相關的庫
cc test_volume_io.o -o test_volume_io \
-lvolume_io -lminc -lnetcdf -lm -lmalloc
這兩個庫 minc 和 netcdf 通常位於 /usr/local/lib 中,該目錄自動在搜尋路徑中。-lm 選項包含數學庫,該庫有時由 BIC 體積 IO 庫呼叫。-lmalloc 庫提供的記憶體分配比預設的更快、更健壯。
為了使用此庫,必須習慣某些風格上的細微差別,其中一些是特定於此軟體作者的,而另一些則是隨著軟體歷史的演變而演變的。因此,請務必注意以下與風格相關的注意事項,恕不道歉。
已經採用了全域性變數通常很糟糕的理念。在許多情況下,在函式中使用全域性變數會隱藏函式的行為,因此,最好在引數列表中指定所有與函式相關的 資訊,而不是依賴任何全域性變數。其次,給定函式修改全域性變數會阻止在多執行緒環境中使用此函式(兩個程序可能同時嘗試修改全域性變數)。由於採用了反全域性變數的理念,BIC 體積 IO 庫的使用者通常必須為函式指定許多引數。這似乎是一個很小的代價,作為回報,我們能夠在引數列表中看到控制每個函式行為的所有因素。
此庫的實現者喜歡輸入大量文字,並且通常不喜歡縮寫。因此,BIC 體積 IO 庫中出現的函式和變數名稱可能非常冗長,幾乎到了完全語法正確的句子的程度。通常,您永遠不會看到名稱為 rem_garb() 的函式。相反,函式更可能具有諸如 remove_garbage() 的名稱,並且在許多情況下,甚至 take_garbage_to_curb()。因此,BIC 體積 IO 庫的使用者將不得不鍵入比平時更長的函式和變數名稱,但希望能夠更清楚地瞭解相關的功能。
在整個庫中定義了許多物件,作為不同大小的結構體。由於按值傳遞結構體(將整個結構體複製到函式中)的效率低下,結構體通常透過引用傳遞給函式。因此,總是有可能將無效指標傳遞給期望指向結構體的指標的函式。以下示例說明了使用此類函式的正確和錯誤方法。給定一個結構體和一個初始化它的庫函式,
使用此函式的正確方法
typedef struct
{
int a, b, c, d;
} big_struct;
void initialize( struct big_struct *s )
{
s->a = 1; s->b = 2; s->c = 3; s->d = 4;
}
使用此函式的錯誤方法
int main()
{
big_struct *s;
initialize( s ); /* WRONG */
}
因為變數 s 是一個未初始化的指標。正確的方法是定義一個結構體變數,而不是指向結構體的指標,並將指向結構體的指標傳遞過去
int main()
{
big_struct s;
initialize( &s );
}
或者,可以透過在呼叫 initialize 之前分配 s 指標來更正上面的錯誤示例。
為與 BIC 體積 IO 庫一起使用定義了幾種型別和宏。庫中的所有函式宣告都以 public 或 private 開頭,這指示函式是否可以從其所在的外部檔案訪問。庫使用者只對以 public 開頭的函式感興趣。它們定義如下
#define public
#define private static
定義了用於邏輯值的型別
typedef int BOOLEAN
#define FALSE 0
#define TRUE 1
#define OFF FALSE
#define ON TRUE
其他定義的有用型別包括
typedef double Real;
typedef enum
{ OK, ERROR, INTERNAL_ERROR, END_OF_FILE, QUIT }
Status;
typedef char Smallest_int;
一些對一般程式設計有用的宏包括
N_DIMENSIONS
等於 3 的常量,代表現實世界中的維度數量。
X
等於 0 的常量,用作各種 XYZ 結構體中的索引。
Y
等於 1 的常量,用作各種 XYZ 結構體中的索引。
Z
等於 2 的常量,用作各種 XYZ 結構體中的索引。
SIZEOF_STATIC_ARRAY( array )
返回靜態分配陣列中的元素數量,例如,
{
int size;
int array[] = { 1, 2, 3 };
size = SIZEOF_STATIC_ARRAY( array ); /* == 3 */
}
ROUND( x )
返回最接近於 x 的整數。如果在兩個整數之間,則返回較大的一個。對於負數、零和正數,都能正確執行。
IS_INT( x )
如果實數引數恰好是整數,則返回 TRUE。
FRACTION( x )
返回引數的小數部分。
FLOOR( x )
返回小於或等於引數的最大整數。
CEILING( x )
返回大於或等於引數的最小整數。
ABS( x )
返回整數或實數的絕對值。
MAX( x, y )
返回兩個整數或實數中的最大值。
MAX3( x, y, z )
返回三個整數或實數中的最大值。
MIN( x, y )
返回兩個整數或實數中的最小值。
MIN3( x, y, z )
返回三個整數或實數中的最小值。
INTERPOLATE( alpha, a, b )
返回 a 和 b 之間的插值,其中 alpha 的範圍為零到一。
PI
返回 Π 的值。
DEG_TO_RAD
返回每度弧度數,用於將角度(以度為單位)乘以該值以得到弧度。
RAD_TO_DEG
返回每弧度度數,用於將角度(以弧度為單位)乘以該值以得到度數。
IJ( i, j, nj )
將 ni 行 nj 列二維陣列的索引 [i, j] 轉換為單個索引,基於行優先順序。
IJK( i, j, k, nj, nk )
將 ni 行 nj 列 nk 層三維陣列的索引 [i, j, k] 轉換為單個索引,基於行優先順序。
for_less( i, start, end )
執行一個 for 迴圈,其中 i 從 start 開始,遞增直到大於或等於 end。
等效於 for( i = start; i < end; ++i )。
for_inclusive( i, start, end )
執行一個 for 迴圈,其中 i 從 start 開始,遞增直到大於 end。
等效於 for( i = start; i <= end; ++i )。
GLUE(x,y)
特殊的 C 原始碼宏,用於將兩個不同的識別符號粘合在一起,例如 GLUE(colour,_name) 會得到 colour_name。
GLUE3(x,y,z)
特殊的 C 原始碼宏,用於將三個不同的識別符號粘合在一起,例如 GLUE(a,b,c) 會得到 abc。
程式設計工具
[edit | edit source]提供了一組函式,用於通用、可移植的程式設計。這些函式涵蓋了字串、時間、檔案 I/O 等基本領域。BIC Volume IO 庫的許多部分都引用了程式設計工具,建議 BIC Volume IO 庫的使用者儘可能使用這些函式。以下是所有程式設計工具的列表,按相關領域分組,並按字母順序排列。
字串
[edit | edit source]提供了一些簡單的字串操作技術。字串是任意長的以 NULL 結尾的字元陣列,根據需要進行分配和刪除。型別 STRING 定義為
typedef char *STRING;
基本的字串建立和刪除例程是
public STRING alloc_string(
int length )
public STRING create_string(
STRING initial )
函式 alloc_string 為指定長度的字串分配儲存空間(透過分配 length+1 位元組),但不為字串分配任何值。函式 create_string 建立一個已分配的字串,其值為 initial。如果 initial 是一個 NULL 指標,則建立一個空字串(``)。
public void delete_string(
STRING string )
可以使用此函式刪除與字串關聯的儲存空間。
public int string_length(
STRING string )
返回字串的長度。
public BOOLEAN equal_strings(
STRING str1,
STRING str2 )
如果兩個字串完全相等,則返回 TRUE。
public void replace_string(
STRING *string,
STRING new_string )
一個方便的函式,它刪除 string 引數,並將其重新分配給 new_string。它不會複製 new_string 的值,而只是將 string 設定為指標 new_string。
public void concat_char_to_string(
STRING *string,
char ch )
將一個字元連線到字串的末尾。
public STRING concat_strings(
STRING str1,
STRING str2 )
建立一個字串,它是兩個引數的連線,並返回該字串,而不會改變字串引數。
public void concat_to_string(
STRING *string,
STRING str2 )
用引數 string 和 str2 的連線替換引數 string。
public BOOLEAN is_lower_case(
char ch )
如果字元是小寫字母,則返回 TRUE。
public BOOLEAN is_upper_case(
char ch )
如果字元是大寫字母,則返回 TRUE。
public char get_lower_case(
char ch )
如果字元是大寫字母,則返回字元的小寫版本,否則返回字元本身。
public char get_upper_case(
char ch )
如果字元是小寫字母,則返回字元的大寫版本,否則返回字元本身。
public BOOLEAN string_ends_in(
STRING string,
STRING ending )
確定字串是否以指定的 ending 結尾。例如,傳遞引數 "rainfall" 和 "fall" 會返回 TRUE。
public STRING strip_outer_blanks(
STRING str )
返回一個字串,它是引數 str,去掉了所有前導和尾隨空格。
public void make_string_upper_case(
STRING string )
將字串轉換為全大寫字串。在原地修改字串。
public int find_character(
STRING string,
char ch )
在給定的 string 中搜索給定的字元,返回找到它的索引,如果未找到,則返回 -1。
public BOOLEAN blank_string(
STRING string )
如果字串為空或僅包含空格、製表符和換行符,則返回 true。
通用檔案 I/O
[edit | edit source]雖然可以使用標準的 UNIX 檔案介面(例如 fprintf),但 BIC Volume IO 庫包含一組例程,用於執行所有檔案操作,並且有可能移植到其他作業系統。還有一些其他的優點,包括自動擴充套件 <function>~ </function> 和環境變數。此外,還提供了壓縮檔案的自動解壓縮功能。
public STRING expand_filename(
STRING filename )
在引數 filename 中搜索某些模式,並相應地擴充套件它們,返回擴充套件後的檔名。任何以 ~ 開始,但不包括斜槓 / 的字元序列將被更改為指定的使用者的 home 目錄。任何美元符號 $ 的出現都會導致後面的文字(直到下一個斜槓)被擴充套件為由文字指定的 environment 變數。可以透過在任何 ~ 或 $ 之前放置一個反斜槓 \ 來避免這種擴充套件。在所有以下使用檔名的函式中,都會自動執行檔名擴充套件。
public BOOLEAN file_exists(
STRING filename )
如果檔案存在,則返回 TRUE。
public BOOLEAN check_clobber_file(
STRING filename )
public BOOLEAN check_clobber_file_default_suffix(
STRING filename,
STRING default_suffix )
檢查檔案是否存在,如果存在,則提示使用者是否可以覆蓋它。如果檔案不存在,或如果檔案存在,使用者對提示輸入 `y',則返回 TRUE。該函式的第二種形式在檔名後面追加一個預設字尾,如果檔名還沒有後綴的話。
public void remove_file(
STRING filename )
刪除指定的檔案,這將導致該檔案在所有對它的引用關閉後才會被刪除。
public BOOLEAN filename_extension_matches(
STRING filename,
STRING extension )
如果檔案以給定的副檔名結尾(前面有一個點),則返回 TRUE。例如,<function>filename_extension_matches( "volume.mnc" , "mnc" )</function> 返回 TRUE。正確處理壓縮檔案,例如,傳遞引數 "volume.mnc.Z" 和 "mnc" 返回 TRUE。
public STRING remove_directories_from_filename(
STRING filename )
從檔名中剝離目錄,返回結果。
public STRING extract_directory(
STRING filename )
從檔名中提取目錄,返回結果。
public STRING get_absolute_filename(
STRING filename,
STRING directory )
給定一個檔名和當前目錄,返回一個絕對檔名(以斜槓 / 開頭的檔名)。
public Status open_file(
STRING filename,
IO_types io_type,
File_formats file_format,
FILE **file )
public Status open_file_with_default_suffix(
STRING filename,
STRING default_suffix,
IO_types io_type,
File_formats file_format,
FILE **file )
函式 open_file() 開啟指定的檔案,其中 io_type 必須是 WRITE_FILE 或 READ_FILE 之一,file_format 必須是 ASCII_FORMAT 或 BINARY_FORMAT 之一。如果成功,則將檔案指標傳遞到最後一個引數中,並返回狀態 OK。否則,將返回一個空指標,並返回狀態 ERROR。自動執行檔名擴充套件。第二個函式執行與 open_file 相同的任務,此外還自動新增指定的字尾副檔名,如果需要的話。在輸入時,如果指定的檔案不存在,並且檔案沒有副檔名,則查詢帶有預設副檔名的指定檔案。
public Status close_file(
FILE *file )
關閉檔案,如果成功則返回 OK。
public Status set_file_position(
FILE *file,
long byte_position )
將檔案指標定位到檔案中的指定位置,其中 0 對應於檔案開頭,如果成功則返回 OK。
public Status flush_file(
FILE *file )
重新整理檔案緩衝區中的任何待定輸出,如果成功則返回 OK。
public Status input_character(
FILE *file,
char *ch )
從檔案中輸入一個字元,並將其作為第二個引數傳遞回來。如果字元是檔案結尾字元,則返回狀態 ERROR,否則返回 OK。
public Status unget_character(
FILE *file,
char ch )
將字元放回輸入佇列。
public Status input_nonwhite_character(
FILE *file,
char *ch )
輸入下一個非空白字元,即下一個不是空格、製表符或換行符的字元。
public Status skip_input_until(
FILE *file,
char search_char )
從檔案中輸入字元,直到找到指定的搜尋字元。
public Status input_string(
FILE *file,
STRING *str,
char termination_char )
從檔案中輸入一個字串。從檔案中讀取字串,直到遇到終止字元或換行符。如果字串以換行符結尾,並且終止字元不是換行符,則從檔案中獲取的下一個字元將是換行符。否則,從檔案中獲取的下一個字元將是終止字元之後的字元。
public Status input_quoted_string(
FILE *file,
STRING *str )
從檔案中輸入一個字串,以引號分隔,返回 OK 或 ERROR。成功讀取一個字串後,從檔案中獲取的下一個字元將是結束引號之後的字元。
public Status input_possibly_quoted_string(
FILE *file,
STRING *str )
從檔案中輸入一個字串,以引號或空白符分隔,返回 OK 或 ERROR。成功讀取一個字串後,從檔案中獲取的下一個字元將是結束引號或最後一個非空白字元之後的字元。
public Status input_line(
FILE *file,
STRING line )
將檔案中的字元輸入到引數 line 中,直到遇到下一個換行符。如果找到了換行符,則從檔案中獲取的下一個字元將是換行符之後的字元。換行符不會儲存在字串中。
public Status input_boolean(
FILE *file,
BOOLEAN *b )
輸入下一個非空白字元。如果它是 ``f 或 ``F,則傳遞值 FALSE 回來。如果它是 ``t 或 ``T,則傳遞值 TRUE 回來。否則返回 ERROR。
public Status input_short(
FILE *file,
short *s )
public Status input_unsigned_short(
FILE *file,
unsigned short *s )
public Status input_int(
FILE *file,
int *i )
public Status input_real(
FILE *file,
Real *r )
public Status input_float(
FILE *file,
float *f )
public Status input_double(
FILE *file,
double *d )
從 ascii 檔案中輸入指定型別的值。
public Status input_newline(
FILE *file )
從檔案讀取字元並丟棄字元,直到幷包括下一個換行符。如果找到換行符,則返回 OK;如果先到達檔案末尾,則返回 ERROR。
public Status input_binary_data(
FILE *file,
void *data,
size_t element_size,
int n )
從檔案讀取二進位制格式的資料陣列。該陣列包含 n 個元素,每個元素的大小為 element_size。返回 OK 或 ERROR。
public Status output_character(
FILE *file,
char ch )
將一個字元輸出到檔案,返回 OK 或 ERROR。
public Status output_string(
FILE *file,
STRING str )
將指定字串輸出到檔案,返回 OK 或 ERROR。
public Status output_quoted_string(
FILE *file,
STRING str )
輸出一個引號,指定字串,以及一個結束引號。
public Status output_newline(
FILE *file )
輸出一個換行符,返回 OK 或 ERROR。
public Status output_boolean(
FILE *file,
BOOLEAN b )
如果引數為 TRUE,則輸出一個空格和字母“T”;否則,輸出一個空格和字母“F”。
public Status output_short(
FILE *file,
short s )
public Status output_unsigned_short(
FILE *file,
unsigned short s )
public Status output_int(
FILE *file,
int i )
public Status output_real(
FILE *file,
Real r )
public Status output_float(
FILE *file,
float f )
public Status output_double(
FILE *file,
double d )
輸出一個空格,然後將指定值輸出到 ASCII 檔案。
public Status output_binary_data(
FILE *file,
void *data,
size_t element_size,
int n )
將資料陣列輸出到檔案,以二進位制格式。該陣列包含 n 個元素,每個元素的大小為 element_size。返回 OK 或 ERROR。
public Status io_binary_data(
FILE *file,
IO_types io_flag,
void *data,
size_t element_size,
int n )
根據引數 io_flag 為 READ_FILE 或 WRITE_FILE,輸入或輸出指定二進位制資料。
public Status io_newline(
FILE *file,
IO_types io_flag,
File_formats format )
根據引數 io_flag 為 READ_FILE 或 WRITE_FILE,輸入或輸出 ASCII 換行符。如果 format 引數為 BINARY_FORMAT,則該函式什麼也不做。
public Status io_quoted_string(
FILE *file,
IO_types io_flag,
File_formats format,
STRING str )
如果 format 引數為 ASCII_FORMAT,則根據引數 io_flag 為 READ_FILE 或 WRITE_FILE,輸入或輸出以引號分隔的字串。如果 format 引數為 BINARY_FORMAT,則輸入或輸出以整數開頭表示字串長度的字串。
public Status io_boolean(
FILE *file,
IO_types io_flag,
File_formats format,
BOOLEAN *b )
public Status io_short(
FILE *file,
IO_types io_flag,
File_formats format,
short *short_int )
public Status io_unsigned_short(
FILE *file,
IO_types io_flag,
File_formats format,
unsigned short *unsigned_short )
public Status io_unsigned_char(
FILE *file,
IO_types io_flag,
File_formats format,
unsigned char *c )
public Status io_int(
FILE *file,
IO_types io_flag,
File_formats format,
int *i )
public Status io_real(
FILE *file,
IO_types io_flag,
File_formats format,
Real *r )
public Status io_float(
FILE *file,
IO_types io_flag,
File_formats format,
float *f )
public Status io_double(
FILE *file,
IO_types io_flag,
File_formats format,
double *d )
輸入或輸出指定型別的二進位制或 ASCII 值。
public Status io_ints(
FILE *file,
IO_types io_flag,
File_formats format,
int n,
int *ints[] )
輸入或輸出二進位制或 ASCII 格式的整數陣列。
public Status io_unsigned_chars(
FILE *file,
IO_types io_flag,
File_formats format,
int n,
unsigned char *unsigned_chars[] )
輸入或輸出二進位制或 ASCII 格式的無符號字元陣列。
提供了一組宏,允許輕鬆分配和釋放記憶體,最多可分配 5 維陣列。還執行記憶體分配檢查,以捕獲錯誤,例如釋放未分配的記憶體。此外,記憶體分配會自動跟蹤所有分配的記憶體,以便檢測記憶體洩漏(孤立的記憶體)。
基本宏如下所示
ALLOC( ptr, n_items )
分配 n_items 個正確型別元素,並將結果分配給引數 ptr。
FREE( ptr )
釋放參數 ptr 指向的記憶體。
REALLOC( ptr, n_items )
更改引數 ptr 指向的記憶體大小,使其為 n_items 個元素,在此過程中可能會更改 ptr 的值。
ALLOC_VAR_SIZED_STRUCT( ptr, element_type, n_elements )
分配一個可變大小的結構,該結構必須具有特定形式。結構的最後一個元素必須是一個大小為 1 的陣列,該陣列將構成結構的可變大小部分。引數 element_type 必須是該最後一個元素的型別,引數 n_elements 是除了結構第一部分的記憶體之外,要為該陣列分配的所需元素數量。一個使用示例是
{
struct { int a;
float b;
char data[1];
} *ptr;
ALLOC_VAR_SIZED_STRUCT( ptr, char, 10 );
ptr->a = 1;
ptr->b = 2.5;
ptr->data[0] = 'a';
ptr->data[9] = 'i';
}
ALLOC2D( ptr, n1, n2 )
ALLOC3D( ptr, n1, n2, n3 )
ALLOC4D( ptr, n1, n2, n3, n4 )
ALLOC5D( ptr, n1, n2, n3, n4, n5 )
分配一個大小為 n1 到 n2 等的 2 到 5 維陣列,並將結果儲存在指定的指標 ptr 中。在二維情況下,這僅透過兩次記憶體分配來完成,一次分配 n1 乘以 n2 個元素用於儲存,另一次分配 n1 個指向第一個記憶體區域的指標。一般來說,每個維度都需要一次記憶體分配。
FREE2D( ptr )
FREE3D( ptr )
FREE4D( ptr )
FREE5D( ptr )
釋放與多維陣列關聯的記憶體。
public void set_alloc_checking(
BOOLEAN state )
啟用或停用分配檢查。它通常在程式開始時被呼叫,以提供對分配的雙重檢查。它在每次呼叫之前的分配宏時都會進行額外的分配。如果未呼叫此函式,則可以透過將環境變數 DEBUG_ALLOC 設定為任何內容來開啟分配檢查。
分配檢查檢測三種類型的記憶體程式設計錯誤:釋放未分配的指標,透過檢查從系統 malloc 例程返回的記憶體塊是否與現有記憶體塊重疊,有時檢測到系統記憶體是否已損壞,以及透過記錄所有分配的記憶體並打印出當前分配的記憶體,可以檢測記憶體洩漏。
public void output_alloc_to_file(
STRING filename )
如果啟用了記憶體檢查,則可以使用此函式檢測記憶體洩漏。在程式結束時,程式設計師應該釋放所有已知的記憶體,然後呼叫此函式。任何剩餘的已分配記憶體將被列印到檔案中,指示分配記憶體的檔案和行號。
除了前面描述的基本記憶體分配宏之外,還提供了一組用於處理動態更改大小的陣列的有用宏
SET_ARRAY_SIZE( array, previous_n_elems, new_n_elems,
chunk_size )
此宏透過指定先前分配給陣列的元素數量(從零開始)來增加或減少陣列的大小。chunk_size 引數定義分配的記憶體塊的大小。例如,如果 chunk_size 為 100,則此宏僅在大小更改跨越到 100 的不同倍數時才會重新分配陣列,從而避免每次呼叫時都進行記憶體分配。此記憶體分配粒度規範必須始終一致地指定;如果此宏使用給定變數和塊大小被呼叫,則隨後使用相同變數呼叫此宏必須指定相同的塊大小。另請注意,作為 new_n_elems 傳入的數字必須在下次呼叫此宏時作為 previous_n_elems 傳入。
ADD_ELEMENT_TO_ARRAY( array, n_elems,
elem_to_add, chunk_size )
將引數 elem_to_add 新增到陣列的 n_elems 個索引處,然後遞增 n_elems。引數 chunk_size 指定記憶體分配的粒度。
DELETE_ELEMENT_FROM_ARRAY( array, n_elems, index_to_remove,
chunk_size )
從陣列中刪除 index_to_remove 個元素,減少陣列中的元素數量(n_elems)並減少記憶體分配,如果跨越 chunk_size 的倍數。同樣,chunk_size 必須在涉及給定指標的前面三個宏的所有呼叫中指定為相同。
ADD_ELEMENT_TO_ARRAY_WITH_SIZE( array, n_alloced, n_elems,
elem_to_add, chunk_size )
向陣列新增一個元素(elem_to_add),遞增 n_elems。如果需要,記憶體將按 chunk_size 中指定的數量增加,並且 n_alloced 變數將按此數量遞增。此用法與 ADD_ELEMENT_TO_ARRAY 的用法不同,因為元素數量(n_elems)可以任意減少,而不會導致記憶體被釋放。
為了提供對特定處理任務進度的簡單監控,可以使用一個進度報告模組。當任務正在進行時,進度報告會在行上列印點,表示任務完成的進度。如果任務將花費很長時間(超過 2 分鐘),進度報告會定期列印當前完成的百分比和估計的剩餘時間。一個使用示例,後面跟著函式描述,如下所示
{
int i, n_slices;
progress_struct progress;
n_slices = 100;
initialize_progress_report( &progress, FALSE,
n_slices, "Processing Slices" );
for( i = 0; i < n_slices; ++i )
{
process_slice( i );
update_progress_report( &progress, i + 1 );
}
terminate_progress_report( &progress );
}
public void initialize_progress_report(
progress_struct *progress,
BOOLEAN one_line_only,
int n_steps,
STRING title )
初始化進度報告結構,指定處理中將發生的步驟數量,以及要列印的進度報告標題。在進度報告期間,顯示屏將自動從列印一行點的短作業模式切換到定期列印完成百分比和估計剩餘時間的長作業模式。如果 one_line_only 標誌為 TRUE,則此功能將被停用,並且只會顯示一行點。
public void update_progress_report(
progress_struct *progress,
int current_step )
告訴進度報告模組已完成多少個步驟,並導致更新行上點的顯示或估計剩餘時間。
public void terminate_progress_report(
progress_struct *progress )
終止進度報告。
與使用標準 UNIX 函式 printf 進行例行文字輸出相比,提供了一個外觀相似的模組,該模組允許安裝任意列印輸出函式。例如,這可以用來將輸出映象到日誌檔案,或將文字傳送到 X 視窗。主要變化是使用名為 print 或 print_error 的函式,該函式與標準 printf 函式具有完全相同的引數。
public void print( STRING format, ... )
public void print_error( STRING format, ... )
接受與 printf() 相同的引數,但允許為最終輸出階段安裝使用者輸出函式。
public void set_print_function(
void (*function) ( STRING ) )
public void set_print_error_function(
void (*function) ( STRING )
設定輸出函式,print() 或 print_error 呼叫中的所有文字將被髮送到該函式。預設情況下,沒有列印函式,輸出被髮送到 printf()。
public void push_print_function()
public void push_print_error_function()
臨時將列印或錯誤列印函式設定為標準輸出,並允許使用者設定另一個列印函式,該函式將在相應的 pop 函式被呼叫時消失。
public void pop_print_function()
public void pop_print_error_function()
恢復先前的使用者列印或錯誤列印函式。
提供了一些與時間、日期和 CPU 時間相關的基本實用程式。
public Real current_cpu_seconds( void )
返回當前程序到目前為止使用的 CPU 秒數。
public Real current_realtime_seconds( void )
返回當前程序執行的秒數。
public STRING get_clock_time()
返回表示當前時鐘時間的字串(小時和分鐘),呼叫者負責刪除該字串。
public STRING get_date()
返回表示當前日期的字串,呼叫者負責刪除該字串。
public STRING format_time(
STRING format,
Real seconds )
接受以秒為單位的時間和具有格式元件的格式字串,例如“%g %s”,並將時間以毫秒、秒、分鐘、天等適當單位列印到字串中。字串被返回,呼叫程式負責刪除該字串。
public void print_time(
STRING format,
Real seconds )
與 format_time 相同,但使用結果呼叫 print()。
public void sleep_program(
Real seconds )
將程式掛起指定的秒數。請注意,在大多數系統上,這隻會執行到某個特定時間增量的最接近倍數。在 Silicon Graphics 系統上,這將是到最接近的百分之一秒。
在這個軟體開發的實驗室中,處理的任務涉及到多維資料體,例如由磁共振和PET掃描器產生的資料。因此,提供了一套廣泛的例程來表示體積,以及以MINC格式讀取和寫入體積。
體積的基本型別是Volume,它實際上是指向已分配結構的指標,該結構包含有關體積型別、維度數量、體素值等的所有資訊。為了使用體積結構,必須首先建立體積,然後設定體積的大小,然後分配體素值的大陣列。或者,可以透過呼叫相應的函式來讀取MINC檔案並建立體積,從而自動建立體積。
一個體積與一定數量的維度相關聯,這些維度必須在1到5之間,但通常為3。體積被認為是任何一種型別的多維陣列,包括所有大小的整數和實數型別。即使一個體積可能儲存在例如1位元組型別中,其值為0到255,但有一個實際值範圍,它提供了從體素值到任何任意實數範圍的對映。這樣,實際範圍可以是任何有效的實數區間,並且與特定儲存型別無關。
由於大多數體積將透過從MINC檔案讀取而建立,因此將首先介紹這種方法,然後描述如何從頭開始建立體積。最後,將介紹更高階應用程式的MINC輸入和輸出的較低級別。
public Status input_volume(
STRING filename,
int n_dimensions,
STRING dim_names[],
nc_type volume_nc_data_type,
BOOLEAN volume_signed_flag,
Real volume_voxel_min,
Real volume_voxel_max,
BOOLEAN create_volume_flag,
Volume *volume,
minc_input_options *options )
此例程從MINC檔案讀取一個體積,首先在create_volume_flag指定為TRUE(通常情況)的情況下建立體積。維度數量是體積所需的維度數量。如果此數量小於檔案中的維度數量,則只讀取與該維度數量相對應檔案的第一個部分。如果指定的維度數量小於1,則使用檔案中的維度數量。引數dim_names指定體積在體積變數中儲存的順序。對於儲存體積中的每個維度,都有一個相應的名稱,該名稱是MIxspace、MIyspace、MIzspace、ANY_SPATIAL_DIMENSION或空字串之一。這些與檔案中的對應維度相匹配,並且體積陣列的維度排序在輸入時重新排序。因此,如果使用者希望以X-Z-Y順序表示體積,則作為dim_names陣列傳遞的值應為三個字串MIxspace、MIzspace和MIyspace。此排序選擇很重要,因為它定義了隨後對體素索引的任何引用的順序。
四個引數volume_nc_data_type到volume_voxel_max可用於指定體積變數中所需的儲存型別,這些型別會從檔案中的儲存型別自動轉換。volume_nc_data_type是MI_ORIGINAL_TYPE、NC_BYTE、NC_SHORT、NC_LONG、NC_FLOAT或NC_DOUBLE之一。對於整數型別,如果需要有符號型別,則volume_signed_flag為TRUE,否則為FALSE。volume_voxel_min和volume_voxel_max指定有效體素值的範圍,並且通常設定為相等以指示使用型別的完整範圍,例如對於無符號NC_BYTE,範圍為0到255.0。如果傳遞MI_ORIGINAL_TYPE,則使用檔案中的型別、符號和體素範圍。
如果create_volume_flag為TRUE(通常情況),則會自動建立體積。否則,假定體積已經存在,並且只有在當前大小與檔案導致的新大小不同時才會重新建立,從而減少讀取多個檔案時的記憶體分配量。
options引數指定輸入過程的一些特殊選項,通常只傳遞一個NULL指標,表示應使用預設選項。目前,可能的選項是
public void set_default_minc_input_options(
minc_input_options *options )
將預設選項填充到options結構中,該結構隨後將傳遞給input_volume()。
public void set_minc_input_promote_invalid_to_min_flag(
minc_input_options *options,
BOOLEAN flag )
預設情況下,任何超出有效體素值範圍的體素值都會提升到最小有效體素值。如果將此flag設定為FALSE,則會停用此提升。
public void set_minc_input_vector_to_scalar_flag(
minc_input_options *options,
BOOLEAN flag )
預設情況下,任何包含型別為向量的維度的體積(例如RGB顏色體積)都會透過對每個向量的分量進行平均來轉換為標量體積。可以透過將flag傳遞為FALSE來停用此功能。
public void set_minc_input_vector_to_colour_flag(
minc_input_options *options,
BOOLEAN flag )
public void set_minc_input_colour_dimension_size(
minc_input_options *options,
int size )
public void set_minc_input_colour_indices(
minc_input_options *options,
int indices[4] )
預設情況下,任何包含型別為向量的維度的體積(例如RGB顏色體積)都會透過對每個向量的分量進行平均來轉換為標量體積。如果將此選項設定為true,則任何具有set_minc_input_colour_dimension_size(預設值為3)所指定的元件數量的向量體積將使用set_minc_input_colour_indices(預設值為0、1、2)所指定的索引轉換為顏色體積。
public void set_minc_input_user_real_range(
minc_input_options *options,
double minimum,
double maximum )
預設情況下,讀取到整數型別體積中的檔案將進行縮放,以便實際範圍是輸入檔案中資料的完整範圍。使用者可以透過使用適當的實際最小值和最大值呼叫此函式來定義另一個範圍。對於浮點型別體積,設定範圍將更改體積的實際範圍,但不會更改體積中的實際值。如果最小值大於或等於最大值,則恢復預設行為。
除了使用input_volume()函式一次性輸入體積外,還有另一種方法可以允許在體積輸入與其他處理任務之間穿插。以下是input_volume()函式為了輸入體積而呼叫的例程集。
public Status start_volume_input(
STRING filename,
int n_dimensions,
STRING dim_names[],
nc_type volume_nc_data_type,
BOOLEAN volume_signed_flag,
Real volume_voxel_min,
Real volume_voxel_max,
BOOLEAN create_volume_flag,
Volume *volume,
minc_input_options *options,
volume_input_struct *input_info )
這將初始化一個檔名,以便增量輸入體積。此函式的引數與input_volume()函式的引數相同,此外還添加了input_info結構,該結構被初始化以供在剩餘函式中使用。如果需要,將建立體積,但不分配,並且不會讀取體積的任何部分。
public void delete_volume_input(
volume_input_struct *input_info )
關閉檔案並終止體積的輸入。透過呼叫start_volume_input()函式,然後呼叫delete_volume_input()函式,可以建立一個體積,該體積具有有關檔案體積的所有資訊,但未分配體素。
public void cancel_volume_input(
Volume volume,
volume_input_struct *input_info )
關閉檔案,終止體積的輸入,並刪除體積。只需呼叫delete_volume_input(),然後呼叫delete_volume()。
public BOOLEAN input_more_of_volume(
Volume volume,
volume_input_struct *input_info,
Real *fraction_done )
輸入體積的一小部分,計算結果既有效率,又不會太大,以至於不能在呼叫此函式時穿插其他處理的呼叫。如果還有更多工作要做,則返回TRUE,即應再次呼叫此函式。已完成的部分作為0到1之間的數字傳遞回來。
public Minc_file get_volume_input_minc_file(
volume_input_struct *volume_input )
將體積輸入中的Minc_file結構傳遞回來,以允許在需要此型別例程中使用此結構。
體積輸出可以透過兩種例程之一完成,具體取決於體積是否被視為另一個體積的修改版本或獨立體積。
public Status output_volume(
STRING filename,
nc_type file_nc_data_type,
BOOLEAN file_signed_flag,
Real file_voxel_min,
Real file_voxel_max,
Volume volume,
STRING history,
minc_output_options *options )
將指定的體積輸出到指定的檔名。如果引數file_nc_data_type為MI_ORIGINAL_TYPE,則體積將以體積變數中的相同型別儲存在MINC檔案中。否則,四個引數file_nc_data_type、file_signed_flag、file_voxel_min和file_voxel_max指定在檔案中儲存體積的型別和有效體素範圍。如果history引數非空,則它表示體積的描述,並將放置在MINC體積中。如果options引數為NULL,則將使用預設選項。否則,可以透過此引數設定一些特定輸出選項,以及以下函式
public void set_default_minc_output_options(
minc_output_options *options )
將options結構設定為預設值。然後,使用者可以覆蓋預設值並將結構傳遞給output_volume()函式。目前,只有一個輸出選項
public void delete_minc_output_options(
minc_output_options *options )
刪除options資料。
public void set_minc_output_dimensions_order(
minc_output_options *options,
int n_dimensions,
STRING dimension_names[] )
定義檔案的輸出順序。每個維度名稱字串必須在體積中具有匹配的維度名稱,這定義了輸出檔案中維度的順序。例如,可能以<function>(x, y, z)</function>順序輸入體積。要以(z, y, x)順序輸出它,請將dimension_names設定為三個字串MIzspace、MIyspace和MIxspace。
public void set_minc_output_real_range(
minc_output_options *options,
Real real_min,
Real real_max )
定義檔案中將出現的影像範圍。預設情況下,不指定任何內容,並且output_volume使用卷的實際最小值和最大值。若要設定卷的實際範圍,請參閱set_volume_real_range()的相關文件。
如果卷是當前儲存在檔案中的另一個卷的修改,那麼使用以下函式輸出卷更為合適
public Status output_modified_volume(
STRING filename,
nc_type file_nc_data_type,
BOOLEAN file_signed_flag,
Real file_voxel_min,
Real file_voxel_max,
Volume volume,
STRING original_filename,
STRING history,
minc_output_options *options )
此函式與其他卷輸出方法(output_volume())之間的唯一區別在於,此函式將輔助資料從原始檔案(original_filename)複製到新檔案。此輔助資料包括患者姓名和其他掃描資料等專案,並且不會讀入卷,因此將它正確傳遞到新的 MINC 檔案的唯一方法是使用此函式。
建立和分配卷後,有很多函式用於操作卷。請注意,與每個卷相關聯的是一個有效的體素範圍,該範圍指示實際儲存在卷中的值的範圍,例如,0 到 200 是無符號位元組卷的一種可能的範圍。還有一個第二個範圍,即real範圍,它將有效體素範圍對映到任意實際範圍,例如,有效體素的 0 到 200 可以對映到real範圍內的 -1.5 到 1.5。在處理卷時,通常會對real範圍感興趣。
public Real get_volume_voxel_value(
Volume volume,
int v0,
int v1,
int v2,
int v3,
int v4 )
給定一個卷和一個到五個體素索引(取決於卷的維數),返回相應的體素值。例如,如果卷是三維的,那麼最後兩個引數將被忽略。
value = convert_voxel_to_value( volume, voxel );
給定一個卷和一個體素值,將它轉換為實際範圍內的值,並返回它。
voxel = convert_value_to_voxel( volume, value )
給定一個卷和一個實際值,將它轉換為有效體素範圍內的體素值,並返回它。
public Real get_volume_real_value(
Volume volume,
int v0,
int v1,
int v2,
int v3,
int v4 )
給定一個卷和一個到五個體素索引(取決於卷的維數),返回相應的實際值。例如,如果卷是三維的,那麼最後兩個引數將被忽略。
public void set_volume_voxel_value(
Volume volume,
int v0,
int v1,
int v2,
int v3,
int v4,
Real voxel )
給定一個卷、一個到五個體素索引和一個voxel值,將此值分配給卷中相應的體素。請注意,不會執行從有效實際範圍到有效體素範圍的轉換,因此使用者可能需要首先使用convert_value_to_voxel函式或使用set_volume_real_value函式。
public void set_volume_real_value(
Volume volume,
int v0,
int v1,
int v2,
int v3,
int v4,
Real value )
給定一個卷、一個到五個體素索引和一個value,在轉換為體素值後,將此值分配給卷中相應的體素。
public void delete_volume(
Volume volume )
刪除與卷相關聯的所有記憶體。
public nc_type get_volume_nc_data_type(
Volume volume,
BOOLEAN *signed_flag )
返回卷的儲存型別(例如,NC_SHORT),並傳遞迴一個指示它是有符號還是無符號的資訊。
public int get_volume_n_dimensions(
Volume volume )
返回卷的維數。
public void get_volume_sizes(
Volume volume,
int sizes[] )
將每個維度的尺寸儲存在陣列sizes中。這是每個維度的體素數。陣列sizes必須至少與卷的維數一樣大。
public void get_volume_separations(
Volume volume,
Real separations[] )
將每個維度的切片間距儲存在陣列separations中。陣列separations必須至少與卷的維數一樣大。
public Real get_volume_voxel_min(
Volume volume )
public Real get_volume_voxel_max(
Volume volume )
public void get_volume_voxel_range(
Volume volume,
Real *voxel_min,
Real *voxel_max )
前兩個函式返回允許的最小或最大體素值。第三個函式傳遞迴這兩個值。
public Real get_volume_real_min(
Volume volume )
public Real get_volume_real_max(
Volume volume )
public void get_volume_real_range(
Volume volume,
Real *min_value,
Real *max_value )
前兩個函式返回最小或最大實際值。第三個函式傳遞迴這兩個值。對映到此實際空間將最小voxel值線性對映到最小real值,並將最大voxel值對映到最大real值。
public STRING *get_volume_dimension_names(
Volume volume )
返回指向每個維度名稱列表的指標。此記憶體必須由呼叫函式使用以下函式釋放。
public void delete_dimension_names(
Volume volume,
STRING dimension_names[] )
釋放為維度名稱分配的記憶體。
public void set_rgb_volume_flag(
Volume volume,
BOOLEAN flag )
設定指示卷是否為紅-綠-藍顏色的卷標誌。只有資料型別為無符號長的卷才能是 rgb 卷。
public BOOLEAN is_an_rgb_volume(
Volume volume )
如果卷是紅-綠-藍顏色卷,則返回TRUE,因為可以在卷輸入時建立此卷。
一個卷有兩個座標系。體素座標系只是卷的 n 維索引座標系。例如,體素座標 (0.0, 0.0, 0.0) 對應於三維卷中第一個體素的中心。體素座標 ( 99.0, 0.0, 0.0 ) 對應於大小為 ( 100, 200, 150 ) 的三維卷的第一個方向中的最後一個體素的中心。第二個座標系是任意的三維座標系,通常稱為世界座標系,通常是 Talairach 座標系。以下函式提供在這兩個座標系之間進行轉換的方法
public void convert_voxel_to_world(
Volume volume,
Real voxel[],
Real *x_world,
Real *y_world,
Real *z_world )
給定一個卷和一個實值體素索引,傳遞迴相應的世界座標。
public void convert_3D_voxel_to_world(
Volume volume,
Real voxel1,
Real voxel2,
Real voxel3,
Real *x_world,
Real *y_world,
Real *z_world )
與convert_voxel_to_world相同,只是它僅適用於三維卷。
public void convert_world_to_voxel(
Volume volume,
Real x_world,
Real y_world,
Real z_world,
Real voxel[] )
將世界座標轉換為體素。為了將這些體素座標用作整數索引(例如,作為GET_VALUE宏的引數),引數voxel的每個分量必須首先四捨五入到最接近的整數。
public void convert_3D_world_to_voxel(
Volume volume,
Real x_world,
Real y_world,
Real z_world,
Real *voxel1,
Real *voxel2,
Real *voxel3 )
與convert_world_to_voxel相同,只是它僅適用於三維卷。
public void convert_voxel_vector_to_world(
Volume volume,
Real voxel_vector[],
Real *x_world,
Real *y_world,
Real *z_world )
public void convert_world_vector_to_voxel(
Volume volume,
Real x_world,
Real y_world,
Real z_world,
Real voxel_vector[] )
這兩個函式在體素空間和世界空間之間轉換向量。這是透過將點 (0,0,0) 轉換為另一個空間來完成的,此外,將向量視為點並將其轉換為另一個空間,並將這兩個結果之間的向量傳遞迴。
public void convert_voxel_normal_vector_to_world(
Volume volume,
Real voxel1,
Real voxel2,
Real voxel3,
Real *x_world,
Real *y_world,
Real *z_world )
將被假定為世界座標系中的表面法線的向量轉換。
除了訪問特定體素值的例程之外,還可以使用最近鄰、線性或三次插值對捲進行插值,這些插值在體素空間或世界空間中指定。
public int evaluate_volume(
Volume volume,
Real voxel[],
BOOLEAN interpolating_dimensions[],
int degrees_continuity,
BOOLEAN use_linear_at_edge,
Real outside_value,
Real values[],
Real **first_deriv,
Real ***second_deriv )
在指定的體素處對捲進行插值,其中degrees_continuity的值分別為 -1、0 或 2,表示最近鄰、線性或三次插值。如果use_linear_at_edge為真,則任何三次插值都將降級為卷邊緣附近的線性插值。此選項僅在特殊情況下需要。引數outside_value是卷外部任何點的值。引數interpolating_dimensions指示哪些維度正在進行插值,通常是NULL指標,表示所有維度都在進行插值。插值後的值將放置在 values 陣列中。值的個數等於未插值維度的值的個數,如果所有維度都在進行插值,則為 1。如果導數引數不為空,則生成的導數將放置在相應的位置。first_deriv是一個大小為 values 個數乘以插值維度個數的二維陣列。second_deriv是一個大小為 values 個數乘以插值維度個數乘以插值維度個數的三維陣列。
public void evaluate_volume_in_world(
Volume volume,
Real x,
Real y,
Real z,
int degrees_continuity,
BOOLEAN use_linear_at_edge,
Real outside_value,
Real values[],
Real deriv_x[],
Real deriv_y[],
Real deriv_z[],
Real deriv_xx[],
Real deriv_xy[],
Real deriv_xz[],
Real deriv_yy[],
Real deriv_yz[],
Real deriv_zz[] )
在指定的世界位置處對捲進行插值,其中degrees_continuity的值分別為 -1、0 或 2,表示最近鄰、線性或三次插值。如果use_linear_at_edge為真,則任何三次插值都將降級為卷邊緣附近的線性插值。此選項僅在特殊情況下需要。引數outside_value是卷外部任何點的值。插值後的值將放置在 values 陣列中。值的個數等於非空間維度的值的個數,如果所有維度都是空間維度,則為 1。如果導數引數不為空,則生成的導數將放置在相應的位置。
public void set_volume_interpolation_tolerance(
Real tolerance )
出於速度考慮,如果在體素中心或其附近評估卷,則不執行插值,而是返回體素值。容差定義了此操作發生的距離與體素中心之間的距離,預設值為 0。請注意,如果需要導數並且指定的連續性程度為 0 或更大,則即使在指定的體素容差範圍內,也會執行插值。
在某些情況下,希望以與從檔案讀取不同的方式建立卷。以下函式提供從頭開始建立卷或建立與現有卷相似的卷的方法。
public Volume create_volume(
int n_dimensions,
STRING dimension_names[],
nc_type nc_data_type,
BOOLEAN signed_flag,
Real voxel_min,
Real voxel_max )
建立並返回給定型別(例如,NC_BYTE,signed_flag 等於FALSE)和給定有效體素範圍的卷。dimension_names用於描述卷的每個維度,目前僅在將卷寫入檔案時使用。
public void set_volume_voxel_range(
Volume volume,
Real voxel_min,
Real voxel_max )
public void set_volume_real_range(
Volume volume,
Real real_min,
Real real_max )
建立卷後,可以使用這些函式隨後更改有效體素範圍或有效實際範圍。
public void set_volume_sizes(
Volume volume,
int sizes[] )
設定卷的尺寸,即每個維度的體素數。請注意,這必須在呼叫函式alloc_volume_data分配體素之前完成。
public void alloc_volume_data(
Volume volume )
建立卷並設定其大小後,此函式將為體素分配記憶體。請注意,體素值不會被初始化,使用者必須用所需的值填充卷。
與每個卷相關聯的是從voxel空間到world空間的變換。有幾種方法可以定義這種變換。最簡單的方法是直接指定它
public void set_voxel_to_world_transform(
Volume volume,
General_transform *transform )
將給定變換分配給卷。
public General_transform *get_voxel_to_world_transform(
Volume volume )
返回指向卷的體素到世界變換的指標。
public void set_volume_separations(
Volume volume,
Real separations[] )
設定每個卷維度的體素間距。請注意,這會導致體素到世界變換相應地更新。
public void set_volume_translation(
Volume volume,
Real voxel[],
Real world_space_voxel_maps_to[] )
設定體素到世界變換的平移部分。指定一個體素座標(voxel),以及希望此體素對映到的實際世界位置(world_space_voxel_maps_to)。體素到世界變換將更新以提供此對映。
public void set_volume_direction_cosine(
Volume volume,
int dimension,
Real dir[] )
設定特定體素維度的真實世界軸。例如,如果dimension為 1,而dir為 (0.0, 1.0, 1.0),則體積第二維度的體素將對映到真實世界軸 (0.0, 1.0, 1.0),該軸已歸一化為單位長度,然後按第二體積維度的體積間距進行縮放。
public void get_volume_direction_cosine(
Volume volume,
int dimension,
Real dir[] )
返回特定體素維度的真實世界軸。請注意,dimension必須是體積中的空間維度。
public void set_volume_space_name(
Volume volume,
STRING name )
使用字串名稱設定體積的座標系型別。這可以是任何字串,但 MINC 提供了一組定義的常量:MI_NATIVE、MI_TALAIRACH 和 MI_CALLOSAL。
public STRING get_volume_space_name(
Volume volume )
返回體積的座標系型別的副本,以字串名稱的形式表示。呼叫函式在完成使用後必須釋放此字串。
建立體積的另一種方法是簡單地從現有體積中複製整個體積定義。
public Volume copy_volume_definition(
Volume existing_volume,
nc_type nc_data_type,
BOOLEAN signed_flag,
Real voxel_min,
Real voxel_max )
public Volume copy_volume_definition_no_alloc(
Volume volume,
nc_type nc_data_type,
BOOLEAN signed_flag,
Real voxel_min,
Real voxel_max )
這兩個函式都建立並返回一個新體積,該體積與現有體積具有相同的定義(大小、體素到世界空間變換等)。如果引數nc_data_type不是MI_ORIGINAL_TYPE,則新體積的儲存型別將與原始體積不同,並由nc_data_type、signed_flag、voxel_min 和 voxel_max 指定。在第一個函式中,體素值已分配但未初始化。在第二個函式中,它們未分配。
public Volume copy_volume(
Volume volume )
建立體積的精確副本。
為了有效地處理對虛擬記憶體而言過大的體積,已經實現了一個簡單的快取方案。磁碟檔案按需讀取和寫入,以提供將大型體積完全駐留在記憶體中的外觀。之前描述的所有體積例程都透明地支援此功能,但有一些例程用於配置體積快取。
public void set_n_bytes_cache_threshold(
int threshold )
設定體積快取的閾值位元組數。如果建立的體積大於此值(無論顯式建立還是從檔案輸入建立),則該體積將在內部由快取方案表示。如果未呼叫此函式,則預設值為 80 兆位元組,或環境變數VOLUME_CACHE_THRESHOLD的值(如果存在)。閾值為零將導致所有體積被快取。閾值小於零將導致沒有體積被快取。
typedef enum { SLICE_ACCESS, RANDOM_VOLUME_ACCESS }
Cache_block_size_hints;
public void set_cache_block_sizes_hint(
Cache_block_size_hints hint )
public void set_default_cache_block_sizes(
int block_sizes[] )
當在快取的體積中訪問體素時,將根據需要從磁碟讀取或寫入包含該體素的相應塊。這兩個函式控制塊的預設大小,因此控制快速訪問相鄰體素(使用較大的塊大小)和快速訪問任意分佈的體素(使用較小的塊大小)之間的權衡。函式set_cache_block_sizes_hint 表示未來建立的體積的預設塊大小應基於這樣的假設來計算,即應用程式將主要以逐片的方式訪問體積體素(SLICE_ACCESS)或以不可預測的順序訪問體素(RANDOM_VOLUME_ACCESS)。第二個函式set_default_cache_block_sizes 提供了一種替代方案,其中顯式設定了預設塊大小。對任一函式的呼叫都會覆蓋之前對另一個函式的任何呼叫。如果未呼叫這兩個函式中的任何一個,則預設值為每個維度的塊大小為 8 個體素,或環境變數VOLUME_CACHE_BLOCK_SIZE指定的值。這些函式隻影響之後建立的體積。要更改給定體積的值,可以使用以下函式
public void set_volume_cache_block_sizes(
Volume volume,
int block_sizes[] )
設定給定體積的快取塊大小。由於此函式會導致快取完全重新整理,因此要更改塊大小,可能會在後續體素訪問過程中造成暫時速度損失,這些訪問會導致快取從檔案讀取塊。
public void set_default_max_bytes_in_cache(
int n_bytes )
設定每個體積允許在快取中使用的預設最大位元組數。由於有更大的機會在快取中找到特定體素,因此較高的數字可能會提供更快的訪問速度,因此此值應儘可能大,前提是考慮到可用的虛擬記憶體量。如果未呼叫此函式,則預設值為 80 兆位元組,或環境變數VOLUME_CACHE_SIZE的值(如果存在)。設定值為 0 將導致快取的體積在其快取中只有一個塊。此函式隻影響之後建立的體積。要更改特定體積的此值,可以使用以下函式
public void set_volume_cache_size(
Volume volume,
int max_memory_bytes )
設定特定體積允許在快取中使用的最大位元組數。呼叫此函式將重新整理快取,以便重新分配資料結構以反映新的大小。與呼叫函式set_volume_cache_block_sizes 一樣,訪問畫素時可能會出現暫時的速度損失。
public void set_cache_output_volume_parameters(
Volume volume,
STRING filename,
nc_type file_nc_data_type,
BOOLEAN file_signed_flag,
Real file_voxel_min,
Real file_voxel_max,
STRING original_filename,
STRING history,
minc_output_options *options )
當修改快取的體積時,將建立一個臨時檔案來儲存體素值。當刪除體積時,此檔案也將被刪除。當輸出快取的體積時,臨時檔案將被複制到輸出檔案,這會導致同時存在體積的兩個副本,這可能會對磁碟儲存造成不可接受的需求,尤其是對於大型體積而言。為避免這種情況,應用程式可以指定一個檔名來放置體素值,這將覆蓋使用臨時檔案。當刪除體積時,此檔案將被關閉並保留在磁碟上,從而無需應用程式輸出體積。
如果應用程式隨後呼叫output_volume() 將此體積輸出到與由此函式設定的檔名相同的檔案,則輸出請求將被忽略,因為該體積已經存在於此檔案中。基本上,程式設計師應使用與最終呼叫output_volume() 時傳遞的引數相同的引數呼叫set_cache_output_volume_parameters()。如果體積是快取的體積,則輸出檔案將在設定體積體素時立即建立,並且隨後對output_volume() 的呼叫不會重新建立檔案,而只是將快取緩衝區重新整理,使檔案完全更新。如果體積不是快取的體積,則對set_cache_output_volume_parameters() 的呼叫將被忽略,而隨後對output_volume() 的呼叫將按照指定的方式建立檔案。請注意,在呼叫此函式時,重要的是在退出程式之前刪除體積,以便快取的體積可以重新整理其緩衝區並關閉檔案,否則,對體積的最新更改將不會寫入檔案。
這裡介紹了讀取、寫入和操作體積的示例。
一個完整的程式,用於讀取 MINC 體積,將所有大於 100.0 的值更改為 100.0,然後將結果寫入一個新檔案。
#include <volume_io.h>
/* ------------------------------------------------------------------
@COPYRIGHT :
Copyright 1993,1994,1995 David MacDonald,
McConnell Brain Imaging Centre,
Montreal Neurological Institute, McGill University.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies. The author and
McGill University make no representations about the
suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
------------------------------------------------------------------ */
int main(
int argc,
char *argv[] )
{
int v1, v2, v3, sizes[MAX_DIMENSIONS];
Real value;
Volume volume;
/*--- input the volume */
if( input_volume( "volume.mnc", 3, NULL, MI_ORIGINAL_TYPE, FALSE,
0.0, 0.0, TRUE, &volume,
(minc_input_options *) NULL ) != OK )
return( 1 );
get_volume_sizes( volume, sizes );
/*--- change all values over 100 to 100 */
for( v1 = 0; v1 < sizes[0]; ++v1 ) {
for( v2 = 0; v2 < sizes[1]; ++v2 ) {
for( v3 = 0; v3 < sizes[2]; ++v3 ) {
value = get_volume_real_value( volume, v1, v2, v3,
0, 0 );
if( value > 100.0 ) {
set_volume_real_value( volume, v1, v2, v3,
0, 0, 100.0 );
}
}
}
}
/*--- output the modified volume */
if( output_modified_volume( "output.mnc", MI_ORIGINAL_TYPE,
FALSE, 0.0, 0.0, volume, "volume.mnc",
"Modified by clamping to 100",
(minc_output_options *) NULL ) != OK )
return( 1 );
return( 0 );
}
之前描述的input_volume 函式旨在為大多數應用程式提供一個簡單的單函式介面,用於讀取體積。但是,應用程式有時可能不想一次讀取整個體積,或者可能需要將輸入檔案分解成多個體積,例如,3D 體積的切片。可以使用以下函式來實現這一點。
public Minc_file initialize_minc_input(
STRING filename,
Volume volume,
minc_input_options *options )
此函式開啟一個 MINC 檔案以輸入到指定的體積。檔案中的維度數量必須大於或等於體積中的維度數量,並且體積中的每個維度名稱都必須在檔案中具有匹配的維度名稱。將返回一個檔案控制代碼,用於以下例程中。
public Minc_file initialize_minc_input_from_minc_id(
int minc_id,
Volume volume,
minc_input_options *options )
此函式執行與initialize_minc_input 相同的任務,只是它接受一個先前開啟的 MINC 檔案作為引數,而不是檔名。
public int get_minc_file_id(
Minc_file file )
返回檔案的 MINC ID,該控制代碼可用於對檔案執行 MINC 函式。
public int get_n_input_volumes(
Minc_file file )
確定開啟的 MINC 檔案中的體積總數。例如,如果檔案包含大小為 100 x 200 x 300 的 x、y、z 資料,並且該檔案已使用二維 x-z 體積開啟,則返回的體積數將為 200,即 y 切片的數量。
public BOOLEAN input_more_minc_file(
Minc_file file,
Real *fraction_done )
將 MINC 檔案的一部分讀取到initialize_minc_input 中指定的體積。必須呼叫此函式,直到它返回 FALSE,此時體積已完全讀入。要讀取檔案中下一個體積(如果有),必須呼叫以下函式。
public BOOLEAN advance_input_volume(
Minc_file file )
將輸入檔案推進到下一個體積。
public BOOLEAN reset_input_volume(
Minc_file file )
將輸入重置為檔案中的第一個體積的開頭。
public Status close_minc_input(
Minc_file file )
關閉 MINC 檔案。
與多體積輸入類似,還有一些例程用於透過子體積將輸出提供給檔案。
public Minc_file initialize_minc_output(
STRING filename,
int n_dimensions,
STRING dim_names[],
int sizes[],
nc_type file_nc_data_type,
BOOLEAN file_signed_flag,
Real file_voxel_min,
Real file_voxel_max,
General_transform *voxel_to_world_transform,
Volume volume,
minc_output_options *options )
開啟一個 MINC 檔案以供建立。引數指定每個維度的數量和名稱,以及每個維度的尺寸。檔案的型別由四個引數控制:file_nc_data_type、file_signed_flag、file_voxel_min 和 file_voxel_max。到世界座標的變換由voxel_to_world_transform 引數指定。volume 附加到檔案以供輸出。體積的維度不能超過檔案中的維度,並且每個維度的名稱必須與檔案中的一個維度匹配。options 與output_volume 函式中指定的一致。請注意,與output_volume 函式不同,如果未指定影像最小值和最大值,則輸出檔案將為每個影像具有單獨的影像最小值和最大值。
public int get_minc_file_id(
Minc_file file )
返回檔案的 MINC ID,該控制代碼可用於對檔案執行 MINC 函式。
public Status copy_auxiliary_data_from_minc_file(
Minc_file file,
STRING filename,
STRING history_string )
將filename 引數中指定的 MINC 檔案中的輔助資訊複製到開啟的 MINC file 中。
public Status output_minc_volume(
Minc_file file )
將附加的體積輸出到當前檔案位置的 MINC 檔案。檔案位置將根據體積的大小前進。
public Status output_volume_to_minc_file_position(
Minc_file file,
Volume volume,
int volume_count[],
long file_start[] )
更通用的例程,用於將指定的體積輸出到指定位置的 MINC 檔案。由於此例程不會更新檔案位置,因此它不會干擾使用函式output_minc_volume 進行的正常體積輸出。由volume_count 定義的體積超立方體將從給定的檔案位置開始寫入檔案。
public Status close_minc_output(
Minc_file file )
關閉 MINC 檔案。
標籤點是三維點集,用於標記感興趣的位置。通常,這些點來自手動定位多個體積中的對應位置,以提供這些體積之間的對映。標籤點儲存在麥康奈爾腦成像中心設計的 ASCII 格式中,檔名約定以.tag結尾。一個標籤檔案可以包含單個標籤點集或兩個標籤點集,具體取決於檔案是否對應一個或兩個體積。每個標籤點包含三個座標:x、y 和 z。每一組一個或兩個標籤點還儲存著一些額外的可選資訊。一個標籤點集可能包含也可能不包含一組三個值:一個實數值權重、一個整型結構 ID 和一個整型患者 ID。一個標籤點可能包含也可能不包含一個標籤字串。本文件描述了讀取和寫入此格式檔案的函式。
public Status input_tag_points(
FILE *file,
int *n_volumes,
int *n_tag_points,
Real ***tags_volume1,
Real ***tags_volume2,
Real **weights,
int **structure_ids,
int **patient_ids,
STRING *labels[] )
public Status input_tag_file(
STRING filename,
int *n_volumes,
int *n_tag_points,
Real ***tags_volume1,
Real ***tags_volume2,
Real **weights,
int **structure_ids,
int **patient_ids,
STRING *labels[] )
這兩個函式從檔案中讀取一組標籤點。第一個形式假設檔案已經開啟,並將由呼叫函式關閉,而第二個形式開啟並關閉由檔名指定的,副檔名為.tag的檔案。每個集合中的體積數(每個集合中標籤的數量,目前為一個或兩個)在n_volumes引數中返回。標籤點數在n_tag_points引數中返回。每個集合中第一個標籤點的三維座標在tags_volume1引數中返回。如果體積數為兩個,則每個集合中的第二個標籤點在tags_volume2引數中返回。最後四個引數返回與每個標籤點集相關的輔助資訊。如果呼叫程式對這四個資料中的任何一個都不感興趣,則可以傳入一個NULL指標,檔案中的值將不會被返回。
public void free_tag_points(
int n_volumes,
int n_tag_points,
Real **tags_volume1,
Real **tags_volume2,
Real weights[],
int structure_ids[],
int patient_ids[],
STRING labels[] )
完成標籤點列表的處理後,可以透過呼叫此函式釋放相關的記憶體。
public Status initialize_tag_file_input(
FILE *file,
int *n_volumes )
public BOOLEAN input_one_tag(
FILE *file,
int n_volumes,
Real tag_volume1[],
Real tag_volume2[],
Real *weight,
int *structure_id,
int *patient_id,
STRING *label,
Status *status )
這兩個例程提供了一種更節省記憶體的方法來輸入標籤點。開啟檔案後,呼叫第一個例程來初始化標籤的輸入。接下來,重複呼叫第二個例程,直到它返回 FALSE,每次讀取一個標籤。
public Status output_tag_points(
FILE *file,
STRING comments,
int n_volumes,
int n_tag_points,
Real **tags_volume1,
Real **tags_volume2,
Real weights[],
int structure_ids[],
int patient_ids[],
STRING labels[] )
public Status output_tag_file(
STRING filename,
STRING comments,
int n_volumes,
int n_tag_points,
Real **tags_volume1,
Real **tags_volume2,
Real weights[],
int structure_ids[],
int patient_ids[],
STRING labels[] )
這兩個函式將標籤點列表寫入標籤點檔案。第一個形式假設檔案已經開啟,並將在稍後由呼叫函式關閉,而第二個形式開啟並關閉檔案,副檔名為.tag。comments引數是任何任意字串,用於記錄此檔案的內容。體積數(n_volumes)必須為一個或兩個。標籤點數由n_tag_points引數指定。一組或兩組標籤點的座標分別在tags_volume1和tags_volume2引數中。如果weights、structure_ids或patient_ids三個引數中的任何一個被指定為NULL,則這三部分資訊都不會寫入檔案。同樣,如果labels引數為NULL,則不會寫入任何標籤。
public STRING get_default_tag_file_suffix()
返回一個指向字串的指標,該字串包含標籤點檔案的預設字尾,目前為``tag。此指標不應該被釋放,其內容也不應該被修改。
public Status initialize_tag_file_output(
FILE *file,
STRING comments,
int n_volumes )
public Status output_one_tag(
FILE *file,
int n_volumes,
Real tag_volume1[],
Real tag_volume2[],
Real *weight,
int *structure_id,
int *patient_id,
STRING label )
public void terminate_tag_file_output(
FILE *file )
這兩個例程提供了一種更節省記憶體的方法來輸出標籤點。開啟檔案後,呼叫第一個例程來初始化標籤的輸出。接下來,重複呼叫第二個例程來每次輸出一個標籤點。第三個例程被呼叫以指示標籤檔案的結束。
以下是一個讀取標籤體積、刪除所有 x 座標為負的標籤、忽略每個集合中的第二個標籤點(如果存在)並將結果寫入新檔案的示例。
#include <volume_io.h>
int main(
int argc,
char *argv[] )
{
int i, n_volumes, n_tag_points, *structure_ids, *patient_ids;
Real **tags1, **tags2, *weights;
STRING *labels;
int new_n_tag_points, *new_structure_ids, *new_patient_ids;
Real **new_tags1, *new_weights;
STRING *new_labels;
/*--- input the tag file */
if( input_tag_file( "input_tags.tag", &n_volumes, &n_tag_points,
&tags1, &tags2, &weights, &structure_ids,
&patient_ids, &labels ) != OK )
return( 1 );
/*--- create a new tag point list of only those tag points
whose x coordinate is nonnegative */
new_n_tag_points = 0;
for_less( i, 0, n_tag_points )
{
if( tags1[i][0] >= 0.0 )
{
/*--- increase the memory allocation of the tag points */
SET_ARRAY_SIZE( new_tags1, new_n_tag_points,
new_n_tag_points+1, 10 );
ALLOC( new_tags1[new_n_tag_points], 3 );
SET_ARRAY_SIZE( new_weights, new_n_tag_points,
new_n_tag_points+1, 10 );
SET_ARRAY_SIZE( new_structure_ids, new_n_tag_points,
new_n_tag_points+1, 10 );
SET_ARRAY_SIZE( new_patient_ids, new_n_tag_points,
new_n_tag_points+1, 10 );
SET_ARRAY_SIZE( new_labels, new_n_tag_points,
new_n_tag_points+1, 10 );
ALLOC( new_labels[new_n_tag_points], strlen(labels[i])+1 );
/*--- copy from the input tags to the new tags */
new_tags1[new_n_tag_points][0] = tags1[i][0];
new_tags1[new_n_tag_points][1] = tags1[i][1];
new_tags1[new_n_tag_points][2] = tags1[i][2];
new_weights[new_n_tag_points] = weights[i];
new_structure_ids[new_n_tag_points] = structure_ids[i];
new_patient_ids[new_n_tag_points] = patient_ids[i];
(void) strcpy( new_labels[new_n_tag_points], labels[i] );
/*--- increment the number of new tags */
++new_n_tag_points;
}
}
/*--- output the new tags, the subset of the input tags */
if( output_tag_file( "output.tag", "Removed negative X's",
1, new_n_tag_points, new_tags1, NULL,
new_weights, new_structure_ids,
new_patient_ids, new_labels ) != OK )
return( 1 );
return( 0 );
}
在處理諸如跨模態和跨受試者配準等任務時,不同座標系之間的變換概念就出現了。提供了一個模組來處理線性(仿射)和非線性變換,並在標準化的腦成像中心格式中提供輸入和輸出,通常用於副檔名為.xfm的檔名。
為了支援這些功能,提供了兩種結構型別。第一個(Transform)是一個四乘四的線性(仿射)變換,它可以促進剛性變換,包括縮放、旋轉、平移和剪下。第二個是更高層次的變換(General_transform),它表示線性變換、非線性變換(薄板樣條)、平滑插值的網格變換、使用者定義的變換或這些變換的級聯。
線性變換函式都處理型別為Transform的物件。
#define Transform_elem( transform, i, j )
用於設定或檢索變換的第i行和第j列的值,其中<function>0<=i, j<=3</function>
public void make_identity_transform(
Transform *transform )
建立一個四乘四的單位變換。
public void transform_point(
Transform *transform,
Real x,
Real y,
Real z,
Real *x_trans,
Real *y_trans,
Real *z_trans )
透過給定的變換變換三維點,並返回三個變換後的座標。
public void transform_vector(
Transform *transform,
Real x,
Real y,
Real z,
Real *x_trans,
Real *y_trans,
Real *z_trans )
透過給定的變換變換三維向量,並返回三個變換後的座標。變換點和變換向量之間的唯一區別在於,變換向量不涉及變換的平移部分。
public void inverse_transform_point(
Transform *transform,
Real x,
Real y,
Real z,
Real *x_trans,
Real *y_trans,
Real *z_trans )
假設變換是正交變換(沒有剪下分量),則透過變換的逆變換變換點。
public void inverse_transform_vector(
Transform *transform,
Real x,
Real y,
Real z,
Real *x_trans,
Real *y_trans,
Real *z_trans )
假設變換是正交變換(沒有剪下分量),則透過變換的逆變換變換向量。
public void concat_transforms(
Transform *result,
Transform *t1,
Transform *t2 )
將變換t2乘以變換t1,並將乘積儲存在result中。透過result變換一個點等效於透過t1變換該點,然後透過t2變換結果。
一般變換可以表示線性變換、薄板樣條變換、網格變換和使用者定義的變換,以及這些變換的級聯。所有處理一般變換的函式都涉及型別為General_transform的物件。
public void create_linear_transform(
General_transform *transform,
Transform *linear_transform )
建立一個由單個線性變換組成的一般變換,該線性變換由linear_transform指定。如果傳入一個NULL作為linear_transform引數,則建立一個單位變換。
public void create_thin_plate_transform(
General_transform *transform,
int n_dimensions,
int n_points,
float **points,
float **displacements )
建立一個由薄板樣條組成的一般變換,它提供了多維空間的平滑非線性對映。points引數是一個大小為n_points乘以n_dimensions的陣列,表示一組點。displacements是一個(n_points + n_dimensions + 1)乘以n_dimensions的陣列,它是由get_nonlinear_warp()函式建立的,該函式不包含在這個庫中。
public void create_grid_transform(
General_transform *transform,
Volume displacement_volume )
建立一個由網格變換組成的一般變換,它提供了多維空間的平滑非線性對映。displacment_volume引數是一個四維體積,表示 x、y 和 z 方向的位移。體積的三個維度必須對應於 x、y 和 z 空間維度,第四個維度必須恰好有三個分量,即世界空間中每個方向的位移。維度可以以任何順序排列。
typedef void (*User_transform_function)( void *user_data,
Real x,
Real y,
Real z,
Real *x_trans,
Real *y_trans,
Real *z_trans )
public void create_user_transform(
General_transform *transform,
void *user_data,
size_t size_user_data,
User_transform_function transform_function,
User_transform_function inverse_transform_function )
透過複製使用者資料(從user_data開始的size_user_data位元組的資料)來建立一個使用者定義的變換。還需要兩個函式指標,用來指定變換點和逆變換點的方法。這些函式的型別為User_transform_function,上面已指定。
public void delete_general_transform(
General_transform *transform )
釋放一般變換結構中儲存的記憶體。
public Transform_types get_transform_type(
General_transform *transform )
返回一般變換型別,可以是LINEAR、THIN_PLATE_SPLINE、USER_TRANSFORM或CONCATENATED_TRANSFORM之一。
public Transform *get_linear_transform_ptr(
General_transform *transform )
如果一般變換的型別為LINEAR,則返回指向線性變換(型別為Transform)的指標,以便與前面描述的特定於線性變換的例程一起使用。否則,列印錯誤訊息。
public void concat_general_transforms(
General_transform *first,
General_transform *second,
General_transform *result )
級聯兩個一般變換。如果這兩個變換都是型別LINEAR,則結果也是這種型別,是兩個矩陣的乘積。否則,結果變換隻是兩個變換的級聯。
public int get_n_concated_transforms(
General_transform *transform )
返回給定變換中級聯變換的數量。如果變換的型別為CONCATENATED_TRANSFORM,則返回的數量是變換的數量,否則為 1。
public General_transform *get_nth_general_transform(
General_transform *transform,
int n )
如果變換的型別為CONCATENATED_TRANSFORM,則返回指向第n個變換的指標,其中n大於等於零且小於級聯變換中的變換數量。
public void general_transform_point(
General_transform *transform,
Real x,
Real y,
Real z,
Real *x_transformed,
Real *y_transformed,
Real *z_transformed )
透過一般變換變換三維點,並將結果傳遞迴最後三個引數。
public void general_inverse_transform_point(
General_transform *transform,
Real x,
Real y,
Real z,
Real *x_transformed,
Real *y_transformed,
Real *z_transformed )
透過一般變換的逆變換變換三維點,並將結果傳遞迴最後三個引數。
public void copy_general_transform(
General_transform *transform,
General_transform *copy )
建立一般變換的副本,根據需要在結構中分配記憶體。
public void create_inverse_general_transform(
General_transform *transform,
General_transform *inverse )
建立一個新的一般變換,它是給定變換的逆變換。
public void invert_general_transform(
General_transform *transform )
更改變換使其成為其逆變換。在同一個變換上呼叫它兩次等同於根本不呼叫該函式。
一般變換儲存在以麥康奈爾腦成像中心設計的 ASCII 格式的檔案中,通常具有 .xfm 的檔名副檔名。輸入和輸出函式是
public Status output_transform_file(
STRING filename,
STRING comments,
General_transform *transform )
public Status output_transform(
FILE *file,
STRING filename,
int *volume_count_ptr,
STRING comments,
General_transform *transform )
這兩個函式將一般變換寫入檔案,以適當的格式。comments 行是一個任意字串,它儲存在檔案中以供文件目的。comments 中的換行符會正確地導致多行註釋,並在每行開頭插入註釋字元。第一種形式開啟檔案,使用預設副檔名 .xfm,寫入變換,然後關閉檔案。函式的第二種形式假定檔案已經開啟,稍後將關閉。由於變換可能包含指向定義變換的 MINC 檔案的指標,因此必須將檔案的名稱傳遞給此函式,以用於建立 MINC 檔案的名稱。volume_count_ptr 必須指向一個已初始化的整數。每次建立變換的輔助 MINC 檔案時,該整數都會用於建立唯一的檔名,然後 volume_count_ptr 會遞增。這兩個函式都返回 ERROR 或 OK。
public Status input_transform(
FILE *file,
STRING filename,
General_transform *transform )
public Status input_transform_file(
STRING filename,
General_transform *transform )
從檔案輸入一般變換。第一種形式假定檔案已經開啟以供輸入,並且稍後將關閉。第二種形式開啟檔案以供輸入,使用預設副檔名 .xfm,讀取變換,然後關閉檔案。這兩個函式都返回 ERROR 或 OK。
public STRING get_default_transform_file_suffix()
返回指向字串的指標,該字串包含變換檔案的預設字尾,目前為 ``xfm。此指標不應釋放或修改其內容。
這是一個示例,它試圖說明一個典型的處理任務,包括使用體積、標籤點和變換。這是一個完整的程式,當與 BIC 體積 IO 庫連結時,它會讀取 MINC 格式的兩個體積,從檔案讀取一組標籤點,以及從檔案讀取變換。假定標籤點位於第一個體積的世界空間中,並且假定變換會將第一個體積的世界空間中的點變換到第二個體積的世界空間中。該程式使用輸入的變換變換每個標籤點(大概是從第一個體積的世界空間變換到第二個體積的世界空間),然後將結果變換到第二個體積的體素空間。如果體素座標在第二個體積內,則列印相應體素的值。
#include <volume_io.h>
/* ------------------------------------------------------------------
@COPYRIGHT :
Copyright 1993,1994,1995 David MacDonald,
McConnell Brain Imaging Centre,
Montreal Neurological Institute, McGill University.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies. The author and
McGill University make no representations about the
suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
------------------------------------------------------------------ */
int main()
{
int v1, v2, v3, sizes[MAX_DIMENSIONS];
Real x_world2, y_world2, z_world2;
Real voxel2[MAX_DIMENSIONS];
Real voxel_value;
Volume volume1, volume2;
int i, n_volumes, n_tag_points;
int *structure_ids, *patient_ids;
Real **tags1, **tags2, *weights;
STRING *labels;
General_transform transform;
/*--- input the two volumes */
if( input_volume( "volume1.mnc", 3, NULL, MI_ORIGINAL_TYPE, FALSE,
0.0, 0.0, TRUE, &volume1,
(minc_input_options *) NULL ) != OK )
return( 1 );
if( input_volume( "volume2.mnc", 3, NULL, MI_ORIGINAL_TYPE, FALSE,
0.0, 0.0, TRUE, &volume2,
(minc_input_options *) NULL ) != OK )
return( 1 );
/*--- input the tag points */
if( input_tag_file( "tags_volume1.tag", &n_volumes, &n_tag_points,
&tags1, &tags2, &weights, &structure_ids,
&patient_ids, &labels ) != OK )
return( 1 );
/*--- input the general transform */
if( input_transform_file( "vol1_to_vol2.xfm", &transform ) != OK )
return( 1 );
/*--- convert each tag point */
get_volume_sizes( volume2, sizes );
for_less( i, 0, n_tag_points )
{
/*--- transform the tag points from volume 1 to volume 2
world space */
general_transform_point( &transform,
tags1[i][X], tags1[i][Y], tags1[i][Z],
&x_world2, &y_world2, &z_world2 );
/*--- transform from volume 2 world space to
volume 2 voxel space */
convert_world_to_voxel( volume2, x_world2, y_world2, z_world2,
voxel2 );
/*--- convert voxel coordinates to voxel indices */
v1 = ROUND( voxel2[0] );
v2 = ROUND( voxel2[1] );
v3 = ROUND( voxel2[2] );
/*--- check if voxel indices inside volume */
if( v1 >= 0 && v1 < sizes[0] &&
v2 >= 0 && v2 < sizes[1] &&
v3 >= 0 && v3 < sizes[2] )
{
voxel_value = get_volume_real_value( volume2, v1, v2, v3,
0, 0 );
print( "The value for tag point %d (%s) is: %g\n",
i, labels[i], voxel_value );
}
else
print( "The tag point %d (%s) is outside.\n" );
}
/*--- free up memory */
delete_volume( volume1 );
delete_volume( volume2 );
free_tag_points( n_volumes, n_tag_points, tags1, tags2,
weights, structure_ids, patient_ids, labels );
delete_general_transform( &transform );
return( 0 );
}