A. Software required: Python with Conda

Reference: https://uwdirect.github.io/software.html

1. Get Python with Conda

  1. Conda is a system for installing and managing packages and their dependencies. You can get Anaconda here: https://docs.anaconda.com/anaconda/install/ and follow the installation instructions.

  2. Go to the Anaconda prompt (just hit the windows button and search for Anaconda Prompt) and update conda's packages for your system by typing "conda update conda" into the terminal. Update suggested packages.

  3. Install Jupyter notebook and its requirements by typing "conda install jupyter" in the same terminal. IPython notebooks is nice for analyzing data and sharing analysis steps since there is access to Markdown and LaTex. If you've lots of code you want to edit, Spyder will be more ideal.

  4. Type "jupyter notebook" in the terminal. A "Home" page in your browser should open. You can close both by closing the tabs. Shut down the kernel by holding "Ctrl +c" within the Anaconda Prompt.

2. Get additional packages required: igor, dipy

Anaconda comes with many packages, but we need a couple more: igor so that we can read Igor Pro files from Python and dipy which is what we will use to register images.

  1. In the same Anaconda Prompt, type "pip install igor" so that you can read Igor Pro files from python.
  2. Then install Dipy by typing "conda install dipy -c conda-forge"
  3. Make sure you have igor and dipy. Type "conda list" to see all the packages you have installed.

B. Navigate to data folder and open a Jupyter Notebook

Typing "dir" in the Anaconda Prompt lists all files in the current directory. "cd" prints the current working directory. To change directories, type "cd" followed by the name of the folder. "cd .." navigates one directory up. For a list of possible commands, type "help."

  1. Make a folder and give it a name by typing mkdir followed by the name like "mkdir ImageAlignment" in the Anaconda Prompt.
  2. Chage to the new folder by typing "cd ImageAlignment"
  3. Now open a Jupyter Notebook by typing "jupyter notebook" and create a new notebook by clicking "New" and selecting Python 2 (or 3 if you installed Python 3) You can change the name of the Notebook by double clicking "Untitled."

C. Download, import, and load scripts and data.

The files you'll need to import are util and imagealignment. util contains functions for reading in files and imagealignment contains functions for flattening and aligning images. To do this type:

1. Get code for loading in igor files and doing image alignment.


In [1]:
#for igor files: 
!curl -o util.py https://raw.githubusercontent.com/kongjy/hyperAFM/master/hyperAFM/util.py
#for image alignment: 
!curl -o imagealignment.py https://raw.githubusercontent.com/kongjy/hyperAFM/master/hyperAFM/imagealignment.py

#the above will download the files at the specified URL and save them as the filenames specified after '-o'   
#curl stands for "see url." to learn more about curl see this page: 
#https://tecadmin.net/5-curl-commands-to-download-files/#


  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 15346  100 15346    0     0   120k      0 --:--:-- --:--:-- --:--:--  133k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  9771  100  9771    0     0   124k      0 --:--:-- --:--:-- --:--:--  130k

2. Get data (cAFM and SKPM images of a P3HT/PMMA blend) for this tutorial


In [2]:
#SKPM file: 
!curl -o SKPM.ibw https://raw.githubusercontent.com/kongjy/hyperAFM/master/Data/PolymerBlends/Image%20Alignment%20Tutorial/Film15SKPM_0000.ibw
#cAFM file:
!curl -o cAFM.ibw https://raw.githubusercontent.com/kongjy/hyperAFM/master/Data/PolymerBlends/Image%20Alignment%20Tutorial/Film15cAFM_1V_0001.ibw


  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1100k  100 1100k    0     0  4256k      0 --:--:-- --:--:-- --:--:-- 4368k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1108k  100 1108k    0     0  4279k      0 --:--:-- --:--:-- --:--:-- 4346k

3. Import relevant packages and data into the notebook.

Curl only downloads the files. To make use of the functions in those files, we need to import them into a notebook.


In [3]:
#packages to load in data and for image alignment 
from util import * #* means to import everything. 
from imagealignment import *

#to plot
import matplotlib.pyplot as plt
#display graphs/plots in notebook 
%matplotlib inline

In [4]:
#import data with load_ibw function in util 
SKPMfile=load_ibw('SKPM.ibw')
cAFMfile=load_ibw('cAFM.ibw')

The data is stored in n-dimensional arrays where n = # data channels. The first layer (i.e, layer 0) is topography, the second, third, etc are the same as when the files are opened in Igor. For the cAFM file, the layers are as follow:
0: topography
1: deflection
2: z sensor
3: current

For the SKPM file, the layers are as follow:
0: topography
1: amplitude
2: phase
3: potential retrace

Basic Image Visualization

We can use SKPMfile[:,:,0] to access the topography for the SKPM file. The first colon means that we will display all rows, the second means that we will display all columns.


In [5]:
fig=plt.imshow(SKPMfile[:,:,0])
plt.colorbar()


Out[5]:
<matplotlib.colorbar.Colorbar at 0x119c35d90>

Note that the image is unflattened. We can use the flatten function in the imagealignment file (which you can look at via spyder, textedit, notepad, or whatever you fancy.)


In [6]:
SKPMtopo_flattend=flatten(SKPMfile[:,:,0])
plt.imshow(SKPMtopo_flattend)
plt.colorbar()


Out[6]:
<matplotlib.colorbar.Colorbar at 0x11ad3bd90>

Here's how we can display the bottom, half of the 256x256 SKPM image


In [7]:
SKPM_bottomquarter=flatten(SKPMfile[128:,:,3])
plt.imshow(SKPM_bottomquarter)


Out[7]:
<matplotlib.image.AxesImage at 0x11af43bd0>

Image Registration with Affine Transformations

This tutorial follows the ideas in the example on the dipy website fairly closely. Take a look at the work by the pros here: http://nipy.org/dipy/examples_built/affine_registration_3d.html. Note that the functions I wrote are interfaces to those in dipy and are meant to make them a little more accessible. So, the functions they call explicitly will be different from those in this tutorial.

For more information about mutual information see this: https://link.springer.com/article/10.1023/A:1007958904918

1. Set up the mutual information metric with setup_mutualinformation, which will be used to evaluate how well we've aligned the images.


In [8]:
mutualinformation=setup_mutualinformation(nbins=32, sampling_prop=None)

See doc string for details on the parameters. Docstrings are embedded between three quotes in the raw imagealignment file. From here on out, please defer to docstrings for each function to learn more about the parameters (i.e, arguments) and their default settings.

2. Set up the affine transformation with setup_affine, which will be used to define the Gaussian Pyramid, smoothing, factors, and method used to optimize the transformation. (See docstring for info about the arguments in the function).


In [10]:
affreg=setup_affine(metric=mutualinformation, level_iters=None , sigmas=None, \
                 factors=None, method='L-BFGS-B')

3. Now that the affine registration is set up, we can start registering images with respect to translation in the x-, y- plane, rotation, scaling, etc with find_affine. Like the example on the dipy page, we'll optimize the registration with a transformation with the fewest degrees of freedom (like RotationTransform2D() or TranslationTransform2D()) and then refine it.)


In [11]:
cAFMtopo=flatten(cAFMfile[:,:,0])
SKPMtopo=flatten(SKPMfile[:,:,0])

In [13]:
translationtrans=find_affine(static=cAFMtopo, moving=SKPMtopo, affreg=affreg, \
                               transform=TranslationTransform2D(), params0=None, \
                              starting_affine=None)


Optimizing level 2 [max iter: 10000]
Optimizing level 1 [max iter: 1000]
Optimizing level 0 [max iter: 100]

You can apply the optimized translation transformation to the moving image, SKPMtopo, with apply_affine.


In [17]:
SKPMtopo_translated = apply_affine(moving=SKPMtopo, transformation=translationtrans)
plt.imshow(SKPMtopo_translated)


Out[17]:
<matplotlib.image.AxesImage at 0x11b34c390>

We can optimize the transformation with respect to translation and rotation by supplying the previously optimized translation transformation.


In [19]:
rigidtrans=find_affine(static=cAFMtopo, moving=SKPMtopo, affreg=affreg, \
                               transform=RigidTransform2D(), params0=None, \
                              starting_affine=translationtrans)
#a rigid transform is one that includes rotatons and translations


Optimizing level 2 [max iter: 10000]
Optimizing level 1 [max iter: 1000]
Optimizing level 0 [max iter: 100]

...and apply it to the original SKPM topo.


In [21]:
SKPMtopo_rigid=apply_affine(moving=SKPMtopo, transformation=rigidtrans)
plt.imshow(SKPMtopo_rigid)


Out[21]:
<matplotlib.image.AxesImage at 0x11b357210>

Do the same with the full affine transformation.


In [23]:
affinetrans=find_affine(static=cAFMtopo, moving=SKPMtopo, affreg=affreg, \
                               transform=AffineTransform2D(), params0=None, \
                              starting_affine=rigidtrans)
SKPMtopo_affine=apply_affine(moving=SKPMtopo, transformation=affinetrans)
plt.imshow(SKPMtopo_affine)


Optimizing level 2 [max iter: 10000]
Optimizing level 1 [max iter: 1000]
Optimizing level 0 [max iter: 100]
Out[23]:
<matplotlib.image.AxesImage at 0x11b6c4d10>

To register the cAFM with the SKPM image, you can apply it to the SKPM layer:


In [27]:
SKPM_transformed=apply_affine(moving=flatten(SKPMfile[:,:,3]), transformation=affinetrans)