{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Fast Fourier Transform {#image_fft_example}\n\nThis example shows how to apply a Fast Fourier Transform (FFT) to a\n`pyvista.ImageData`{.interpreted-text role=\"class\"} using\n`pyvista.ImageDataFilters.fft`{.interpreted-text role=\"func\"} filter.\n\nHere, we demonstrate FFT usage by denoising an image, effectively\nremoving any \\\"high frequency\\\" content by performing a [low pass\nfilter](https://en.wikipedia.org/wiki/Low-pass_filter).\n\nThis example was inspired by [Image denoising by\nFFT](https://scipy-lectures.org/intro/scipy/auto_examples/solutions/plot_fft_image_denoise.html).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import numpy as np\n\nimport pyvista as pv\nfrom pyvista import examples"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Load the example Moon landing image and plot it.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "image = examples.download_moonlanding_image()\nprint(image.point_data)\n\n# Create a theme that we can reuse when plotting the image\ngrey_theme = pv.themes.DocumentTheme()\ngrey_theme.cmap = 'gray'\ngrey_theme.show_scalar_bar = False\ngrey_theme.axes.show = False\nimage.plot(theme=grey_theme, cpos='xy', text='Unprocessed Moon Landing Image')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Apply FFT to the image\n\nFFT will be applied to the active scalars, `'PNGImage'`, the default\nscalars name when loading a PNG image.\n\nThe output from the filter is a complex array stored by the same name\nunless specified using `output_scalars_name`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "fft_image = image.fft()\nfft_image.point_data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Plot the FFT of the image\n\nPlot the absolute value of the FFT of the image.\n\nNote that we are effectively viewing the \\\"frequency\\\" of the data in\nthis image, where the four corners contain the low frequency content of\nthe image, and the middle is the high frequency content of the image.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "fft_image.plot(\n    scalars=np.abs(fft_image.point_data['PNGImage']),\n    cpos=\"xy\",\n    theme=grey_theme,\n    log_scale=True,\n    text='Moon Landing Image FFT',\n    copy_mesh=True,  # don't overwrite scalars when plotting\n)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Remove the noise from the `fft_image`\n\nEffectively, we want to remove high frequency (noisy) data from our\nimage. First, let\\'s reshape by the size of the image.\n\nNext, perform a low pass filter by removing the middle 80% of the\ncontent of the image. Note that the high frequency content is in the\nmiddle of the array.\n\n::: note\n::: title\nNote\n:::\n\nIt is easier and more efficient to use the existing\n`pyvista.ImageDataFilters.low_pass`{.interpreted-text role=\"func\"}\nfilter. This section is here for demonstration purposes.\n:::\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "ratio_to_keep = 0.10\n\n# modify the fft_image data\nwidth, height, _ = fft_image.dimensions\ndata = fft_image['PNGImage'].reshape(height, width)  # note: axes flipped\ndata[int(height * ratio_to_keep) : -int(height * ratio_to_keep)] = 0\ndata[:, int(width * ratio_to_keep) : -int(width * ratio_to_keep)] = 0\n\nfft_image.plot(\n    scalars=np.abs(data),\n    cpos=\"xy\",\n    theme=grey_theme,\n    log_scale=True,\n    text='Moon Landing Image FFT with Noise Removed',\n    copy_mesh=True,  # don't overwrite scalars when plotting\n)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Convert to the spatial domain using reverse FFT\n\nFinally, convert the image data back to the \\\"spatial\\\" domain and plot\nit.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "rfft = fft_image.rfft()\nrfft['PNGImage'] = np.real(rfft['PNGImage'])\nrfft.plot(cpos=\"xy\", theme=grey_theme, text='Processed Moon Landing Image')"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}