跳轉到內容

MINC/軟體開發/EZMINC/教程

來自華夏公益教科書,開放的書籍,為開放的世界

開啟 minc 檔案以供讀取

[編輯 | 編輯原始碼]
 #include "minc_1_rw.h"
 using namespace minc;
 //...
 try
 {
  minc_1_reader rdr;
  rdr.open(input_minc_file);
 } catch (const minc::generic_error & err) {
  std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl;
  std::cerr << err.msg()<<std::endl;
 }

開啟 minc 檔案以供寫入

[編輯 | 編輯原始碼]

Minc 檔案是一個複雜的結構,許多引數必須設定正確才能生成有意義的檔案,最簡單的方法是從另一個 minc 檔案中複製它們

 minc_1_writer wrt;
 wrt.open(output_minc_file,example_minc_file);

或者,如果另一個檔案已經開啟:syntaxhighlight lang="text"

wrt.open(output_minc_file,rdr);

</syntaxhighlight>

或者,如果只需要保留尺寸(建立一個具有浮點型別體素和 2D 切片的 minc 檔案):syntaxhighlight lang="text"

wrt.open(output_minc_file,rdr.info(),2,NC_FLOAT);

</syntaxhighlight>

分析 MINC 檔案元資訊

[編輯 | 編輯原始碼]
  • 確定維度數:rdr.dim_no()
  • 計算矩陣大小、解析度 

syntaxhighlight lang="text"

std::cout<<"Dimensions:"<<std::endl
<< " Vector:"<<rdr.ndim(0)<<std::endl
<< " X:"<<rdr.ndim(1)<<" step:"<<rdr.nspacing(1)<<" start:"<<rdr.nstart(1)<<std::endl
<< " Y:"<<rdr.ndim(2)<<" step:"<<rdr.nspacing(2)<<" start:"<<rdr.nstart(2)<<std::endl
<< " Z:"<<rdr.ndim(3)<<" step:"<<rdr.nspacing(3)<<" start:"<<rdr.nstart(3)<<std::endl
<< " Time:"<<rdr.ndim(4)<<" step:"<<rdr.nspacing(4)<<" start:"<<rdr.nstart(4)<<std::endl;

</syntaxhighlight> 注意 這些是物理引數,不依賴於 minc 檔案中資訊儲存的方式

  • 輸出方向餘弦矩陣
 for(int i=0;i<3;i++)
 {
 if(rdr.have_dir_cos(i))
  for(int j=0;j<3;j++)
    std::cout<<rdr.ndir_cos(i,j)<<" ";
  std::cout<<std::endl;
 }
  • 讀取 minc 檔案歷史記錄
 std::cout<<"Minc history:"<<rdr.history().c_str()<<std::endl;
  • 讀取字串屬性
 std::cout<<"Subject name:"<<rdr.att_value_string("patient","full_name").c_str()<<std::endl;
  • 讀取雙精度屬性

syntaxhighlight lang="text"

std::cout<<"Echo time:"<<rdr.att_value_double("acquisition","echo_time")[0]<<std::endl;

</syntaxhighlight> 注意:讀取雙精度屬性按值返回 std::vector<double>

讀取影像

[編輯 | 編輯原始碼]

影像資料儲存為給定型別的多維值陣列。陣列按切片組織(整個檔案可能只有一個切片),儲存在 minc 檔案中的值可能是歸一化的,請參閱MINC/參考以獲取完整詳細資訊。EZMINC 的開發旨在隱藏資料表示的複雜性,使其遠離程式設計師,但同時允許對資料儲存方式進行完全控制,如果需要的話。有幾種方法可以使用 EZMINC 庫從檔案中讀取影像資訊

  • 最簡單的方法是將整個體積複製到記憶體中的多維陣列中。通常這是最方便的方法
    • 讀取表示實值的體積(將它們解釋為浮點數)

syntaxhighlight lang="text"

#include <minc_1_simple.h>
#include <minc_1_simple_rw.h>
using namespace minc;
//....
simple_volume<float> src;
minc_1_reader rdr;
rdr1.open(input_file);
load_simple_volume<float>(rdr,src);
std::cout<<"Voxel at voxel coordinates (1,2,3) is "<<src.get(1,2,3)<<std::endl;
//using safe_get to make sure that we don't read beyond the allocated space
std::cout<<"Voxel at world coordinates (1,2,3) is "<<src.safe_get(src.world_to_voxel(IDX<double>(1.0,2.0,3.0)))<<std::endl;

</syntaxhighlight>

    • 讀取具有二進位制掩碼(或離散標籤)的體積
 #include <minc_io_simple_volume.h>
 #include <minc_1_simple.h>
 #include <minc_1_simple_rw.h>
 using namespace minc;
 //....
 simple_volume<unsigned char> src;
 minc_1_reader rdr;
 rdr1.open(input_file);
 load_simple_volume<unsigned char>(rdr,src);
 std::cout<<"Labels at (1,2,3) is "<<(int)src.get(1,2,3)<<std::endl;
    • 讀取 4D 體積
 simple_4d_volume<float> vol;
 load_4d_volume<float>(rdr,vol);
 std::cout<<"Voxel at voxel coordinates (1,2,3) slice 0 is "<<src.get(1,2,3,0)<<std::endl;
  • 讀取整個 minc 檔案作為單個連續緩衝區,以向量維度為最快變化(如果存在),X、Y、Z 和時間為最慢變化(如果存在)的方式組織
 #include <minc_1_rw.h>
 #include <minc_1_simple.h>
 using namespace minc;
 //...
 minc_1_reader rdr;
 rdr.open(input_file);
 rdr.setup_read_float(); //we have to setup the file to a proper data type
 
 size_t size=1;
 for(i=0;i<rdr.dim_no();i++)
    size*=rdr.dim(i).length;
  
 float* array=new float[size];
 
 load_standard_volume<float>(rdr,array);
  • 逐個體素讀取整個 minc 檔案,按照資料在檔案中儲存的順序。當處理大量輸入檔案並且將它們全部一起儲存在記憶體中存在問題時,此方法非常有用
 #include <minc_1_rw.h>
 #include <minc_1_simple.h>
 using namespace minc;
 //...
 minc_1_reader rdr;
 rdr.open(input_file);
 rdr.setup_read_float(); //we have to setup the file to a proper data type
 minc_input_iterator<float> in(rdr);
 
 double avg=0;
 int cnt=0;
 for(in.begin();!in.last();in.next())
 {
    avg+=in.value()
    cnt++;
 }
 std::cout<<"Average value="<<avg/cnt<<std::endl;
  • 最低階介面,按資料在檔案中儲存的順序逐片讀取 minc 檔案
 #include <minc_1_rw.h>
 using namespace minc;
 //...
 minc_1_reader rdr;
 rdr.open(input_file);
 rdr.setup_read_float(); //we have to setup the file to a proper data type

 float* slice_buffer=new float[rdr.slice_len()];

 for(rdr.begin();!rdr.last();rdr.next_slice())//minc_1_reader is actually an iterator!
 {
    rdr.read(slice_buffer);
    //do something usefull with the data
 }

寫入 MINC 檔案元資訊

[編輯 | 編輯原始碼]
  • 複製歷史記錄 注意:如果使用 minc_1_writer::open 的第一種形式,歷史記錄將自動複製
 wrt.copy_headers(rdr);
  • 將新行追加到 MINC 歷史記錄
 wrt.append_history("minc_test was used to produce this file\n");
  • 寫入字串屬性
wrt.insert("patient","full_name","John Doe");
  • 寫入雙精度屬性
wrt.insert("acquisition","echo_time",0.120); //echo time was 120ms
  • 寫入雙精度值陣列
std::vector<double> bvalues(64);
//...
wrt.insert("acquisition","bvalues",bvalues);
  • 從另一個 minc 檔案複製所有頭
wrt.copy_headers(rdr);

寫入影像

[編輯 | 編輯原始碼]
  • 最簡單的介面,使用 simple_volume 或 simple_4d_volume
 simple_volume<float> output_vol;
 //...
 minc_1_writer wrt;
 wrt.open(output_minc,rdr);
 save_simple_volume<float>(wrt,output_vol);
 simple_4d_volume<float> output_vol;
 //...
 minc_1_writer wrt;
 wrt.open(output_minc,rdr);
 save_4d_volume(wrt,vol);
  • 從連續陣列寫入影像
 float *output_vol=new float[size];
 //...
 minc_1_writer wrt;
 wrt.open(output_minc,rdr);
 wrt.setup_write_float(); //have to setup the data type
 save_standard_volume<float>(wrt,output_vol);
  • 使用輸出迭代器
    //adding a value c to all voxels
    minc_1_reader rdr;
    rdr.open(input_minc);
    rdr.setup_read_float();
    
    minc_1_writer wrt;
    wrt.open(output_minc,rdr);
    wrt.setup_write_float();
     
    minc_input_iterator<float> in(rdr);
    minc_output_iterator<float> out(wrt);
    for(in.begin(),out.begin();!in.last();in.next(),out.next())
    {
      out.value(in.value()+c);
    }
  • 最低階,逐片寫入影像
 #include <minc_1_rw.h>
 using namespace minc;
 //...
 minc_1_reader rdr;
 rdr.open(input_file);
 rdr.setup_read_float(); //we have to setup the file to a proper data type

 minc_1_writer wrt;
 wrt.open(output_minc,rdr);
 wrt.setup_write_float();

 float* slice_buffer=new float[rdr.slice_len()];

 for(rdr.begin(),wrt.begin();!rdr.last();rdr.next_slice(),wrt.next_slice())
 {
    rdr.read(slice_buffer);
    //do something usefull with the data
    wrt.write(slice_buffer);
 }
華夏公益教科書