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指標來更正。
型別和宏
[edit | edit source]為與 BIC Volume 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替換為引數string和str2的連線。
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 目錄。任何美元符號$的出現,都會導致接下來的文字(直到下一個斜槓)擴充套件到由文字指定的環境變數。透過在任何~ 或$之前放置一個反斜槓 \,可以避免這種擴充套件。在以下所有接受檔名的函式中,都會自動執行檔名擴充套件。
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 格式表示的無符號字元陣列。
記憶體分配
[edit | edit source]提供了一組宏,允許輕鬆分配和釋放記憶體,最多支援 5 維陣列。還會執行記憶體分配檢查,以捕獲錯誤,例如釋放未分配的記憶體。此外,記憶體分配會自動跟蹤所有分配的記憶體,因此可以檢測記憶體洩漏(孤立記憶體)。
基本記憶體分配
[edit | edit source]基本宏如下所示
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 中。在二維情況下,這僅透過 2 次記憶體分配來實現,一次是為儲存分配 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 )
如果啟用了記憶體檢查,則可以使用此函式來檢測記憶體洩漏。在程式結束時,程式設計師應該釋放所有已知的記憶體,然後呼叫此函式。任何剩餘的已分配記憶體都會被列印到一個檔案中,指示分配記憶體的檔案和行號。
更高級別的陣列分配
[edit | edit source]除了前面介紹的基本記憶體分配宏之外,還提供了一組用於處理動態更改大小的陣列的有用宏
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'th 索引處,然後遞增 n_elems。引數 chunk_size 指定記憶體分配的粒度。
DELETE_ELEMENT_FROM_ARRAY( array, n_elems, index_to_remove,
chunk_size )
從陣列中刪除 index_to_remove'th 元素,減少陣列中的元素數(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 變數將增加此值。此使用的不同之處在於,元素數 (n_elems) 可以任意減少,而不會導致記憶體被釋放。
進度報告
[edit | edit source]為了簡化對特定處理任務的進度的監控,提供了一個進度報告模組。在任務執行過程中,進度報告會在行中列印點,指示任務完成的進度。如果任務將花費很長時間(超過 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 )
終止進度報告。
文字輸出
[edit | edit source]與使用標準的 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 位元組型別中,其值從零到 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為零到 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 檔案的唯一方法是使用此函式。
建立和分配卷後,有很多函式可用於操作卷。請注意,與每個卷關聯的是一個有效的體素範圍,該範圍指示實際儲存在卷中的值範圍,例如,零到 200 是無符號位元組卷的一個可能的範圍。還有一個第二個範圍,即real範圍,它將有效體素範圍對映到任意實數範圍,例如,有效體素的零到 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 )
給定一個卷和一個實數值體素索引,傳遞迴相應的 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[] )
將 world 座標轉換為體素。為了將這些體素座標用作整數索引,例如,作為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 )
轉換假定為表面法線的向量到 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是一個二維陣列,大小為值的個數乘以插值維度的個數。second_deriv是一個三維陣列,大小為值的個數乘以插值維度的個數乘以插值維度的個數。
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 )
建立體積並設定其大小後,此函式將分配體素的記憶體。請注意,體素值不會被初始化,使用者必須用所需的值填充體積。
每個體積都與從 體素 空間到 世界 空間的轉換相關聯。有幾種方法可以定義這種轉換。最簡單的方法是直接指定它。
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[] )
設定體素到世界轉換的平移部分。指定一個體素座標 (體素),以及希望此體素對映到的真實世界位置 (world_space_voxel_maps_to)。體素到世界轉換將更新以提供此對映。
public void set_volume_direction_cosine(
Volume volume,
int dimension,
Real dir[] )
設定特定體素維度的真實世界軸。例如,如果 維度 為 1,而 方向 為 (0.0, 1.0, 1.0),那麼體積的第二個維度上的體素將對映到真實世界軸 (0.0, 1.0, 1.0) 並歸一化為單位長度,然後按體積的第二個維度上的間距進行縮放。
public void get_volume_direction_cosine(
Volume volume,
int dimension,
Real dir[] )
返回特定體素維度的真實世界軸。請注意,維度 必須是體積中的空間維度。
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 )
返回體積的座標系型別的副本,用字串名稱表示。呼叫函式在完成操作後必須釋放此字串。
複製體積
[edit | edit source]建立體積的另一種方法是從現有體積中簡單地複製整個體積定義。
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 )
建立體積的精確副本。
體積快取
[edit | edit source]為了有效地處理太大而無法放入虛擬記憶體的體積,我們實現了一個簡單的快取方案。按需讀寫磁碟檔案以提供大容量完全駐留在記憶體中的外觀。前面描述的所有體積例程都透明地支援此功能,但也有一些例程用於配置體積快取。
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() 將按指定建立檔案。請注意,當呼叫此函式時,重要的是在退出程式之前刪除體積,以便快取的體積重新整理其緩衝區並關閉檔案,否則,對體積的最新更改將不會寫入檔案。
體積原始碼示例
[edit | edit source]這裡提供了一些讀取、寫入和操作體積的示例。
一個完整的程式,用於讀取 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 );
}
多體積輸入
[edit | edit source]前面描述的 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,則返回的數量是變換的數量,否則為一。
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 Volume 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 );
}