From 57b81fd1fe64cac63194386b383d40707e5bbdf0 Mon Sep 17 00:00:00 2001 From: Edoardo Pasca Date: Fri, 21 Jun 2019 22:22:42 +0100 Subject: Reorganise processors (#24) * add test phase * updated test * removed unused import * updated test --- .../plugins/processors/AcquisitionDataPadder.py | 116 +++++++++++++++++++++ .../Python/ccpi/plugins/processors/__init__.py | 2 +- Wrappers/Python/conda-recipe/meta.yaml | 15 ++- Wrappers/Python/test/__init__.py | 0 Wrappers/Python/test/test_Processors.py | 55 ++++++++++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100755 Wrappers/Python/ccpi/plugins/processors/AcquisitionDataPadder.py create mode 100644 Wrappers/Python/test/__init__.py create mode 100755 Wrappers/Python/test/test_Processors.py diff --git a/Wrappers/Python/ccpi/plugins/processors/AcquisitionDataPadder.py b/Wrappers/Python/ccpi/plugins/processors/AcquisitionDataPadder.py new file mode 100755 index 0000000..4033c7b --- /dev/null +++ b/Wrappers/Python/ccpi/plugins/processors/AcquisitionDataPadder.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 30 13:43:52 2019 + +@author: ofn77899 +""" +from ccpi.framework import DataProcessor, DataContainer, AcquisitionData,\ + AcquisitionGeometry, ImageGeometry, ImageData +from ccpi.reconstruction.parallelbeam import alg as pbalg +import numpy + +class AcquisitionDataPadder(DataProcessor): + '''Normalization 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: AcquisitionDataSetn + ''' + + def __init__(self, + center_of_rotation = None, + acquisition_geometry = None, + pad_value = 1e-5): + kwargs = { + 'acquisition_geometry' : acquisition_geometry, + 'center_of_rotation' : center_of_rotation, + 'pad_value' : pad_value + } + + super(AcquisitionDataPadder, self).__init__(**kwargs) + + def check_input(self, dataset): + if self.acquisition_geometry is None: + self.acquisition_geometry = dataset.geometry + if dataset.number_of_dimensions == 3: + return True + else: + raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ + .format(dataset.number_of_dimensions)) + + def process(self, out=None): + projections = self.get_input() + w = projections.get_dimension_size('horizontal') + print ("horizontal ", w) + delta = w - 2 * self.center_of_rotation + + padded_width = int ( + numpy.ceil(abs(delta)) + w + ) + delta_pix = padded_width - w + + voxel_per_pixel = 1 + geom = pbalg.pb_setup_geometry_from_acquisition(projections.as_array(), + self.acquisition_geometry.angles, + self.center_of_rotation, + voxel_per_pixel ) + + print ("geom", geom) + padded_geometry = self.acquisition_geometry.clone() + + padded_geometry.pixel_num_h = geom['n_h'] + padded_geometry.pixel_num_v = geom['n_v'] + + delta_pix_h = padded_geometry.pixel_num_h - self.acquisition_geometry.pixel_num_h + delta_pix_v = padded_geometry.pixel_num_v - self.acquisition_geometry.pixel_num_v + + if delta_pix_h == 0: + delta_pix_h = delta_pix + padded_geometry.pixel_num_h = padded_width + #initialize a new AcquisitionData with values close to 0 + out = AcquisitionData(geometry=padded_geometry) + out = out + self.pad_value + + + #pad in the horizontal-vertical plane -> slice on angles + if delta > 0: + #pad left of middle + command = "out.array[" + for i in range(out.number_of_dimensions): + if out.dimension_labels[i] == 'horizontal': + value = '{0}:{1}'.format(delta_pix_h, delta_pix_h+w) + command = command + str(value) + else: + if out.dimension_labels[i] == 'vertical' : + value = '{0}:'.format(delta_pix_v) + command = command + str(value) + else: + command = command + ":" + if i < out.number_of_dimensions -1: + command = command + ',' + command = command + '] = projections.array' + #print (command) + else: + #pad right of middle + command = "out.array[" + for i in range(out.number_of_dimensions): + if out.dimension_labels[i] == 'horizontal': + value = '{0}:{1}'.format(0, w) + command = command + str(value) + else: + if out.dimension_labels[i] == 'vertical' : + value = '{0}:'.format(delta_pix_v) + command = command + str(value) + else: + command = command + ":" + if i < out.number_of_dimensions -1: + command = command + ',' + command = command + '] = projections.array' + #print (command) + #cleaned = eval(command) + exec(command) + return out diff --git a/Wrappers/Python/ccpi/plugins/processors/__init__.py b/Wrappers/Python/ccpi/plugins/processors/__init__.py index e688671..da13b98 100644 --- a/Wrappers/Python/ccpi/plugins/processors/__init__.py +++ b/Wrappers/Python/ccpi/plugins/processors/__init__.py @@ -1,4 +1,4 @@ from .processors import setupCCPiGeometries from .processors import CCPiForwardProjector from .processors import CCPiBackwardProjector -from .processors import AcquisitionDataPadder +from .AcquisitionDataPadder import AcquisitionDataPadder diff --git a/Wrappers/Python/conda-recipe/meta.yaml b/Wrappers/Python/conda-recipe/meta.yaml index ab67b0c..c9126d4 100644 --- a/Wrappers/Python/conda-recipe/meta.yaml +++ b/Wrappers/Python/conda-recipe/meta.yaml @@ -8,7 +8,20 @@ build: script_env: - CIL_VERSION # number: 0 - +test: + requires: + - python-wget + - cvxpy # [ unix and py36 and np115 ] + + source_files: + - ./test # [win] + - ./ccpi/Wrappers/Python/test # [not win] + + commands: + - python -c "import os; print (os.getcwd())" + - python -m unittest discover # [win] + - python -m unittest discover -s ccpi/Wrappers/Python/test # [not win] + requirements: build: - python diff --git a/Wrappers/Python/test/__init__.py b/Wrappers/Python/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Wrappers/Python/test/test_Processors.py b/Wrappers/Python/test/test_Processors.py new file mode 100755 index 0000000..0c43126 --- /dev/null +++ b/Wrappers/Python/test/test_Processors.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 30 14:39:20 2019 + +@author: ofn77899 +""" + +import sys +import unittest +import numpy +from ccpi.framework import DataProcessor +from ccpi.framework import DataContainer +from ccpi.framework import ImageData +from ccpi.framework import AcquisitionData +from ccpi.framework import ImageGeometry +from ccpi.framework import AcquisitionGeometry +from timeit import default_timer as timer +from ccpi.io.reader import NexusReader +from ccpi.processors import CenterOfRotationFinder +from ccpi.plugins.processors import AcquisitionDataPadder +import wget +import os +import math + +class TestDataProcessor(unittest.TestCase): + def setUp(self): + wget.download('https://github.com/DiamondLightSource/Savu/raw/master/test_data/data/24737_fd.nxs') + self.filename = '24737_fd.nxs' + + def tearDown(self): + os.remove(self.filename) + + def test_AcquisitionDataPadder(self): + reader = NexusReader(self.filename) + ad = reader.get_acquisition_data_whole() + print (ad.geometry) + cf = CenterOfRotationFinder() + cf.set_input(ad) + print ("Center of rotation", cf.get_output()) + self.assertAlmostEqual(86.25, cf.get_output()) + + adp = AcquisitionDataPadder(acquisition_geometry=cf.get_input().geometry,center_of_rotation=cf.get_output(),pad_value=0) + adp.set_input(ad) + padded_data = adp.get_output() + print ("Padded data shape", padded_data.shape) + print (" " , padded_data.dimension_labels) + idx = None + for k,v in padded_data.dimension_labels.items(): + if v == AcquisitionGeometry.HORIZONTAL: + idx = k + + padded_axis = padded_data.shape[idx] + self.assertEqual(padded_axis , math.ceil(cf.get_output() * 2)) + numpy.save("pippo.npy" , padded_data.as_array()) + -- cgit v1.2.3