# Copyright 2019 United Kingdom Research and Innovation# Copyright 2019 The University of Manchester## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.## Authors:# CIL Developers, listed at: https://github.com/TomographicImaging/CIL/blob/master/NOTICE.txtfromcil.frameworkimportProcessor,DataContainer,AcquisitionData,\
AcquisitionGeometry,ImageGeometry,ImageDataimportnumpy
[docs]classNormaliser(Processor):'''Normalisation based on flat and dark This processor read in a AcquisitionData and normalises it based on the instrument reading with and without incident photons or neutrons. Input: AcquisitionData Parameter: 2D projection with flat field (or stack) 2D projection with dark field (or stack) Output: AcquisitionDataSet '''def__init__(self,flat_field=None,dark_field=None,tolerance=1e-5):kwargs={'flat_field':flat_field,'dark_field':dark_field,# very small number. Used when there is a division by zero'tolerance':tolerance}#DataProcessor.__init__(self, **kwargs)super(Normaliser,self).__init__(**kwargs)ifnotflat_fieldisNone:self.set_flat_field(flat_field)ifnotdark_fieldisNone:self.set_dark_field(dark_field)defcheck_input(self,dataset):ifdataset.number_of_dimensions==3or\
dataset.number_of_dimensions==2:returnTrueelse:raiseValueError("Expected input dimensions is 2 or 3, got {0}"\
.format(dataset.number_of_dimensions))defset_dark_field(self,df):iftype(df)isnumpy.ndarray:iflen(numpy.shape(df))==3:raiseValueError('Dark Field should be 2D')eliflen(numpy.shape(df))==2:self.dark_field=dfelifissubclass(type(df),DataContainer):self.dark_field=self.set_dark_field(df.as_array())defset_flat_field(self,df):iftype(df)isnumpy.ndarray:iflen(numpy.shape(df))==3:raiseValueError('Flat Field should be 2D')eliflen(numpy.shape(df))==2:self.flat_field=dfelifissubclass(type(df),DataContainer):self.flat_field=self.set_flat_field(df.as_array())@staticmethoddefNormalise_projection(projection,flat,dark,tolerance):a=(projection-dark)b=(flat-dark)withnumpy.errstate(divide='ignore',invalid='ignore'):c=numpy.true_divide(a,b)c[~numpy.isfinite(c)]=tolerance# set to not zero if 0/0returnc
[docs]@staticmethoddefestimate_normalised_error(projection,flat,dark,delta_flat,delta_dark):'''returns the estimated relative error of the normalised projection n = (projection - dark) / (flat - dark) Dn/n = (flat-dark + projection-dark)/((flat-dark)*(projection-dark))*(Df/f + Dd/d) '''a=(projection-dark)b=(flat-dark)df=delta_flat/flatdd=delta_dark/darkrel_norm_error=(b+a)/(b*a)*(df+dd)returnrel_norm_error
defprocess(self,out=None):projections=self.get_input()dark=self.dark_fieldflat=self.flat_fieldifprojections.number_of_dimensions==3:ifnot(projections.shape[1:]==dark.shapeand \
projections.shape[1:]==flat.shape):raiseValueError('Flats/Dark and projections size do not match.')a=numpy.asarray([Normaliser.Normalise_projection(projection,flat,dark,self.tolerance) \
forprojectioninprojections.as_array()])elifprojections.number_of_dimensions==2:a=Normaliser.Normalise_projection(projections.as_array(),flat,dark,self.tolerance)y=type(projections)(a,True,dimension_labels=projections.dimension_labels,geometry=projections.geometry)returny