From 7e0eed804c0c5f614d340805ebc4fd8ce8a57b55 Mon Sep 17 00:00:00 2001 From: Davis Marc Vigneault Date: Fri, 8 May 2020 09:20:44 -0700 Subject: [PATCH 1/3] WIP: serialize NDArrayITKBase --- Modules/Bridge/NumPy/wrapping/PyBuffer.i.init | 15 +++ .../itkQuadEdgeMeshToQuadEdgeMeshFilter.h | 97 ++++++++++--------- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init index 892267faa54..18bf88a1ca7 100644 --- a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init +++ b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init @@ -15,6 +15,21 @@ try: if obj is None: return self.itk_base = getattr(obj, 'itk_base', None) + def __reduce_ex__(self, protocol): + if protocol >= 5: + return type(self)._reconstruct, (PickleBuffer(self),), None + else: + return type(self)._reconstruct, (bytearray(self),) + + @classmethod + def _reconstruct(cls, obj): + with memoryview(obj) as m: + # Get a handle over the original buffer object + obj = m.obj + print('within reconstruct') + print(cls, type(obj)) + if type(obj) is np.ndarray: return obj + else: return np.asarray(obj) except ImportError: HAVE_NUMPY = False diff --git a/Modules/Core/QuadEdgeMesh/include/itkQuadEdgeMeshToQuadEdgeMeshFilter.h b/Modules/Core/QuadEdgeMesh/include/itkQuadEdgeMeshToQuadEdgeMeshFilter.h index d0376eca007..c260a15cc58 100644 --- a/Modules/Core/QuadEdgeMesh/include/itkQuadEdgeMeshToQuadEdgeMeshFilter.h +++ b/Modules/Core/QuadEdgeMesh/include/itkQuadEdgeMeshToQuadEdgeMeshFilter.h @@ -150,7 +150,7 @@ CopyMeshToMeshCellData(const TInputMesh * in, TOutputMesh * out) InputCellDataContainerConstPointer inputCellData = in->GetCellData(); - if (inputCellData.IsNull()) + if (inputCellData == nullptr) { // There is nothing to copy return; @@ -223,28 +223,31 @@ CopyMeshToMeshCells(const TInputMesh * in, TOutputMesh * out) InputCellsContainerConstPointer inCells = in->GetCells(); - if (inCells) + if (inCells == nullptr) { - InputCellsContainerConstIterator cIt = inCells->Begin(); - InputCellsContainerConstIterator cEnd = inCells->End(); - while (cIt != cEnd) + // There is nothing to copy + return; + } + + InputCellsContainerConstIterator cIt = inCells->Begin(); + InputCellsContainerConstIterator cEnd = inCells->End(); + while (cIt != cEnd) + { + auto * pe = dynamic_cast(cIt.Value()); + if (pe) { - auto * pe = dynamic_cast(cIt.Value()); - if (pe) + InputPointIdList points; + InputPointsIdInternalIterator pIt = pe->InternalPointIdsBegin(); + InputPointsIdInternalIterator pEnd = pe->InternalPointIdsEnd(); + + while (pIt != pEnd) { - InputPointIdList points; - InputPointsIdInternalIterator pIt = pe->InternalPointIdsBegin(); - InputPointsIdInternalIterator pEnd = pe->InternalPointIdsEnd(); - - while (pIt != pEnd) - { - points.push_back((*pIt)); - ++pIt; - } - out->AddFaceWithSecurePointList(points, false); + points.push_back((*pIt)); + ++pIt; } - ++cIt; + out->AddFaceWithSecurePointList(points, false); } + ++cIt; } } @@ -261,20 +264,23 @@ CopyMeshToMeshEdgeCells(const TInputMesh * in, TOutputMesh * out) InputCellsContainerConstPointer inEdgeCells = in->GetEdgeCells(); - if (inEdgeCells) + if (inEdgeCells == nullptr) { - InputCellsContainerConstIterator ecIt = inEdgeCells->Begin(); - InputCellsContainerConstIterator ecEnd = inEdgeCells->End(); + // There is nothing to copy + return; + } + + InputCellsContainerConstIterator ecIt = inEdgeCells->Begin(); + InputCellsContainerConstIterator ecEnd = inEdgeCells->End(); - while (ecIt != ecEnd) + while (ecIt != ecEnd) + { + auto * pe = dynamic_cast(ecIt.Value()); + if (pe) { - auto * pe = dynamic_cast(ecIt.Value()); - if (pe) - { - out->AddEdgeWithSecurePointList(pe->GetQEGeom()->GetOrigin(), pe->GetQEGeom()->GetDestination()); - } - ++ecIt; + out->AddEdgeWithSecurePointList(pe->GetQEGeom()->GetOrigin(), pe->GetQEGeom()->GetDestination()); } + ++ecIt; } } @@ -293,25 +299,28 @@ CopyMeshToMeshPoints(const TInputMesh * in, TOutputMesh * out) InputPointsContainerConstPointer inPoints = in->GetPoints(); - if (inPoints) + if (inPoints == nullptr) { - InputPointsContainerConstIterator inIt = inPoints->Begin(); - InputPointsContainerConstIterator inEnd = inPoints->End(); + // There is nothing to copy + return; + } - OutputPointsContainerPointer oPoints = out->GetPoints(); - if (oPoints.IsNull()) - { - oPoints = OutputPointsContainer::New(); - out->SetPoints(oPoints); - } - OutputPointType pOut; + InputPointsContainerConstIterator inIt = inPoints->Begin(); + InputPointsContainerConstIterator inEnd = inPoints->End(); - while (inIt != inEnd) - { - pOut.CastFrom(inIt.Value()); - oPoints->InsertElement(inIt.Index(), pOut); - ++inIt; - } + OutputPointsContainerPointer oPoints = out->GetPoints(); + if (oPoints == nullptr) + { + oPoints = OutputPointsContainer::New(); + out->SetPoints(oPoints); + } + OutputPointType pOut; + + while (inIt != inEnd) + { + pOut.CastFrom(inIt.Value()); + oPoints->InsertElement(inIt.Index(), pOut); + ++inIt; } } } // end namespace itk From 6e20253491d1aa7ce5fc3ae639114d1adeb37131 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liu Date: Tue, 28 Jul 2020 16:17:24 -0400 Subject: [PATCH 2/3] ENH: Serialize/Deserialize NDArrayITKBase --- Modules/Bridge/NumPy/wrapping/PyBuffer.i.init | 17 ++++------ .../NumPy/wrapping/test/itkPyBufferTest.py | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init index 18bf88a1ca7..545e02e8d98 100644 --- a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init +++ b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init @@ -16,20 +16,15 @@ try: self.itk_base = getattr(obj, 'itk_base', None) def __reduce_ex__(self, protocol): - if protocol >= 5: - return type(self)._reconstruct, (PickleBuffer(self),), None - else: - return type(self)._reconstruct, (bytearray(self),) + np_copy = np.array(self, copy=True) + return type(self)._reconstruct, (np_copy,), None @classmethod def _reconstruct(cls, obj): - with memoryview(obj) as m: - # Get a handle over the original buffer object - obj = m.obj - print('within reconstruct') - print(cls, type(obj)) - if type(obj) is np.ndarray: return obj - else: return np.asarray(obj) + with memoryview(obj) as m: + obj = m.obj + if type(obj) is np.ndarray: + return cls(obj, itk_base=None) except ImportError: HAVE_NUMPY = False diff --git a/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py b/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py index ebb04aa5e98..37b8fd24495 100644 --- a/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py +++ b/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py @@ -29,6 +29,38 @@ class TestNumpyITKMemoryviewInterface(unittest.TestCase): def setUp(self): pass + def test_NDArrayITKBase_pickle(self): + """ + Test the serialization of itk.NDArrayITKBase + """ + Dimension = 3 + ScalarImageType = itk.Image[itk.UC, Dimension] + RegionType = itk.ImageRegion[Dimension] + + region = RegionType() + region.SetSize(0, 6); + region.SetSize(1, 6); + region.SetSize(2, 6); + + scalarImage = ScalarImageType.New() + scalarImage.SetRegions(region); + scalarImage.Allocate(True); + scalarImage.SetPixel([0, 0, 0], 5) + scalarImage.SetPixel([0, 0, 1], 3) + scalarImage.SetPixel([5, 5, 5], 8) + ndarray_itk_base = itk.array_view_from_image(scalarImage) + + import pickle + + ## test serialization of itk ndarrary itk base + pickled = pickle.dumps(ndarray_itk_base) + reloaded = pickle.loads(pickled) + equal = (reloaded == ndarray_itk_base).all() + print('--------------pickle testing---------') + print('Successfully pickled type ', type(ndarray_itk_base), type(reloaded), equal) + print(reloaded) + assert equal, 'Different results before and after pickle' + def test_NumPyBridge_itkScalarImage(self): "Try to convert all pixel types to NumPy array view" From d52833abaa66a9fe09f81248f50b41e6fe31ca9e Mon Sep 17 00:00:00 2001 From: Zhiyuan Liu Date: Tue, 28 Jul 2020 16:17:24 -0400 Subject: [PATCH 3/3] ENH: Serialize/Deserialize NDArrayITKBase --- Modules/Bridge/NumPy/wrapping/PyBuffer.i.init | 17 ++++------- .../NumPy/wrapping/test/itkPyBufferTest.py | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init index 18bf88a1ca7..545e02e8d98 100644 --- a/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init +++ b/Modules/Bridge/NumPy/wrapping/PyBuffer.i.init @@ -16,20 +16,15 @@ try: self.itk_base = getattr(obj, 'itk_base', None) def __reduce_ex__(self, protocol): - if protocol >= 5: - return type(self)._reconstruct, (PickleBuffer(self),), None - else: - return type(self)._reconstruct, (bytearray(self),) + np_copy = np.array(self, copy=True) + return type(self)._reconstruct, (np_copy,), None @classmethod def _reconstruct(cls, obj): - with memoryview(obj) as m: - # Get a handle over the original buffer object - obj = m.obj - print('within reconstruct') - print(cls, type(obj)) - if type(obj) is np.ndarray: return obj - else: return np.asarray(obj) + with memoryview(obj) as m: + obj = m.obj + if type(obj) is np.ndarray: + return cls(obj, itk_base=None) except ImportError: HAVE_NUMPY = False diff --git a/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py b/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py index ebb04aa5e98..bee7f6f86bf 100644 --- a/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py +++ b/Modules/Bridge/NumPy/wrapping/test/itkPyBufferTest.py @@ -29,6 +29,35 @@ class TestNumpyITKMemoryviewInterface(unittest.TestCase): def setUp(self): pass + def test_NDArrayITKBase_pickle(self): + """ + Test the serialization of itk.NDArrayITKBase + """ + Dimension = 3 + ScalarImageType = itk.Image[itk.UC, Dimension] + RegionType = itk.ImageRegion[Dimension] + + region = RegionType() + region.SetSize(0, 6); + region.SetSize(1, 6); + region.SetSize(2, 6); + + scalarImage = ScalarImageType.New() + scalarImage.SetRegions(region); + scalarImage.Allocate(True); + scalarImage.SetPixel([0, 0, 0], 5) + scalarImage.SetPixel([0, 0, 1], 3) + scalarImage.SetPixel([5, 5, 5], 8) + ndarray_itk_base = itk.array_view_from_image(scalarImage) + + import pickle + + ## test serialization of itk ndarrary itk base + pickled = pickle.dumps(ndarray_itk_base) + reloaded = pickle.loads(pickled) + equal = (reloaded == ndarray_itk_base).all() + assert equal, 'Different results before and after pickle' + def test_NumPyBridge_itkScalarImage(self): "Try to convert all pixel types to NumPy array view"