Image normalization

This example is part of the processing performed during a "Fullfield XANES" experiment at ESRF-ID21 and described in this article: http://iopscience.iop.org/1742-6596/425/19/192001/pdf/1742-6596_425_19_192001.pdf

During this experiement, radiographs of a sample are taken at various energies. As the full beam is used, on should divide the signal by the flat-field image, both corrected for the dark current of the CCD.

![setup](setup.png)

src="files/setup.png">

For an optimal use of the dynamic range, the data frame has a longer exposure time than the flat-field frame. Exposure time is recorded in the header of the file. Each frame needs to be corrected for the correct dark (with the same exposure time).

There are three dark-current files: dark-2.edf, dark-3 and dark-6.edf, two flat-field taken before and after the experiment and a raw data frame in the directory. Correct the image the image for the dark and flat-field effect. Check the correctness of your results often with "imshow" ...

Exercise:

  • Read all 6 EDF files and find their exposure time
  • Correct the data and flat-field images for their respective dark-current images
  • Average the two flat-field images
  • Correct the data from the flat-field effect

Solution

Initialization of the scientific environment


In [1]:
%pylab inline


Populating the interactive namespace from numpy and matplotlib

In [2]:
import fabio

Load all images


In [3]:
ls *.edf


dark-2.edf  dark-3.edf  dark-6.edf  flat-1.edf  flat-2.edf  raw.edf

In [4]:
dark2 = fabio.open("dark-2.edf")
dark3 = fabio.open("dark-3.edf")
dark6 = fabio.open("dark-6.edf")
flat1 = fabio.open("flat-1.edf")
flat2 = fabio.open("flat-2.edf")
raw = fabio.open("raw.edf")
print(raw.header)


{'exposure_time': '6', 'time_of_frame': '4.146026', 'time_of_day': '1292520991.838942', 'HeaderID': 'EH:000001:000000:000000', 'Image': '0', 'DataType': 'SignedInteger', 'acq_frame_nb': '0', 'ByteOrder': 'LowByteFirst', 'time': 'Thu Dec 16 18:36:31 2010', 'Dim_1': '2048', 'Dim_2': '2048', 'energy': '4.99', 'Size': '16777216'}

In [5]:
for edf in (dark2, dark3, dark6, flat1, raw):
    print("%s : %s"%(edf.filename,edf.header["exposure_time"]))


dark-2.edf : 2
dark-3.edf : 3
dark-6.edf : 6
flat-1.edf : 3
raw.edf : 6

In [6]:
imshow(raw.data)
print(raw.data.dtype)


int32

In [7]:
imshow(flat1.data)
print(flat1.data.dtype)


int32

Important note: check the data-type of your data as well: intergers are very bad for calculation due to over/under-flow.

Dark-current correction

Convert the data-type for the calculation in float.


In [8]:
raw_dc = raw.data.astype(float) - dark6.data
flat1_dc = flat1.data.astype(float) - dark3.data
flat2_dc = flat2.data.astype(float) - dark3.data
print(raw_dc.dtype)
imshow(raw_dc)


float64
Out[8]:
<matplotlib.image.AxesImage at 0x7f09ac17ced0>

Average out the flat-field images


In [9]:
flat = (flat1_dc + flat2_dc)/2.0
imshow(flat)


Out[9]:
<matplotlib.image.AxesImage at 0x7f09ac0a1ed0>

Perform the flat-field correction (weighted by exposure time)


In [10]:
corr = raw_dc / flat / 2.0
imshow(corr)


Out[10]:
<matplotlib.image.AxesImage at 0x7f09ac043f90>

Why was it so important to calculate with floats ?


In [11]:
int_corr = (raw.data - dark6.data ) / (flat1.data + flat2.data - 2*dark3.data)
print(int_corr)
print(int_corr.max())


[[0 0 0 ..., 0 0 0]
 [0 0 0 ..., 0 0 0]
 [0 0 0 ..., 0 0 0]
 ..., 
 [0 0 0 ..., 0 0 0]
 [0 0 0 ..., 0 0 0]
 [0 0 0 ..., 0 0 0]]
1

In [12]:
imshow(int_corr)


Out[12]:
<matplotlib.image.AxesImage at 0x7f09abf68ed0>

In [ ]: