.. include:: texenv.txt

Building a dictionary
======================

This tutorial explains how to generate a dictionary required by PyHST2 when using the Dictionary-based reconstruction method.
A typical use case is when you have a high quality reconstructed slice of a sample, and you want to perform low-dose scans on similar samples afterwards.
The dictionary will capture the essential features of the high-quality slice, and will be used to reconstruct other volumes.


Installing ksvd
----------------

You first need to install ``ksvd``, a Python script which generates a patches file from a slice/volume.
In this tutorial, the directory **/home/myself/software/ksvd** is used as an example.

First download and compile ksvd :

.. code-block:: bash

    mkdir software/ksvd
    cd software/ksvd
    export KSVD_DIR=$(pwd)
    git clone http://gitlab.esrf.fr/mirone/ksvd
    cd ksvd
    python setup.py install --prefix=$KSVD_DIR

Then, set the environment variables. This has to be done each time you want to run ksvd.

.. code-block:: bash

    export PATH=$PATH:$KSVD_DIR/bin
    export PYTHONPATH=$PYTHONPATH:$KSVD_DIR/lib/python2.7/site-packages/


Running ksvd
-------------

Do not forget to set the environment variables :

.. code-block:: bash

    export PATH=$PATH:/home/myself/software/ksvd/bin
    export PYTHONPATH=$PYTHONPATH:/home/myself/software/ksvd/lib/python2.7/site-packages/


The syntax is ``ksvd input_file.yaml``. You need :
    * An input file
    * A slice or volume from which the patches will be built


Input file format for a slice
-------------------------------

``ksvd`` uses an input file format in the ``.yaml`` format. Suppose you have a (good quality) slice (in EDF or vol format) ``myslice.edf`` from which you want to build the dictionary patches.
A basic input file will be :

.. code-block:: python

    patchwidth: 8
    NPURSUIT:    4
    n_comps:   200
    nitersksvd:  5
    files:
     - !ImageFile
        START_X: 0
        END_X: 100000
        START_Y: 0
        END_Y: 100000
        VAL_MIN: -1.0e+30   # no constraints
        VAL_MAX: +1.0e+30   # no constraints
        FILE_TYPE: edf
        FILE:  myslice.edf
        DERIVATIVES: 0
        N_PATCHES: 40000

This example produces a dictionary of 200 :math:`8 \times 8` patches.

You can build the patches from a region of interest with the parameters ``START_X``, ``END_X``, ``START_Y``, ``END_Y``.
If the entire slice is used, you can set these parameters to a huge value.

You can also discard values outsides of the range ``[VAL_MIN, VAL_MAX]``.


Input file format for a volume
-------------------------------

The input file for a vomume is slightly different. A example of file building patches on the volume ``myvol.vol`` is the following :

.. code-block:: python

    patchwidth: 8
    NPURSUIT:    4
    n_comps:   200
    nitersksvd:  5

    files:
     - !VolumeFile
        START_X: 600
        END_X: 1428
        START_Y: 600
        END_Y: 1333
        START_Z: 31
        END_Z: 51
        VDIMX: 2048
        VDIMY: 2048
        VDIMZ: 81
        VAL_MIN: 0.1
        VAL_MAX: 0.29
        FILE_TYPE: vol
        FILE:  myvolume.vol
        DERIVATIVES: 0
        N_PATCHES: 40000


In this example, 200 :math:`8 \times 8` patches are generated from the region of interest :math:`[600, 1428] \times [600, 1333]`. The slices 31 to 51 are used in the volume.
The parameters ``VDIMX, VDIMY, VDIMZ`` specify the total dimensions of the volume.


Input file format for vectorial patches
----------------------------------------

The Dictionary-based reconstruction can exploit the 3D correlation within the volume (instead of the 2D correlation in a slice).
To do so, the patches need to be three-dimensional (hence they have to be learned on a volume).

The following example generates 300 patches of size :math:`8 \times 8 \times 3`. This means that in the reconstruction, the slice will be reconstructed by groups of 3.
Here, the provided volume has 7 slices, which is enough for this example.

.. code-block:: python

    patchwidth: 8
    NPURSUIT:    4
    n_comps:   300
    nitersksvd:  5
    patch_eight: 3

    files:
     - !VolumeFile
        START_X: 0
        END_X: 1163
        START_Y: 879
        END_Y: 1333
        START_Z: 0
        END_Z: 6
        VDIMX: 2048
        VDIMY: 2048
        VDIMZ: 7
        VAL_MIN: -1000.0
        VAL_MAX: 1000.0
        FILE_TYPE: vol
        FILE:  myvol.vol
        DERIVATIVES: 0
        N_PATCHES: 40000









Input file for differential phase contrast
-------------------------------------------

PyHST2 has a reconstruction mode for differential phase contrast (eg. analyzer-based phase contrast).
In this case, each line of the sinogram is multiplied by :math:`\cos(\theta)` and :math:`\sin(\theta)`, which gives two sinograms, and eventually two slices.
The slice corresponding to the :math:`\cos (\theta)` component will be reconstructed with a set of patches, while the slice corresponding to the component  :math:`\sin (\theta)` will be resconstructed with another set of patches.

Thus, the dictionary contains patches with *two components*. To build this kind of patches, the option to set is

.. code-block:: python

    DERIVATIVES: 1


Visualizing the patches
------------------------

You can also visualize the patches. In the directory where your patches file is located, just type

.. code-block:: bash

    ksvd

(without arguments), and then provide the name of the patches file when prompted.


A common error
---------------

If you do not have the version 5 of PyMca, you will get the following error :

.. code-block:: python

    Traceback (most recent call last):
      File "/home/myself/software/ksvd/bin/ksvd", line 3, in <module>
        import ksvd.ksvd
      File "/home/myself/software/ksvd/lib/python2.7/site-packages/ksvd/ksvd.py", line 7, in <module>
        from PyMca5.PyMcaIO import EdfFile
    ImportError: No module named PyMca5.PyMcaIO

You need to modify the lines 7-8 of the file ``/home/myself/software/ksvd/lib/python2.7/site-packages/ksvd/ksvd.py``.
The lines

.. code-block:: python

    from PyMca5.PyMcaIO import EdfFile
    #from PyMca import EdfFile

should be

.. code-block:: python

    #from PyMca5.PyMcaIO import EdfFile
    from PyMca import EdfFile


