跳轉到內容

MINC/教程/程式設計05

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

使用超立方體

[編輯 | 編輯原始碼]

上一個教程遍歷了體積中的每個體素,對其加了1,並將輸出寫回同一個體積。在這裡我們將改進該示例:輸出將寫入一個新的體積,我們將使用超立方體進行資料處理。

超立方體是 minc 中的核心概念。它允許您從體積中提取任意(但連續)的資料塊,對其進行操作,然後將其寫回體積。這比單獨獲取每個體素快得多;但是,它需要更多的記憶體。

因此,繼續示例:此程式碼獲取一個體積,建立一個副本,該副本在所有方面都相同,只是每個體素都加了 1。新體積也將始終使用全域性縮放,無論輸入是否具有切片縮放。

#include <minc2.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int main(int argc, char **argv) {
  mihandle_t    minc_volume, new_volume;
  midimhandle_t dimensions[3], *dimensions_new;
  double        min, max;
  int           result, i;
  unsigned long start[3], count[3];
  unsigned int  sizes[3];
  double        *slab;

  if (argc != 3) {
    fprintf(stderr, "Usage: input.mnc output.mnc\n");
  }

  /* open the volume - first command line argument */
  result = miopen_volume(argv[1], MI2_OPEN_READ, &minc_volume);
  /* check for error on opening */
  if (result != MI_NOERROR) {
    fprintf(stderr, "Error opening input file: %d.\n", result);
    return(1);
  }

  /* get the dimension sizes */
  miget_volume_dimensions(minc_volume, MI_DIMCLASS_SPATIAL,
			  MI_DIMATTR_ALL, MI_DIMORDER_FILE,
			  3, dimensions);
  miget_dimension_sizes(dimensions, 3, sizes);
  printf("Volume sizes: %u %u %u\n", sizes[0], sizes[1], sizes[2]);

到目前為止,一切都很好 - 這些程式碼對你來說應該都不陌生。請注意為新體積和新維度建立了兩個新變數。

  /* allocate new dimensions */
  dimensions_new = malloc(sizeof(midimhandle_t) * 3);

  /* copy the dimensions */
  for(i=0; i < 3; i++) {
    micopy_dimension(dimensions[i], &dimensions_new[i]);
  }

在這裡,我們為新體積的維度分配記憶體,並從舊體積複製維度定義。

  /* allocate memory for the hyperslab - make it size of entire volume */
  slab = malloc(sizeof(double) * sizes[0] * sizes[1] * sizes[2]);

  start[0] = start[1] = start[2] = 0.0;
  if (miget_real_value_hyperslab(minc_volume, MI_TYPE_DOUBLE,
				 start, count, slab) != MI_NOERROR) {
    fprintf(stderr, "Error getting hyperslab\n");
    return(1);
  }

為超立方體分配了記憶體,並獲得了超立方體 - 在這種情況下,超立方體是整個體積。關鍵函式是miget_real_value_hyperslab,它接受五個引數:minc 體積控制代碼,您想要資料所在的型別,開始的陣列(在本例中全為零),計數的陣列(體積大小)和寫入資料的地址。


  /* set min and max to the first voxel plus 1 
   *  (since we add one to everything anyway) */
  min = slab[0]+1;
  max = slab[0]+1;

  /* loop over all voxels */
  for (i=0; i < sizes[0] * sizes[1] * sizes[2]; i++) {
    /* increment voxel by 1 */
    slab[i] += 1;
    
    /* check if min or max should be changed */
    if (slab[i] < min) {
      min = slab[i];
    }
    else if (slab[i] > max) {
      max = slab[i];
    }
  }

現在我們迴圈遍歷超立方體中的每個體素(注意它是如何作為一維陣列處理的),確保保留修改後的影像最小值和最大值。

  /* create the new volume */
  if (micreate_volume(argv[2], 3, dimensions_new, MI_TYPE_UBYTE,
		      MI_CLASS_REAL, NULL, &new_volume) != MI_NOERROR) {
    fprintf(stderr, "Error creating new volume\n");
    return(1);
  }

然後我們使用micreate_volume建立實際的體積。它接受七個引數:檔名,維度數,實際維度的陣列(透過上面的複製操作建立),資料型別(此處設定為無符號位元組),資料類,特殊體積屬性(此處設定為 NULL),以及體積控制代碼的地址。

  /* create the data for the new volume */
  if (micreate_volume_image(new_volume) != MI_NOERROR) {
    fprintf(stderr, "Error creating volume data\n");
    return(1);
  }

現在,我們使用micreate_volume_image確保資料在 minc 體積控制代碼中建立。

  /* set valid and real range */
  miset_volume_valid_range(new_volume, 255, 0);
  miset_volume_range(new_volume, max, min);

  /* write the modified hyperslab to the file */
  if (miset_real_value_hyperslab(new_volume, MI_TYPE_DOUBLE,
				 start, count, slab) != MI_NOERROR) {
    fprintf(stderr, "Error setting hyperslab\n");
    return(1);
  }

然後我們設定有效範圍 - 從 0 到 255,因為這是無符號位元組資料 - 以及體積範圍,這是透過在迴圈遍歷體素時跟蹤最小值和最大值確定的。超立方體使用miset_real_value_hyperslab放回體積,它接受與miget_real_value_hyperslab完全相同的引數。

  /* closes the volume and makes sure all data is written to file */
  miclose_volume(minc_volume);
  miclose_volume(new_volume);

  /* free memory */
  free(dimensions_new);
  free(slab);

  return(0);
}

最後,我們關閉體積,釋放已分配的記憶體並退出。

程式碼

[編輯 | 編輯原始碼]
#include <minc2.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int main(int argc, char **argv) {
  mihandle_t    minc_volume, new_volume;
  midimhandle_t dimensions[3], *dimensions_new;
  double        min, max;
  int           result, i;
  unsigned long start[3], count[3];
  unsigned int  sizes[3];
  double        *slab;

  if (argc != 3) {
    fprintf(stderr, "Usage: input.mnc output.mnc\n");
  }

  /* open the volume - first command line argument */
  result = miopen_volume(argv[1], MI2_OPEN_READ, &minc_volume);
  /* check for error on opening */
  if (result != MI_NOERROR) {
    fprintf(stderr, "Error opening input file: %d.\n", result);
    return(1);
  }

  /* get the dimension sizes */
  miget_volume_dimensions(minc_volume, MI_DIMCLASS_SPATIAL,
			  MI_DIMATTR_ALL, MI_DIMORDER_FILE,
			  3, dimensions);
  miget_dimension_sizes(dimensions, 3, sizes);
  printf("Volume sizes: %u %u %u\n", sizes[0], sizes[1], sizes[2]);

  /* allocate new dimensions */
  dimensions_new = malloc(sizeof(midimhandle_t) * 3);

  /* copy the dimensions */
  for(i=0; i < 3; i++) {
    micopy_dimension(dimensions[i], &dimensions_new[i]);
  }

  start[0] = start[1] = start[2] = 0;

  for (i=0; i < 3; i++) {
    count[i] = (unsigned long) sizes[i];
  }

  /* allocate memory for the hyperslab - make it size of entire volume */
  slab = malloc(sizeof(double) * sizes[0] * sizes[1] * sizes[2]);

  if (miget_real_value_hyperslab(minc_volume, MI_TYPE_DOUBLE,
				 start, count, slab) != MI_NOERROR) {
    fprintf(stderr, "Error getting hyperslab\n");
    return(1);
  }
  
  /* set min and max to the first voxel plus 1 
   *  (since we add one to everything anyway) */
  min = slab[i]+1;
  max = slab[i]+1;

  /* loop over all voxels */
  for (i=0; i < sizes[0] * sizes[1] * sizes[2]; i++) {
    /* increment voxel by 1 */
    slab[i] += 1;
    
    /* check if min or max should be changed */
    if (slab[i] < min) {
      min = slab[i];
    }
    else if (slab[i] > max) {
      max = slab[i];
    }
  }

  /* create the new volume */
  if (micreate_volume(argv[2], 3, dimensions_new, MI_TYPE_UBYTE,
		      MI_CLASS_REAL, NULL, &new_volume) != MI_NOERROR) {
    fprintf(stderr, "Error creating new volume\n");
    return(1);
  }
  
  /* create the data for the new volume */
  if (micreate_volume_image(new_volume) != MI_NOERROR) {
    fprintf(stderr, "Error creating volume data\n");
    return(1);
  }

  /* set valid and real range */
  miset_volume_valid_range(new_volume, 255, 0);
  miset_volume_range(new_volume, max, min);

  /* write the modified hyperslab to the file */
  if (miset_real_value_hyperslab(new_volume, MI_TYPE_DOUBLE,
				 start, count, slab) != MI_NOERROR) {
    fprintf(stderr, "Error setting hyperslab\n");
    return(1);
  }
  
  /* closes the volume and makes sure all data is written to file */
  miclose_volume(minc_volume);
  miclose_volume(new_volume);

  /* free memory */
  free(dimensions_new);
  free(slab);

  return(0);
}
華夏公益教科書