Manual for reconstructing tomographic images with PyHST

a description and the lastest sources for ESRF PyHST project can be found here

a list of useful Unix commands can be found here


Table Of Content

basics required:
keep in mind:
  • PyHST is available for Linux and SUN only, hst_master, hst_slave are available for Tru64 only
  • graphic display is important - only use ssh -X account@domain.whatever, Windows user should enable "Tunnel X11 connections" in their SSH option menu and make sure to start X-Win before launching the ssh application; test graphic output eg with "gv" - if it fails check the display parameter echo $DISPLAY and correct it with setenv DISPLAY your_host:display
  • Unix is case sensitive - "PyHST my_file.par" is NOT the same as "pyhst my_FILE.par"
  • DO NOT USE blank space or hyphen in Unix file names (try "my_file" instead of "my file" / "my-file")
  • all (Linux) data is stored LITTLE ENDIAN (LowByteFirst) - BIG ENDIAN (HighByteFirst) can lead to unexpected errors
  • check results after each step by creating images (corrected radiographics, sinograms, sample slices) and store them in easy-to-use format (JPG, GIF, etc)
  • when you are finished with the reconstruction do not forget to remove your redundant files (float volumes etc.) to lower hard disc consumption - not-necessary over-quota use of hard disc space might lead to random data removement by your system administrator

All data located outside your $HOME is usually not backuped automatically - always keep backuping in mind, please ask your local contact!

1. Short notes on the EDF format (if already known skip to next step)

EDF Format
Input data (projections, sinograms etc.) have to be in EDF format (at the moment).
    Edf format assumptions:
    ===========================
    - Each Edf file contains a certain number of data blocks.
    - Each data block represents data stored in an one, two or three-dimensional array.
    - Each data block contains a header section, written in ASCII, and a data section of
      binary information.
    - The size of the header section in bytes is a multiple of 1024. The header is
      padded with spaces (0x20). If the header is not padded to a multiple of 1024,
      the file is recognized, but the output is always made in this format.
    - The header section starts by '{' and finishes by '}'. It is composed by several
      pairs 'keyword = value;'. The keywords are case insensitive, but the values are case
      sensitive. Each pair is put in a new line (they are separeted by 0x0A). In the
      end of each line, a semicolon (;) separes the pair of a comment, not interpreted.
      Exemple:
        {
        ; Exemple Header
        HeaderID = EH:000001:000000:000000    ; automatically generated
        ByteOrder = LowByteFirst              ;
        DataType = FloatValue                 ; 4 bytes per pixel
        Size = 4000000                        ; size of data section
        Dim_1= 1000                           ; x coordinates
        Dim_2 = 1000                          ; y coordinates

        (padded with spaces to complete 1024 bytes)
        }
    - There are some fields in the header that are required for this implementation. If any of
      these is missing, or inconsistent, it will be generated an error:
        Size: Represents size of data block
        Dim_1: size of x coordinates (Dim_2 for 2-dimentional images, and also Dim_3 for 3d)
        DataType
        ByteOrder
    - For the written images, these fields are automatically genereted:
        Size,Dim_1 (Dim_2 and Dim_3, if necessary), Byte Order, DataType, HeaderID and Image
      These fields are called here "static header", and can be retrieved by the method
      GetStaticHeader. Other header components are taken by GetHeader. Both methods returns
      a dictionary in which the key is the keyword of the pair. When writting an image through
      WriteImage method, the Header parameter should not contain the static header information,
      which is automatically generated.
    - The indexing of images through these functions is based just on the 0-based position in
      the file, the header items HeaderID and Image are not considered for referencing the
      images.
    - The data section contais a number of bytes equal to the value of Size keyword. Data
      section is going to be translated into an 1D, 2D or 3D Numaric Array, and accessed
      through GetData method call.


    IMPORTANT - READ THIS
    ===========================
    If you are going to use EdfFile, you have to care about the type of your data.
    The EdfFile class stores data in a Numeric Python array, very efficient
    way for doing matrix operations.

    However, for an unknow reason (to us), Numeric Python doesn't handle the following
    types:
    - unsigned short
    - unsigned integer
    - unsigned long
    Which are supported by Edf file specification.
    So if you use these formats, pay attention to the type parameters when reading
    from or writing to a file (when using other Edf types, the convertions are direct,
    and you don't need to mention the type, unless you really want to change it).

    By default, if no type is mentioned, the EdfFile class stores, when reading a file:
    - UnsignedShort data into an short array
    - UnsignedInteger data into an integer array
    - UnsignedLong data into a long array

    This keeps the size of storage in memory, but can imply in loss of information.

    Taking "unsigned short" as an exemple:
    1) Supposing you get data with: "array=obj.GetData(0)", this array is going to be
       created as signed short. If you write it then as: 'obj2.WriteImage({},array)',
       the edf image created is going to be of signed short type, different from the
       original. To save in the same way as the former image, you must be explicit
       about the data type: 'obj2.WriteImage({},array,DataType="UnsignedShort")'
    2) If you intend to make operations, or even just read properly the values of an
       image, you should read this image as 'array=obj.GetData(0),DataType="Long")'.
       This will require two times the storage space but will assure correct values.
       If you intend to save it again, you should include the correct data type you
       are saving to.
    3) When you are saving an unsigned short array into a long, float or double
       format, you should be explicit to the fact you want this array to be
       considered a signed or unsigned (through the parameter WriteAsUnsigened).
       Suppose an hexa value of FFFF in this array. This means -1 if the array
       comes from signed data, or 65535 if it cames from unsigned data. If you save
       the array as this: 'obj2.WriteImage({},array,DataType="FloatValue")' it is
       going to be considered unsigned, and a value of FFFF is going to be
       translated into a float -1. If you want to consider the array as unsigned
       you should do:
       'obj2.WriteImage({},array,DataType="FloatValue", WriteAsUnsigened=1 )'
       In this way, a FFFF value is going to be translated into a float 65535.


Alexandre Gobbo (gobbo@esrf.fr)

The complete documentation can be found here.

new parameters

  • SAVE_JPEG_SLICES=YES or NO
    JPEG_QUALITY=1 .. 100
  • DO_HISTOGRAM=YES or NO
  • BICUBIC=int constant

    interpolates more projections, for eg constant=10 6000 instead 600 projections where jused by interpolating between the experimental data (Paul Tafforeau)

  • SUMRULE={0, 1, 2}

    • 0 = use classical RAM-LAK Filter, frequency f0 is set to 0, resulting in mean(slice) as offset substracted from all attenuation values, recommended if float volumes are reduced to char-volumes after reconsturction
    • 1 = adds mean(sinogram)-mean(slice) to all attenuation values, works fine if object does not leave field of view during tomographic scan, leads to more exact determination of the local attenuation coefficient
    • 2 = impuric approach for local tomography (object leaves field of view during scan) in order to have same effect as option "1", approach: use mean of local frequencies around f0 (Mirone)

  • OUTPUT_SINOGRAMS={YES, NO}

    creates Sinograms (EDF-Format) instead of reconstructing

  • RECONSRUCT_FROM_SINOGRAMS={YES, NO}

    works now fine with PyHST and hst_slave

  • OPTIONS= { 'padding':'E' } or { 'padding':'0' }

    • { 'padding':'E' } - padds in frequency domain with last and first values of array (default!) in the sense of [FFT_of_input_data_DIMx][PADDING_FirstValue_DIMx][PADDING_LastValue_DIMx]
    • { 'padding':'0' } - padds in frequency domain with zeros

  • OPTIONS= {'axis_to_the_center':'N'} or {'axis_to_the_center':'Y'}

    by toggling this option on ('Y') the volume is reconstructed that way that the axis of rotation is put in the middle of the resulting 3d data set, very useful if afterwards a stack of volumes has to be combined into one; can be combined with the option above via the syntax eg { 'padding':'E' , 'axis_to_the_center':'N' }

  • Fourier-Filters/Windowing, if you prefer alternative filters de-comment one of the following
        # HANN-filter
        #def FOURIER_FILTER(self, x): return 0.5 + 0.5*math.cos(2*math.pi*x)
    
        # BLACKMAN-filter
        #def FOURIER_FILTER(self, x): return 0.42 - 0.5*math.cos(2*math.pi*(x-0.5)) + 0.08*math.cos(4*math.pi*(x-0.5))
    
        # HAMMING-filter
        #def FOURIER_FILTER(self, x): return 0.54-0.46*math.cos(2*math.pi*(x-0.5))
    
        # COSINE-filter
        #def FOURIER_FILTER(self, x): return math.cos(math.pi*(x))
    
        # SHEPP-LOGAN-filter
        #def FOURIER_FILTER(self, x): return math.sin(math.pi*(x))/(math.pi*(x))
    
        # BARTLETT-filter
        #def FOURIER_FILTER(self, x): return 1 - abs(2*x)
        

    for further descriptions please refer to

    • Principles of Computerized Tomographic Imaging, by Avinash C. Kak, Malcolm Slaney, Society for Industrial & Applied Mathematics, U.S. (re-issue, 2001)
    • Reconstructions from Radiographs and Electron Micrographs, G. N. Ramachandran, A. V. Lakshminarayan, Proc. Acad. Sci. USA 68, 2236 (1971)
    • Einführung in die Computertomographie Mathematisch-physikalische Grundlagen der Bildrekonstruktion, by T. M. Buzug, Springer Verlag (2004).

  • Ring-artefacts type I (warm CCD pixel, defects on scintillating screen etc.), filters

    • sinogram-based filter, performs high-pass on mean over all angles (of one slice) to detect distortions, these are than corrected by adding the high-passed sinogram to input sinogram with conservation of the mean of the input sinogram, the array ar[] as heaviside-function defines the high-pass
            DO_SINO_FILTER= YES
            SINO_FILTER = "SINO_Filter"
            ar = Numeric.ones(NUM_IMAGE_1,'f')
            ar[0]=0.0
            ar[2:18]=0.0
            SINO_FILTER_PARA={"FILTER": ar }
            
      the path to the object (in case of conflicting versions, selfdone objects etc) can be set via
            SINO_FILTER_PATH="/"
            

      initially suggest by Mark River

    • same as above, only median instead of mean is used
            DO_SINO_FILTER= YES
            SINO_FILTER = "SINO_Filter_Median"
            ar = Numeric.ones(NUM_IMAGE_1,'f')
            ar[0]=0.0
            ar[2:18]=0.0
            SINO_FILTER_PARA={"FILTER": ar }
            
      the path to the object (in case of conflicting versions, selfdone objects etc) can be set via
            SINO_FILTER_PATH="/"
            
    • another filter based on detecting lines parallel to the angle axis can be called via
            DO_SINO_FILTER= YES
            SINO_FILTER = "SINO_Filter_Smooth"
            span = 51
            SINO_FILTER_PARA={"SmoothFilter":span}
            
      the detected lines are removed by a "Moving Average Filter", for further details see manual (Mirko Boin)

    • to be done: sinogramic filter based on filtering the 2D FFT sinogram, see C. Raven, Numerical removal of ring artifacts in microtomography, Rev. Sci. Instr. 69, no. 8 (1998)

  • Ring-artefacts type II (inadequateness of flatfield correction), Tafforeau filter on projections, to be done

  • Axis correction, in case of axis movement during tomographic scan (inadequateness of mechanics)
        DO_AXIS_CORRECTION=YES
        AXIS_CORRECTION_FILE="your_file"
        
    your_file has to be text-formated, a column of int values (number of rows == number of projections) defines a shift (pixel units) in x-direction for each projection used, a second column can be used to introduce corrections in the y-direction as well. The latter case includes shifting based on interpolating while only x-corrections are exactly performed. X-corrections are useful to realign mismatches after sample has been moved out and in beam for flatfield projections.

  • Median-Filter

    • relative conditioned, image-median(image) is used to determine wether filter should be applied or not
          DO_CCD_FILTER= YES
          CCD_FILTER = "CCD_Filter"
          CCD_FILTER_PARA={"threshold": 0.0005 } #filter condition
          

      Via the threshold parameter one can control how strong the filter works on the image, entering -1.0 means max filtering. The path to the compiled object can be set via

          CCD_FILTER_PATH="/"
          
      in case you are running into conflicting versions or want to try on your own. To be done: Parameter for chosing filter application for or after flatfield correction or both
    • absolute conditioned, same as above with new parameters FRAC and ABS to be used as

          DO_CCD_FILTER= YES
          CCD_FILTER = "CCD_FilterAbsRel"
          CCD_FILTER_PARA={"threshold": 0.0005, "FRAC": 1, "ABS": 1}
          
      with the path can be specified via
          CCD_FILTER_PATH="/"
          
      ABS=1 will use abs(median(image)) instead of median(image) while FRAC=1 toggles between comparing the threshold with a) abs(median(image))/abs(image) (case ABS=1) or b) median(image)/abs(image) (case ABS=0) and plain comparison of abs(median(image)) or median(image) with the given threshold

    • CCD_Filter_Min
      is a test plugin not to be used at all

how to use forward projection

input: volumes volume, output: projections

b)

Sample_Noisy Sample_DeNoise_2xMedian
noisy image
denoised by applying median twice


How to display the data:

2. Creating HST parameter file (if already done skip to next step)

paramter files for HST can be created with hst_master which is a Tru64 program, to run it log on an alpha machine, eg from nitomo1

ssh -X your_account@darling

and run

/chmi/nitomo1/bin/ESRF/hst_master_new

accept the "Conditions Of Use" and then select "Reconstruction Direct From Sinograms: NO" (reconstruction from sinograms at the time this manual is written is only possible with HST_SLAVE!). Then you are asked for the first data file image, use the browser to find your directory (eg /chmi/nitomo1/username/BESSY_session_date/sample_XYZ/radios) and select the first image in that folder (should be radio0000.edf) by plain clicking. The following screen appears (color palette can be different)

Select a region of interest (ROI) - first click activates, second click finalises - by drawing a rectangle. This ROI is used to crop the reconstruction area, the smaller the ROI the faster the reconstruction and less hard disc space is required. The next screen you have to select the last data file image by plain clicking and then onwards into the parameters, the first mask should look like this

and on the next one

the following parameters should be checked, the rest should be left unchanged,

After passing the parameters once again you have to select a ROI (see above) and afterwards the "180 degree rotation image file" (usually again the last image in your folder), if the selected image is displayed correctly click on YES and THEN for the last time select a region of interest (this time used to calculate the axis of rotation - principle: use center of mass from 0 degree and 180 degree image, in the middle you have the axis of rotation). Press ok on the next screen and on the last screen you can save the parameters to a file of your choice, it is recommended to use the suffix .par!

More experienced users can skip the graphical interface and create a parameter file directly by editing a file from a previous reconstruction. A parameter file for HST looks like this

! HST_SLAVE PARAMETER FILE

RECONSTRUCT_FROM_SINOGRAMS = NO

! Parameters defining the projection file series
FILE_PREFIX = /hmi/rack/Bessy_Okt03/alex_AlSi7_16wpTiH2_beh/radios/radio
NUM_FIRST_IMAGE =      0 ! No. of first projection file
NUM_LAST_IMAGE =    899 ! No. of last projection file
NUMBER_LENGTH_VARIES = NO
LENGTH_OF_NUMERICAL_PART =  4 ! No. of characters
FILE_POSTFIX = .edf
FILE_INTERVAL =      1 ! Interval between input files

! Parameters defining the projection file format
NUM_IMAGE_1 =    991 ! Number of pixels horizontally
NUM_IMAGE_2 =   1251 ! Number of pixels vertically
IMAGE_PIXEL_SIZE_1 =      3.59 ! Pixel size horizontally (microns)
IMAGE_PIXEL_SIZE_2 =      3.59 ! Pixel size vertically

! Parameters defining background treatment
SUBTRACT_BACKGROUND = NO ! No background subtraction
BACKGROUND_FILE = N.A.

! Parameters defining flat-field treatment
CORRECT_FLATFIELD = NO ! No flat-field correction
FLATFIELD_FILE = N.A.
FLATFIELD_CHANGING = N.A.
FF_PREFIX = N.A.
FF_NUM_FIRST_IMAGE = N.A.
FF_NUM_LAST_IMAGE = N.A.
FF_NUMBER_LENGTH_VARIES = N.A.
FF_LENGTH_OF_NUMERICAL_PART = N.A.
FF_POSTFIX = N.A.
FF_FILE_INTERVAL = N.A.

TAKE_LOGARITHM = NO

! Parameters defining experiment
ANGLE_BETWEEN_PROJECTIONS =    0.20000 ! Increment angle in degrees
ROTATION_VERTICAL = YES
ROTATION_AXIS_POSITION =       568 ! Position in pixels

! Parameters defining reconstruction
OUTPUT_SINOGRAMS = NO ! Output sinograms to files or not
OUTPUT_RECONSTRUCTION = YES ! Reconstruct and save or not
START_VOXEL_1 =     1  ! X-start of reconstruction volume
START_VOXEL_2 =     1 ! Y-start of reconstruction volume
START_VOXEL_3 =     210 ! Z-start of reconstruction volume
END_VOXEL_1 =    990 ! X-end of reconstruction volume
END_VOXEL_2 =    990 ! Y-end of reconstruction volume
END_VOXEL_3 =    210 ! Z-end of reconstruction volume
OVERSAMPLING_FACTOR =  4 ! 0 = Linear, 1 = Nearest pixel
ANGLE_OFFSET =  -5.000000 ! Reconstruction rotation offset angle in degrees
CACHE_KILOBYTES =   4096 ! Size of processor cache (L2) per processor (Kbytes)
SINOGRAM_MEGABYTES =    800 ! Maximum size of sinogram storage (megabytes)

! Parameters defining output file / format
OUTPUT_FILE = /hmi/rack/Bessy_Okt03/alex_AlSi7_16wpTiH2_beh/alex.vol

! Reconstruction program options
DISPLAY_GRAPHICS = NO ! No images

Section-by-Section description:

! HST_SLAVE PARAMETER FILE

RECONSTRUCT_FROM_SINOGRAMS = NO

toggles if input files are in radiographic style or as sinograms written, sinograms (at the time this manual was written) can only be used with hst_slave, not with PyHST

! Parameters defining the projection file series
FILE_PREFIX = /hmi/rack/Bessy_Okt03/alex_AlSi7_16wpTiH2_beh/radios/radio
NUM_FIRST_IMAGE =      0 ! No. of first projection file
NUM_LAST_IMAGE =    899 ! No. of last projection file
NUMBER_LENGTH_VARIES = NO
LENGTH_OF_NUMERICAL_PART =  4 ! No. of characters
FILE_POSTFIX = .edf
FILE_INTERVAL =      1 ! Interval between input files

widely self-explaining, "FILE_PREFIX" should be set to the path where you data image files are located plus "radio", the rest should be left unchanged as long as you use bam2hst to create EDF files. "FILE_INTERVAL" is necessary if you want to reconstruct quick&dirty, eg setting it to "2" makes hst recognizing only half of input files.

! Parameters defining the projection file format
NUM_IMAGE_1 =    991 ! Number of pixels horizontally
NUM_IMAGE_2 =   1251 ! Number of pixels vertically
IMAGE_PIXEL_SIZE_1 =      3.59 ! Pixel size horizontally (microns)
IMAGE_PIXEL_SIZE_2 =      3.59 ! Pixel size vertically

the first two values can be found in any of your EDF files (belonging to your current reconstruction) header - use head -c 1024 radio0000.edf to display header information and then Dim_1 = NUM_IMAGE_1 and Dim_2 = NUM_IMAGE_2, the image pixel size is the resolution used (usally something like 3.6, 5.5 or 11 microns) and can be found in your BAM headerfile, see "Scandx=..." [mm]

! Parameters defining background treatment
SUBTRACT_BACKGROUND = NO ! No background subtraction
BACKGROUND_FILE = N.A.

! Parameters defining flat-field treatment
CORRECT_FLATFIELD = NO ! No flat-field correction
FLATFIELD_FILE = N.A.
FLATFIELD_CHANGING = N.A.
FF_PREFIX = N.A.
FF_NUM_FIRST_IMAGE = N.A.
FF_NUM_LAST_IMAGE = N.A.
FF_NUMBER_LENGTH_VARIES = N.A.
FF_LENGTH_OF_NUMERICAL_PART = N.A.
FF_POSTFIX = N.A.
FF_FILE_INTERVAL = N.A.

can be left unchanged as long as BAM software as well as bam2hst is used, the flatfield and dark correction is already applied there

TAKE_LOGARITHM = NO

should be left unchanged, the logarithm is taken by bam2hst, in some cases it might be helpful to take the logarithm twice in order to improve the contrast but it can also lead to unexpectable errors

! Parameters defining experiment
ANGLE_BETWEEN_PROJECTIONS =    0.20000 ! Increment angle in degrees
ROTATION_VERTICAL = YES
ROTATION_AXIS_POSITION =       568 ! Position in pixels

"ANGLE_BETWEEN_PROJECTIONS" usually is 180 / number_of_projections and can also be found in your BAM headerfile, see "WinkelIncr=...", the "ROTATION_VERTICAL" is always "YES", the "ROTATION_AXIS_POSITION" can be determined with hst_master (see above), during the measurements, by running /hmi/bin/center_of_image -fit in the directory where your EDF files are stored and/or later (should always be) optimised by hand (see below)

! Parameters defining reconstruction
OUTPUT_SINOGRAMS = NO ! Output sinograms to files or not
OUTPUT_RECONSTRUCTION = YES ! Reconstruct and save or not
START_VOXEL_1 =     1  ! X-start of reconstruction volume
START_VOXEL_2 =     1 ! Y-start of reconstruction volume
START_VOXEL_3 =     210 ! Z-start of reconstruction volume
END_VOXEL_1 =    990 ! X-end of reconstruction volume
END_VOXEL_2 =    990 ! Y-end of reconstruction volume
END_VOXEL_3 =    210 ! Z-end of reconstruction volume
OVERSAMPLING_FACTOR =  4 ! 0 = Linear, 1 = Nearest pixel
ANGLE_OFFSET =  -5.000000 ! Reconstruction rotation offset angle in degrees
CACHE_KILOBYTES =   4096 ! Size of processor cache (L2) per processor (Kbytes)
SINOGRAM_MEGABYTES =    800 ! Maximum size of sinogram storage (megabytes)

"OUTPUT_SINOGRAMS" can be used to create sinograms instead of using bam2hst or xdisp but only works with hst_slave, not with PyHST (sinograms will be stored in EDF format (1024 byte textheader plus binary data) and can be displayed with ImageJ); "OUTPUT_RECONSTRUCTION" should always be set to "YES" (otherwise no data will be saved), "START_VOXEL_..." and "END_VOXEL_..." defining the 3D region of interest (see below), the "ANGLE_OFFSET" is explained in detail in the next step and the rest should be left unchanged

! Parameters defining output file / format
OUTPUT_FILE = /hmi/rack/Bessy_Okt03/alex_AlSi7_16wpTiH2_beh/alex.vol

the file where the reconstructed data should be written to, please use the suffix .vol !

! Reconstruction program options
DISPLAY_GRAPHICS = NO ! No images

should be set per default to no.

The latest generation of PyHST understands some more parameters which are listed here .

Eg a Median filter can be used (only with PyHST) by adding the following lines to your parameter file


#konditionaler Medianfilter
DO_CCD_FILTER= YES
CCD_FILTER = "CCD_Filter"
CCD_FILTER_PARA={"threshold": 0.0005 } #Bedingung/Schwellwert

Via the threshold parameter one can control how strong the filter works on the image, entering -1.0 means max filtering. The path to the compiled object can be set via

CCD_FILTER_PARA ={}
in case you are running into conflicting versions or want to try on your own. To be done: Parameter for chosing filte application for or after flatfield correction or both

3. Reconstruction (if already done skip to next step)

Before reconstructing a whole volume the parameter file delivered by hst_master (or self-done) has to be checked and optimised.

Please keep in mind that calculation time and resources are and always will be limited, specially on our Linux machines nitomo... which should be dedicated mostly to 3d image analysis. Therefore try to use as much as possible the HMI alpha-cluster darling (see DV pages for more details) or other machines available. Only the first node of darling is accessable via a shell (eg ssh -X darling). Single slices always can be calculated there, if the load factor on darling0 is high (check with top or uptime) it is recommended that long reconstructions are done on higher knodes using the prun program (see DV pages or enter man prun).

The fastest way for optimising is to work on a single slice only. The number of slices available is equal to the "NUM_IMAGE_2" value in your parameter file. Chose the middle slice by setting "START_VOXEL_3 = END_VOXEL_3 = NUM_IMAGE_2 / 2", the parameter file is in textformat and can be edited with (x)emacs, vi, kwrite, kate etc.

To reconstruct on nitomo1 use the following syntax

/hmi/bin/ESRF/PyHST your_parameter_file 2 FLOAT

here "2" means the number of parallel threads to be used on one machine (2 is the recommended value if you are the only one working on a dual-cpu machine, otherwise chose 1) and "FLOAT" is the arithmetic to be used (currently on Linux-PyHST only FLOAT is available, on SUN-PyHST only INT is available).

To reconstruct on darling, nacha or any other alpha-machine use

/chmi/nitomo1/bin/ESRF/hst_slave_v30 your_parameter_file

The resulting data is saved in the file specified with the "OUTPUT_FILE" parameter in raw/binary format as FLOAT 4byte values. Additionally a file *.vol.info is created where the file dimensions can be found. To view the file enter less your_file.vol.info ! (Do not try to display binary data with the less program, it might reset your terminal!)

To display the calculated slices (compareable to displaying EDF files) enter cd /hmi/ImageJ and ./run then use FILE -> IMPORT -> RAW and select the file to display, then enter the following import information:

ImageType: 32bit REAL
WIDTH: xdim_of_info_file (see below)
HEIGHT: ydim_of_info_file (see below)
Offset to First Image: 0
Number Of Images: 1  (can be higher if you calculated more than one slice)
Gap: 0
White is Zero: disabled
Little Endian: enabled
Open All Files: disabled
the x and y dimensions are the ones from the info file (NUM_X and NUM_Y values).

0) create a sinogram

The first step which has to be done before any other is to create a sinogram. Mostly all errors which can happen can be detected by checking the sinogram! So please enter the directory with your radiographic EDF files and run

/hmi/bin/sinomaker

the program widely parametrises itself! An xv is automatically opened when the sinogram has been created.

PLEASE NOTE THAT FROM NOW ON NO LONGER USER-SUPPORT IS GIVEN BY RECONSTRUCTION PROBLEMS IF YOU ARRIVE WITHOUT sinogramIC SAMPLE IMAGE IN YOUR HANDS!!!

a) optimise axis of rotation

Can be done straight-forward: hst_master delivers an axis_of_rotation value based on center of mass calculation. If you do not want to use hst_master a good estimate is always the middle of your radiogramm (NUM_IMAGE_1 / 2). A very good estimate for the axis of rotation (error usually in the range of one pixel) is calculated by running /hmi/bin/center_of_image -fit in the folder where your corresponding EDF files are stored. The latter program takes the first image (0 degree rotation) and last image (180 degree rotation), mirrors vertically the last image and calculates the L2-norm of the difference (first minus last) image. The horizontal shift of the last image is introduced as parameter - a (1,10) evolution strategy fits this shift value to the minimal L2-norm. The resulting shift value is used to calculate the axis of rotation. An uncertainness of one pixel remains due to possible rounding errors. The program widely parametrises itself! Depending on the image size and how tricky it is for the program to find the minimal value the calculation time can be up to 20 minutes.

So do the reconstruction and display the result, an example for a completely wrong axis of rotation (210 pixels away from the correct value) is displayed in the following image

You probably recognise the semi circle artefacts (180 degree scan, for 360 degree the semi circles become full circles) which are the main characterisation for a wrong axis of rotation. The aim is first to decrease the diameter of the artefacts: with big steps for huge artefacts and small steps for little artefacts as displayed in the next image

Here the axis of rotation is only 10 pixels away from the correct value, the artefacts' diameter is much smaller, if you step to far (over the minimum) by varying the axis of rotation value one can notice an inversion of the semi circles' orientation, see here

If you already come close to that point it is the best way to change the axis of rotation value only one pixel, calculate and make a whole serie around that minimum you found. Display all the slices on one screen and select the best with the eye, in this case it looks like this

Please use the same contrast setting for all images of your serie (in ImageJ use CTRL+SHIFT+C to enter the contrast menu, chose "Set" and then enter corresponding MIN_VALUE and MAX_VALUE, use the same MIN_VALUE and MAX_VALUE for each new image you have created).

b) optimise angle offset

The "ANGLE_OFFSET" has to be optimised before a best crop (min. volume) can be done! Shifting the offset to positive values rotates the sample counterclockwise, shifting it to negative values rotates clockwise. Result of optimal "ANGLE_OFFSET" is shown below.

c) crop/region of interest (ROI)

"START_VOXEL_..." and "END_VOXEL_..." defining the 3D region of interest and should be set to values which minimize the volume to be reconstructed (in order to save calculation time and hard disc space). A good tool again is ImageJ: import a slice and with the xy-coordinate display the values for optimal cropping can be calculated.

d) check and reconstruct

Make sure your region of interest is not to small (eg in cases when your sample is not parallel or not 100% vertical within the image, one can easily check that by looking at the radiographic images) - try to reconstruct the first, middle and last slice. Did you save sample slice(s)? Did you have a look at at least one sinogram? Did you save one or two sinograms and radiographs in JPG?

To reconstruct on nitomo1 use the following syntax

/hmi/bin/ESRF/PyHST your_parameter_file 2 FLOAT &

here "2" means the number of parallel threads to be used on one machine (2 is the recommended value) and "FLOAT" is the arithmetic to be used (currently on Linux-PyHST only FLOAT is available, on SUN-PyHST only INT is available). The "&" makes your program work in background which means it will continue working even your terminal dies or you when you do a logout.

To reconstruct on darling, nacha or any other alpha-machine use

/chmi/nitomo1/bin/ESRF/hst_slave_v30 your_parameter_file &

when you are finished with the reconstruction do not forget to remove your EDF files to lower hard disc consumption

e) vgstudiomax and AVS

A powerful rendering tool for displaying 3d data sets is Visual Graphics Studio - currently it is only accessable on nitomo2 (32bit) and nitomo3 (64bit). Start it by entering vgstudiomax in any directory on nitomo2/3. On nitomo2 files with a size up-to 2GB can be loaded (if your 3d image is sized in the range of 2GB ... 4GB you have to work with image stacks), one thread can use up to 4 GB. On nitomo3 the filesize and usable memory is only limited by the available system memory.

To import a (float 4byte) volume select FILE -> IMPORT -> RAW Volume and browse to your volume file which you like to display and then with NEXT to the Data Type interface:

  • 32bit FLOAT
  • binary
  • LittleEndian (if clickable, otherwise skip)

with NEXT to the Size interface, enter the dimensions which you find in the *vol.info file (less your_file.vol.info -> values NUM_X, NUM_Y, NUM_Z), the header is 0 for all HST and cutvol files.

On the next interface "Load As" you should click the preview button to check if your entered dimensions are ok. If you are not happy with the color range map (eg all the tomograph is white or black) try to play with the histogram values, a good estimate is always the intervall between 0 and 15.

On the next interface one can define a region of interest, please make sure that the memory required for loading your image is available (indicated at the bottom of the interface, green: ok, red: memory alert - out of memory).

Press again NEXT and FINISH! to start the loading process.

A complete development language for 3d images is also available called AVS. It is accessable on any Unix machine whithin the HMI intranet (Linux or Tru64) but the number of licenses available at one time is limited to 5 (license server).

For any volume file which you want to import a so called FLD file has to be created which is basically a headerfile in textformat which has to look like this

# AVS field file
# CREATOR: Alexander Rack
# DESCRIPTION: testz
# TYPE: 1
# SPACING: 5.000000e-06 5.000000e-06 5.000000e-06
# HISTORY: (null)
#
ndim=3   			 # number of dimensions in the field
dim1=687 			 # dimension of axis 1
dim2=717 			 # dimension of axis 2
dim3=50 			 # dimension of axis 3
nspace=3 			 # number of physical coordinates per point
veclen=1 			 # number of components at each point
data=byte 			 # data type (byte,integer,float,double)
field=uniform 			 # field type (uniform, rectilinear, irregular)
variable 1 file = 247.vol filetype=binary

Start it by entering start_express -nohw in any directory. Create a new application FILE -> New Application ("Multi-Window DataView" and "3D" should be enabled, rest disabled). Drag&Drop "ReadField" (DataImport folder) and "VolumeRender" (Visualization folder) in your application and connect the tools with the mouse, the result should look like this

In "MultiWindowApp" with the module "ReadField" you can import your volume file with browsing and selecting your FLD file. The result is displayed in the "Scene" window. Select the module "VolumeRender" to manipulate rendering etc. For more help and information see the detailed AVS online help.

4. Histograms and char-volumes

The volume files done by PyHST or hst_slave are binary files, each voxel value is saved as FLOAT 4byte. 3d image analysis programs as well as rendering tools work with grey-scaled char 1byte data sets (which also helps lowering RAM and hard disc space consumption).

The first step for converting a FLOAT volume to a CHAR volume is creating a so called histogram, a plot of the voxel count vs. attenuation coefficients. Enter the directory with your volume file and then on nitomo1

/hmi/bin/ESRF/volStat your_volume_file > your_file_histogram

on any other Linux machine (nihaibel etc)

/chmi/nitomo1/bin/ESRF/volStat your_volume_file > your_file_histogram

or on any Tru64 machine (darling, nacha etc)

/chmi/nitomo1/bin/ESRF/volStat_alpha your_volume_file > your_file_histogram

The histograms can be plotted with "Origin" (Windows) or "xmgrace" (Unix) - both programs have an easy-to-use graphical interface. A bit quicker is to use gnuplot (Unix), start it by entering

gnuplot

and then

se lo y

pl "your_file_histogram"

You can save the file to postscript with

se te po

se ou "your_file.ps"

pl "your_file_histogram"

Leave the program with exit. A typical results looks like this

As you can see clearly the range where the voxel count function lives is the intervall [-10,70], so it is ok to project only these FLOAT 4byte values on the CHAR 1byte intervall [0, 255] (whole-numbered!!!). The idea is to identify the CHAR 1byte "0" value with the "-10" FLOAT 4byte. The "255" is then equal to "70" and all the whole-numbered values in between 0 and 255 are equal to ((70 - (-10) ) / 256)*whole_numbered_value . This of course leads to a reduction/loss of information.

This projection on CHAR 1byte is done with 2uchar, on nitomo1

/hmi/bin/ESRF/2uchar input.vol input.Nmin_abs_coeffXmax_abs_coeff.vol 0 min_abs_koeff max_abs_koeff

on any other Linux machine (nihaibel ...)

/chmi/nitomo1/bin/ESRF/2uchar input.vol input.Nmin_abs_coeffXmax_abs_coeff.vol 0 min_abs_koeff max_abs_koeff

on any other Tru64 machine (darling, nacha ...)

/chmi/nitomo1/bin/ESRF/2uchar_alpha input.vol input.Nmin_abs_coeffXmax_abs_coeff.vol 0 min_abs_koeff max_abs_koeff

Note:

One check you should do is if the noise is oversampled. Load one slice with ImageJ and select an area with no absorption (pore, vacuum etc - use area tools rectangle, circle etc). Select ANALYZE -> SET MEASUREMENTS and enable "Standard Deviation" -> OK. Now ANALYZE -> MEASURE, the "StdDev" value shoud be bigger than (max_abs_coeff - min_abs_coeff)/256 !

The CHAR 1byte volume files can be rendered with Visual Graphics Studio as well as AVS - just keep in mind to use 1byte CHAR instead of 4byte FLOAT as importing parameter.

when you are finished with the converting to char do not forget to remove your FLOAT volume files to lower hard disc consumption

Last updated: March 2006, Alexander Rack