From 0c7d8ef1e4b4dd718ef451f16436a27fdd301a02 Mon Sep 17 00:00:00 2001 From: Tom Birdsong Date: Fri, 20 May 2022 11:25:06 -0400 Subject: [PATCH] ENH: Add 1D FFT Example --- src/Filtering/FFT/CMakeLists.txt | 15 +++- .../ComputeFFTInOneDimension/CMakeLists.txt | 23 ++++++ .../FFT/ComputeFFTInOneDimension/Code.py | 56 +++++++++++++++ .../Documentation.rst | 71 +++++++++++++++++++ ...Liver1DFFTModulusOutputBaseline.mha.sha512 | 1 + ...seLiver1DFFTPhaseOutputBaseline.mha.sha512 | 1 + .../MouseLiverModulusOutput.png.sha512 | 1 + .../MouseLiverPhaseOutput.png.sha512 | 1 + .../MouseLiverRF.mha.sha512 | 1 + 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/CMakeLists.txt create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/Code.py create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/Documentation.rst create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTModulusOutputBaseline.mha.sha512 create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTPhaseOutputBaseline.mha.sha512 create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverModulusOutput.png.sha512 create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverPhaseOutput.png.sha512 create mode 100644 src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverRF.mha.sha512 diff --git a/src/Filtering/FFT/CMakeLists.txt b/src/Filtering/FFT/CMakeLists.txt index 9395b3404..ded87208a 100644 --- a/src/Filtering/FFT/CMakeLists.txt +++ b/src/Filtering/FFT/CMakeLists.txt @@ -1,4 +1,17 @@ -add_example(FilterImageInFourierDomain) +add_example(ComputeFFTInOneDimension) +compare_to_baseline( + PYTHON_ONLY + EXAMPLE_NAME ComputeFFTInOneDimension + TEST_NAME ComputeFFTInOneDimensionModulusBaselineComparison + BASELINE_PREFIX MouseLiver1DFFTModulusOutputBaseline +) +compare_to_baseline( + PYTHON_ONLY + EXAMPLE_NAME ComputeFFTInOneDimension + TEST_NAME ComputeFFTInOneDimensionPhaseBaselineComparison + BASELINE_PREFIX MouseLiver1DFFTPhaseOutputBaseline +) + compare_to_baseline( EXAMPLE_NAME FilterImageInFourierDomain BASELINE_PREFIX OutputBaseline diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/CMakeLists.txt b/src/Filtering/FFT/ComputeFFTInOneDimension/CMakeLists.txt new file mode 100644 index 000000000..908216995 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.16.3) + +project(ComputeFFTInOneDimension) + +find_package(ITK REQUIRED) +include(${ITK_USE_FILE}) + +install(FILES Code.py CMakeLists.txt + DESTINATION share/ITKSphinxExamples/Code/Filtering/FFT/ComputeFFTInOneDimension + COMPONENT Code + ) + +enable_testing() + +if(ITK_WRAP_PYTHON) + find_package(PythonInterp REQUIRED) + add_test(NAME ComputeFFTInOneDimensionPython + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/Code.py + ${CMAKE_CURRENT_BINARY_DIR}/MouseLiverRF.mha + ${CMAKE_CURRENT_BINARY_DIR}/MouseLiver1DFFTModulusOutputPython.mha + ${CMAKE_CURRENT_BINARY_DIR}/MouseLiver1DFFTPhaseOutputPython.mha + ) +endif() \ No newline at end of file diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/Code.py b/src/Filtering/FFT/ComputeFFTInOneDimension/Code.py new file mode 100644 index 000000000..09b59c8ba --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/Code.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +# Copyright NumFOCUS +# +# 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.txt +# +# 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. + +import itk +import argparse + +parser = argparse.ArgumentParser(description="Compute Inverse FFT Of Image.") +parser.add_argument("input_path", nargs=1, type=str) +parser.add_argument("modulus_output_path", nargs=1, type=str) +parser.add_argument("phase_output_path", nargs=1, type=str) +parser.add_argument("fft_direction", nargs="?", default=0, type=int) +args = parser.parse_args() + +# Read input image +pixel_type = itk.F +image = itk.imread(args.input_path[0], pixel_type=pixel_type) +print(f"Read real input image of type {type(image)} and size {itk.size(image)}") + +assert ( + args.fft_direction < image.GetImageDimension() +), "FFT direction must be an image dimension" + +# Perform FFT in given direction +padded_image = itk.fft_pad_image_filter(image) +print(f"Padded input image to size {itk.size(image)}") +print(f"Performing FFT along axis {args.fft_direction}") +complex_image = itk.forward1_dfft_image_filter(image, direction=args.fft_direction) +print( + f"Generated complex frequency image of type {type(complex_image)} and size {itk.size(complex_image)}" +) + +# Shift image along FFT dimension to represent complex range (-f_B, +f_B] +shift = [0] * complex_image.GetImageDimension() +shift[args.fft_direction] = int(itk.size(complex_image)[args.fft_direction] / 2) +shift = [int(itk.size(complex_image)[args.fft_direction] / 2), 0] +shifted_image = itk.cyclic_shift_image_filter(complex_image, shift=shift) + +# Write out modulus and phase images for visualization in PNG format +modulus_image = itk.complex_to_modulus_image_filter(shifted_image) +itk.imwrite(modulus_image, args.modulus_output_path[0]) + +phase_image = itk.complex_to_phase_image_filter(shifted_image) +itk.imwrite(phase_image, args.phase_output_path[0]) diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/Documentation.rst b/src/Filtering/FFT/ComputeFFTInOneDimension/Documentation.rst new file mode 100644 index 000000000..9bf7b3ad3 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/Documentation.rst @@ -0,0 +1,71 @@ +:name: ComputeFFTInOneDimension + +Compute Forward FFT In One Dimension +==================================== + +.. index:: + single: Forward1DFFTImageFilter + single: ComplexToRealImageFilter + single: ComplexToImaginaryImageFilter + single: ComplexToModulusImageFilter + single: CyclicShiftImageFilter + single: ImageFileReader + single: ImageFileWriter + +Synopsis +-------- + +Compute forward FFT of an image in one dimension. + + +Results +------- + +.. figure:: MouseLiverRF.png + :scale: 50% + :alt: Input image + + Input RF Ultrasound Image + +.. figure:: MouseLiverModulusOutput.png + :scale: 50% + :alt: Modulus Image + + Output Modulus Image + +.. figure:: MouseLiverPhaseOutput.png + :scale: 50% + :alt: Phase Image + + Output Phase Image + +Output:: + + Read real input image of type and size itkSize2 ([1536, 128]) + Padded input image to size itkSize2 ([1536, 128]) + Performing FFT along axis 0 + Generated complex frequency image of type and size itkSize2 ([1536, 128]) + +Code +---- + +Python +...... + +.. literalinclude:: Code.py + :language: python + :lines: 1, 16- + + +Classes demonstrated +-------------------- + +.. breathelink:: itk::FFTPadImageFilter + +.. breathelink:: itk::Forward1DFFTImageFilter + +.. breathelink:: itk::CyclicShiftImageFilter + +.. breathelink:: itk::ComplexToModulusImageFilter + +.. breathelink:: itk::ComplexToPhaseImageFilter diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTModulusOutputBaseline.mha.sha512 b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTModulusOutputBaseline.mha.sha512 new file mode 100644 index 000000000..d216fbd48 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTModulusOutputBaseline.mha.sha512 @@ -0,0 +1 @@ +bcbead186f60040a16fa7091598b2da7ead8f97935efcd078c285ede14a57b717d53f95ffb2db1df6235cc19be67f98e617fc63deb24a18c7278345fd9ba24f7 diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTPhaseOutputBaseline.mha.sha512 b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTPhaseOutputBaseline.mha.sha512 new file mode 100644 index 000000000..60b989319 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiver1DFFTPhaseOutputBaseline.mha.sha512 @@ -0,0 +1 @@ +f59ba4947c6394fa1b1dc77ff123b53d61b676a2bcdfd16758b0cd2672360cd3ed631e49890a8e0aa31a90eaa4fb44f1b10396b27896ffa26f0a144fc31bfd07 diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverModulusOutput.png.sha512 b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverModulusOutput.png.sha512 new file mode 100644 index 000000000..ea34982f1 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverModulusOutput.png.sha512 @@ -0,0 +1 @@ +d09c892a12a7deafd6465652b30a95c102e4f242e3e9eedbc69603eb61afa08c44b3bdea39bf4e2207de0f59f3c3a3e5f7af76d9ea8380872f5f3eac2a46c29e diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverPhaseOutput.png.sha512 b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverPhaseOutput.png.sha512 new file mode 100644 index 000000000..5135b186e --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverPhaseOutput.png.sha512 @@ -0,0 +1 @@ +20da0fff4cc937515571e60464f88b83f591f4e71af507d5206ab1460259df6cd0f1d6df98c55d880b25502b49586d5d789f918d4702b5c411d745a88fe7fec2 diff --git a/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverRF.mha.sha512 b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverRF.mha.sha512 new file mode 100644 index 000000000..d689e1716 --- /dev/null +++ b/src/Filtering/FFT/ComputeFFTInOneDimension/MouseLiverRF.mha.sha512 @@ -0,0 +1 @@ +e0db3e0f2409e80d0c707507f29b78c9d493e7d603010bfbfe6c97df6e56b6c92c22c3ce7e7894cb27c7321992314045fd7ce7ac1d22c657e8ec0b4d37495b9e