diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..e96a482a --- /dev/null +++ b/.coveragerc @@ -0,0 +1,6 @@ +[run] +omit = + */convolution.py + */_transonic.py + */_le_template_simple_.py + */benchmark.py \ No newline at end of file diff --git a/.github/workflows/build_test_deploy_all_wheels.yml b/.github/workflows/build_test_deploy_all_wheels.yml index dc2b37a7..cbcd897d 100644 --- a/.github/workflows/build_test_deploy_all_wheels.yml +++ b/.github/workflows/build_test_deploy_all_wheels.yml @@ -74,4 +74,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.BMS_DEPLOY_PYPI_TOKEN }} - packages-dir: ./final_dist/ + packages-dir: ./final_dist/ \ No newline at end of file diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml new file mode 100644 index 00000000..6476c9a3 --- /dev/null +++ b/.github/workflows/build_wheels.yml @@ -0,0 +1,56 @@ +name: (self-hosted) Build and Publish Wheels + +on: workflow_dispatch + +jobs: + build: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: true + matrix: + include: + - os: macOS-ARM + runner: [self-hosted, macOS, ARM64] + archs: arm64 + cibw_build: cp39-macosx_arm64 cp310-macosx_arm64 cp311-macosx_arm64 cp312-macosx_arm64 + - os: manylinux + runner: [self-hosted, Ubuntu, Native] + archs: auto + cibw_build: cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 + - os: windows + runner: [self-hosted, Windows] + archs: auto + cibw_build: cp39-win_amd64 cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: 3.9 # Works as bootstrap for cibuildwheel + + - name: Install cibuildwheel and nox + run: | + python -m pip install --upgrade pip + python -m pip install cibuildwheel==2.16.2 + python -m pip install nox + + - name: Build sdist (only on Windows) + if: matrix.os == 'windows' + run: python -m nox --sessions build_sdist + + - name: Build wheels + run: python -m cibuildwheel --output-dir wheelhouse + env: + CIBW_BUILD: ${{ matrix.cibw_build }} + CIBW_ARCHS: ${{ matrix.archs }} + + - name: Test wheels (only on macOS ARM64) + if: matrix.os == 'macOS-ARM' + run: python -m nox --sessions test_wheel + + - uses: actions/upload-artifact@v4 + with: + name: wheels-${{ matrix.os }} + path: ./wheelhouse/* diff --git a/.github/workflows/buildtest_mac_arm_wheels.yml b/.github/workflows/buildtest_mac_arm_wheels.yml index 6329c7e4..4be1da32 100644 --- a/.github/workflows/buildtest_mac_arm_wheels.yml +++ b/.github/workflows/buildtest_mac_arm_wheels.yml @@ -23,7 +23,7 @@ jobs: run: python -m cibuildwheel --output-dir wheelhouse # to supply options, put them in 'env', like: env: - CIBW_BUILD: cp39-macosx_arm64 cp310-macosx_arm64 cp311-macosx_arm64 cp312-macosx_arm64 + CIBW_BUILD: cp39-macosx_arm64 cp310-macosx_arm64 cp311-macosx_arm64 cp312-macosx_arm64 cp313-macosx_arm64 CIBW_ARCHS: arm64 - name: Test wheels diff --git a/.github/workflows/buildtest_manylinux_wheels.yml b/.github/workflows/buildtest_manylinux_wheels.yml index 83ce7730..b3984f50 100644 --- a/.github/workflows/buildtest_manylinux_wheels.yml +++ b/.github/workflows/buildtest_manylinux_wheels.yml @@ -21,7 +21,7 @@ jobs: - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BUILD: cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 + CIBW_BUILD: cp39-manylinux_x86_64 cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 cp313-manylinux_x86_64 # to supply options, put them in 'env', like: # env: # CIBW_SOME_OPTION: value diff --git a/.github/workflows/buildtest_windows_x86.yml b/.github/workflows/buildtest_windows_x86.yml index 0e584bc7..fae66bf9 100644 --- a/.github/workflows/buildtest_windows_x86.yml +++ b/.github/workflows/buildtest_windows_x86.yml @@ -44,7 +44,7 @@ jobs: - name: Build wheels run: python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BUILD: cp39-win_amd64 cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 + CIBW_BUILD: cp39-win_amd64 cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 cp313-win_amd64 # to supply options, put them in 'env', like: # env: # CIBW_SOME_OPTION: value diff --git a/notebooks/ChannelRegistration.ipynb b/notebooks/ChannelRegistration.ipynb index 62eab4d6..b256fbac 100644 --- a/notebooks/ChannelRegistration.ipynb +++ b/notebooks/ChannelRegistration.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "313252b6", + "id": "21d1e58b", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -22,7 +22,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a7fd8e2a", + "id": "b3c2a12b", "metadata": { "cellView": "form" }, @@ -54,7 +54,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -77,7 +80,7 @@ { "cell_type": "code", "execution_count": null, - "id": "321413ab", + "id": "a5c09b00", "metadata": { "cellView": "form" }, @@ -91,7 +94,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -102,7 +105,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -161,7 +164,7 @@ }, { "cell_type": "markdown", - "id": "a84604a2", + "id": "535b3d44", "metadata": {}, "source": [ "# Channel Registration Parameters: \n", @@ -179,7 +182,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7a99907f", + "id": "5c4e28f4", "metadata": { "cellView": "form" }, @@ -229,7 +232,7 @@ " gui_reg._main_display.children = gui_reg._main_display.children + (stackview.slice(dataset_registered, colormap=gui_reg[\"cmaps\"].value, continuous_update=True),)\n", "\n", "\n", - "gui_reg.add_label(\"Channel Registration parameters:\")\n", + "gui_reg.add_label(value=\"Channel Registration parameters:\")\n", "gui_reg.add_int_slider(\"ref\", description=\"Reference channel\", min=0, max=dataset_original.shape[0]-1, value=0)\n", "gui_reg.add_int_slider(\"max\", description=\"Max expected drift\", min=0, max=1000, value=10)\n", "gui_reg.add_int_slider(\"blocks\", description=\"Blocks per axis\", min=1, max=10, value=5)\n", @@ -247,7 +250,7 @@ }, { "cell_type": "markdown", - "id": "eefc7618", + "id": "ae281b8a", "metadata": {}, "source": [ "## Use the following cell only if you have a previously calculated translation mask\n", @@ -257,7 +260,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55cdcf4f", + "id": "c0e91c8c", "metadata": { "cellView": "form" }, @@ -312,9 +315,9 @@ " gui_reg_apply[\"Register Image\"].description = \"Align\"\n", " gui_reg_apply._main_display.children = gui_reg_apply._main_display.children + (stackview.slice(aligned_image, colormap=gui_reg_apply[\"cmaps\"].value, continuous_update=True),)\n", "\n", - "gui_reg_apply.add_label(\"Load translation mask:\")\n", + "gui_reg_apply.add_label(value=\"Load translation mask:\")\n", "gui_reg_apply.add_file_upload(\"upload\")\n", - "gui_reg_apply.add_label(\"Load image to register:\")\n", + "gui_reg_apply.add_label(value=\"Load image to register:\")\n", "gui_reg_apply.add_file_upload(\"upload image\")\n", "gui_reg_apply.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", diff --git a/notebooks/DriftCorrection.ipynb b/notebooks/DriftCorrection.ipynb index 4e9899bf..5c942f05 100644 --- a/notebooks/DriftCorrection.ipynb +++ b/notebooks/DriftCorrection.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "065b6c17", + "id": "4a8ab58f", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -22,7 +22,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7f4d7a86", + "id": "80886110", "metadata": { "cellView": "form" }, @@ -54,7 +54,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -77,7 +80,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7e22c6f0", + "id": "7d8288ff", "metadata": { "cellView": "form" }, @@ -91,7 +94,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -102,7 +105,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -161,7 +164,7 @@ }, { "cell_type": "markdown", - "id": "9b2595dc", + "id": "c800a0e9", "metadata": {}, "source": [ "# Drift Correction Parameters: \n", @@ -178,7 +181,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4aeea0dc", + "id": "e2d6671a", "metadata": { "cellView": "form" }, @@ -254,30 +257,13 @@ " )\n", "\n", "\n", - "gui_drift.add_label(\"Drift Correction parameters:\")\n", - "gui_drift.add_dropdown(\n", - " \"ref\",\n", - " description=\"Reference frame\",\n", - " options=[\"First frame\", \"Previous frame\"],\n", - " value=\"First frame\",\n", - ")\n", - "gui_drift.add_int_slider(\n", - " \"max\", description=\"Max expected drift\", min=0, max=1000, value=10\n", - ")\n", - "gui_drift.add_int_slider(\n", - " \"time_averaging\",\n", - " description=\"Time averaging\",\n", - " min=1,\n", - " max=dataset_original.shape[0],\n", - " value=1,\n", - ")\n", - "gui_drift.add_dropdown(\n", - " \"cmaps\",\n", - " description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\",\n", - " remember_value=True,\n", - ")\n", + "gui_drift.add_label(value=\"Drift Correction parameters:\")\n", + "gui_drift.add_dropdown(\"ref\", description=\"Reference frame\", options=[\"First frame\", \"Previous frame\"], value=\"First frame\")\n", + "gui_drift.add_int_slider(\"max\", description=\"Max expected drift\", min=0, max=1000, value=10)\n", + "gui_drift.add_int_slider(\"time_averaging\", description=\"Time averaging\", min=1, max=dataset_original.shape[0], value=1)\n", + "gui_drift.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\", remember_value=True)\n", "gui_drift.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", "gui_drift.add_button(\"align\", description=\"Align\")\n", "gui_drift[\"align\"].on_click(on_button_align)\n", @@ -288,7 +274,7 @@ }, { "cell_type": "markdown", - "id": "5678e56d", + "id": "60fc5a28", "metadata": {}, "source": [ "## Use the following cell only if you have a previously calculated drift table\n", @@ -298,7 +284,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3bdca2b8", + "id": "45dc3ea1", "metadata": { "cellView": "form" }, @@ -355,9 +341,9 @@ " gui_drift_apply[\"Align image\"].description = \"Align\"\n", " gui_drift_apply._main_display.children = gui_drift_apply._main_display.children + (stackview.slice(aligned_image, colormap=gui_drift_apply[\"cmaps\"].value, continuous_update=True),)\n", "\n", - "gui_drift_apply.add_label(\"Load drift table:\")\n", + "gui_drift_apply.add_label(value=\"Load drift table:\")\n", "gui_drift_apply.add_file_upload(\"upload\")\n", - "gui_drift_apply.add_label(\"Load image to align:\")\n", + "gui_drift_apply.add_label(value=\"Load image to align:\")\n", "gui_drift_apply.add_file_upload(\"upload image\")\n", "gui_drift_apply.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", diff --git a/notebooks/ExampleDataSRRFandQC.ipynb b/notebooks/ExampleDataSRRFandQC.ipynb index 8594d77d..1ec6d8e1 100644 --- a/notebooks/ExampleDataSRRFandQC.ipynb +++ b/notebooks/ExampleDataSRRFandQC.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "35223840", + "id": "ccf59fd6", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -26,29 +26,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aef3a5f2", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9c73791a", + "id": "ac16d462", "metadata": { "cellView": "form" }, @@ -80,7 +58,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -102,7 +83,7 @@ }, { "cell_type": "markdown", - "id": "c46af7c4", + "id": "b589d195", "metadata": {}, "source": [ "## Next lets create the Data Loader GUI.\n", @@ -113,7 +94,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e86a2c07", + "id": "894a6951", "metadata": { "cellView": "form" }, @@ -127,7 +108,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -138,7 +119,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -197,7 +178,7 @@ }, { "cell_type": "markdown", - "id": "5f2998a0", + "id": "517e4a79", "metadata": {}, "source": [ "## Now let's use SRRF to generate a super-resolution image\n", @@ -206,7 +187,7 @@ }, { "cell_type": "markdown", - "id": "85caef65", + "id": "b2b2ef21", "metadata": {}, "source": [ "# SRRF Parameters:\n", @@ -222,16 +203,19 @@ { "cell_type": "code", "execution_count": null, - "id": "980a7aae", + "id": "c7fc2972", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create SRRF GUI\n", + "# @title Create SRRF GUI\n", "gui_srrf = EasyGui(\"srrf\")\n", "from nanopyx.methods import SRRF\n", - "from nanopyx.core.transform.sr_temporal_correlations import calculate_SRRF_temporal_correlations\n", + "from nanopyx.core.transform.sr_temporal_correlations import (\n", + " calculate_SRRF_temporal_correlations,\n", + ")\n", + "\n", "\n", "def run_srrf(b):\n", " clear_output()\n", @@ -241,6 +225,7 @@ " magnification = gui_srrf[\"magnification\"].value\n", " frames_per_timepoint = gui_srrf[\"frames_per_timepoint\"].value\n", " srrf_order = gui_srrf[\"srrf_order\"].value\n", + " mpcorrection = gui_srrf[\"mpcorrection\"].value\n", " # disable button while running\n", " gui_srrf[\"run\"].disabled = True\n", " gui_srrf[\"run\"].description = \"Running...\"\n", @@ -249,14 +234,21 @@ " elif frames_per_timepoint > dataset_original.shape[0]:\n", " frames_per_timepoint = dataset_original.shape[0]\n", "\n", - " output= []\n", + " output = []\n", "\n", " for i in range(dataset_original.shape[0] // frames_per_timepoint):\n", - " block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint]\n", - " result = SRRF(block, magnification=magnification, ringRadius=ring_radius,\n", - " radialityPositivityConstraint=True,\n", - " doIntensityWeighting=True)\n", - " output.append(calculate_SRRF_temporal_correlations(result[0], srrf_order))\n", + " block = dataset_original[\n", + " i * frames_per_timepoint : (i + 1) * frames_per_timepoint\n", + " ]\n", + " result = SRRF(\n", + " block,\n", + " magnification=magnification,\n", + " ringRadius=ring_radius,\n", + " radialityPositivityConstraint=True,\n", + " doIntensityWeighting=True,\n", + " macro_pixel_correction=mpcorrection,\n", + " )\n", + " output.append(calculate_SRRF_temporal_correlations(result, srrf_order))\n", "\n", " global dataset_srrf\n", " dataset_srrf = np.array(output)\n", @@ -269,21 +261,49 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_srrf.tif\", dataset_srrf)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_srrf.tif\", dataset_srrf)\n", - " gui_srrf._main_display.children = gui_srrf._main_display.children + (stackview.slice(dataset_srrf, colormap=gui_srrf[\"cmaps\"].value, continuous_update=True),)\n", - "\n", - "gui_srrf.add_float_slider(\"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=0.5, remember_value=True)\n", - "gui_srrf.add_int_slider(\"magnification\", description=\"Magnification:\", min=1, max=10, value=5)\n", - "gui_srrf.add_int_slider(\"srrf_order\", description=\"SRRF order:\", min=-1, max=4, value=3)\n", - "gui_srrf.add_label(\"-=-= Time-Lapse =-=-\")\n", - "gui_srrf.add_int_slider(\"frames_per_timepoint\", description=\"Frames per time-point (0 - auto)\", min=1, max=dataset_original.shape[0], value=dataset_original.shape[0]//2)\n", + " gui_srrf._main_display.children = gui_srrf._main_display.children + (\n", + " stackview.slice(\n", + " dataset_srrf,\n", + " colormap=gui_srrf[\"cmaps\"].value,\n", + " continuous_update=True,\n", + " ),\n", + " )\n", + "\n", + "\n", + "gui_srrf.add_float_slider(\n", + " \"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=0.5\n", + ")\n", + "gui_srrf.add_int_slider(\n", + " \"magnification\", description=\"Magnification:\", min=1, max=10, value=5\n", + ")\n", + "gui_srrf.add_int_slider(\n", + " \"srrf_order\", description=\"SRRF order:\", min=-1, max=4, value=3\n", + ")\n", + "gui_srrf.add_label(value=\"-=-= Time-Lapse =-=-\")\n", + "gui_srrf.add_int_slider(\n", + " \"frames_per_timepoint\",\n", + " description=\"Frames per time-point (0 - auto)\",\n", + " min=1,\n", + " max=dataset_original.shape[0],\n", + " value=dataset_original.shape[0] // 2,\n", + ")\n", + "gui_srrf.add_checkbox(\n", + " \"mpcorrection\", description=\"Macro Pixel Correction\", value=True\n", + ")\n", "gui_srrf.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", - "gui_srrf.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_srrf.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_srrf.add_button(\"run\", description=\"Run\")\n", - "gui_srrf['run'].on_click(run_srrf)\n", + "gui_srrf[\"run\"].on_click(run_srrf)\n", "gui_srrf.show()\n", "\n", "\n" @@ -291,7 +311,7 @@ }, { "cell_type": "markdown", - "id": "51e4d923", + "id": "41180535", "metadata": {}, "source": [ "## Let's use NanoPyx to generate an error map of the SRRF image\n", @@ -301,13 +321,13 @@ { "cell_type": "code", "execution_count": null, - "id": "4abbd64f", + "id": "ab02d527", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create Error Map GUI\n", + "# @title Create Error Map GUI\n", "gui_error = EasyGui(\"Error\")\n", "\n", "import numpy as np\n", @@ -316,6 +336,7 @@ "from matplotlib import pyplot as plt\n", "from nanopyx.core.transform import ErrorMap\n", "\n", + "\n", "def run_error(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -324,7 +345,9 @@ " gui_error[\"run\"].description = \"Calculating...\"\n", " global errormap\n", " error_map = ErrorMap()\n", - " error_map.optimise(np.mean(dataset_original, axis=0), np.mean(dataset_srrf, axis=0))\n", + " error_map.optimise(\n", + " np.mean(dataset_original, axis=0), np.mean(dataset_srrf, axis=0)\n", + " )\n", " gui_error[\"run\"].disabled = False\n", " gui_error[\"run\"].description = \"Calculate\"\n", " print(\"RSE: \", error_map.getRSE())\n", @@ -336,7 +359,9 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_error_map.tif\", errormap)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map.tif\", errormap)\n", " plt.imshow(errormap)\n", " plt.axis(\"off\")\n", @@ -346,11 +371,13 @@ " with output_plot:\n", " display(Image.open(img_buf))\n", " gui_error._main_display.children = gui_error._main_display.children + (\n", - " widgets.Label(value=\"RSE: \"+str(error_map.getRSE())),\n", - " widgets.Label(value=\"RSP: \"+str(error_map.getRSP())),\n", - " output_plot)\n", + " widgets.Label(value=\"RSE: \" + str(error_map.getRSE())),\n", + " widgets.Label(value=\"RSP: \" + str(error_map.getRSP())),\n", + " output_plot,\n", + " )\n", " plt.clf()\n", "\n", + "\n", "def run_error_stack(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -364,27 +391,40 @@ " rse_rsp_table = []\n", "\n", " # Ensure datasets are 3D\n", - " if np.ndim(dataset_original) == 2: \n", - " dataset_original = np.expand_dims(dataset_original, axis=0) \n", - " if np.ndim(dataset_srrf) == 2: \n", - " dataset_srrf = np.expand_dims(dataset_srrf, axis=0) \n", + " if np.ndim(dataset_original) == 2:\n", + " dataset_original = np.expand_dims(dataset_original, axis=0)\n", + " if np.ndim(dataset_srrf) == 2:\n", + " dataset_srrf = np.expand_dims(dataset_srrf, axis=0)\n", + "\n", + " # Ensures datasets have same number of frames\n", + "\n", + " if dataset_original.shape[0] > dataset_srrf.shape[0]:\n", + " factor = dataset_original.shape[0] // dataset_srrf.shape[0]\n", + " remainder = dataset_original.shape[0] % dataset_srrf.shape[0]\n", + " averaged_blocks = [\n", + " np.mean(dataset_original[i * factor : (i + 1) * factor], axis=0)\n", + " for i in range(dataset_srrf.shape[0])\n", + " ]\n", + " if remainder > 0:\n", + " averaged_blocks.append(\n", + " np.mean(dataset_original[-remainder:], axis=0)\n", + " )\n", + " dataset_original = np.array(averaged_blocks)\n", "\n", " # Iterate through each slice\n", " print(\"Processing slices...\")\n", - " for i in tqdm(range(dataset_original.shape[0]),desc=\"Slices processed\"): \n", - " slice_df = dataset_original[i] # \n", - " slice_sr = dataset_srrf[i] # \n", - " \n", + " for i in tqdm(range(dataset_original.shape[0]), desc=\"Slices processed\"):\n", + " slice_df = dataset_original[i] #\n", + " slice_sr = dataset_srrf[i] #\n", + "\n", " error_map = ErrorMap()\n", " error_map.optimise(slice_df, slice_sr)\n", "\n", " # Store the error map and RSE/RSP values\n", " errormap_stack.append(np.array(error_map.imRSE))\n", - " rse_rsp_table.append({\n", - " \"Slice\": i,\n", - " \"RSE\": error_map.getRSE(),\n", - " \"RSP\": error_map.getRSP()\n", - " })\n", + " rse_rsp_table.append(\n", + " {\"Slice\": i, \"RSE\": error_map.getRSE(), \"RSP\": error_map.getRSP()}\n", + " )\n", "\n", " # Convert results to arrays\n", " errormap_stack = np.array(errormap_stack) # 3D stack of error maps\n", @@ -394,10 +434,16 @@ " if own_data:\n", " path = gui_data[\"upload\"].selected_path\n", " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", - " tiff.imwrite(path + os.sep + name + \"_error_map_stack.tif\", errormap_stack)\n", - " rse_rsp_table.to_csv(path + os.sep + name + \"_rse_rsp_table.csv\", index=False)\n", + " tiff.imwrite(\n", + " path + os.sep + name + \"_error_map_stack.tif\", errormap_stack\n", + " )\n", + " rse_rsp_table.to_csv(\n", + " path + os.sep + name + \"_rse_rsp_table.csv\", index=False\n", + " )\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map_stack.tif\", errormap_stack)\n", " rse_rsp_table.to_csv(name + \"_rse_rsp_table.csv\", index=False)\n", "\n", @@ -414,9 +460,13 @@ "\n", "\n", "gui_error.add_checkbox(\"save\", description=\"Save output\", value=True)\n", - "gui_error.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_error.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_error.add_button(\"run\", description=\"Calculate\")\n", "gui_error[\"run\"].on_click(run_error_stack)\n", "gui_error.show()\n", @@ -426,7 +476,7 @@ }, { "cell_type": "markdown", - "id": "f46f54e3", + "id": "40f389f4", "metadata": {}, "source": [ "## Let's compare the resolution of the raw data with the SRRF using FRC and DecorrelationAnalysis. Let's start with calculation the FRC resolution of the raw data (select frame 3 and 11).\n", @@ -435,7 +485,7 @@ }, { "cell_type": "markdown", - "id": "63a03836", + "id": "b3b9ce84", "metadata": {}, "source": [ "# FRC Parameters:\n", @@ -450,7 +500,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4c7fdeb0", + "id": "6ef9e176", "metadata": { "cellView": "form" }, @@ -496,7 +546,7 @@ " gui_frc_df._main_display.children = gui_frc_df._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_df.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=0)\n", "gui_frc_df.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=1)\n", @@ -510,7 +560,7 @@ }, { "cell_type": "markdown", - "id": "8bdcd38c", + "id": "3be3aa0a", "metadata": {}, "source": [ "## Now do the same for the SRRF image\n", @@ -520,7 +570,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f53ebbc0", + "id": "3c364a56", "metadata": { "cellView": "form" }, @@ -566,7 +616,7 @@ " gui_frc_srrf._main_display.children = gui_frc_srrf._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_srrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_srrf.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_srrf[0].shape[0]-1, value=0)\n", "gui_frc_srrf.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_srrf[0].shape[0]-1, value=1)\n", @@ -580,7 +630,7 @@ }, { "cell_type": "markdown", - "id": "e4dbf494", + "id": "611e7ff7", "metadata": {}, "source": [ "## Let's do the same using Decorrelation analysis\n", @@ -589,7 +639,7 @@ }, { "cell_type": "markdown", - "id": "cf511dc0", + "id": "19efd107", "metadata": {}, "source": [ "# Image Decorrelation Analysis Parameters:\n", @@ -605,7 +655,7 @@ { "cell_type": "code", "execution_count": null, - "id": "caae72d5", + "id": "72263010", "metadata": { "cellView": "form" }, @@ -651,7 +701,7 @@ " gui_decorr_df._main_display.children = gui_decorr_df._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_df.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_original.shape[0]-1, value=0)\n", "gui_decorr_df.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", @@ -666,7 +716,7 @@ }, { "cell_type": "markdown", - "id": "e6625292", + "id": "4c0790e7", "metadata": {}, "source": [ "## Now let's measure the resolution of the generated SRRF image using Decorrelation analysis\n", @@ -676,7 +726,7 @@ { "cell_type": "code", "execution_count": null, - "id": "812ce078", + "id": "b87c1750", "metadata": { "cellView": "form" }, @@ -722,7 +772,7 @@ " gui_decorr_srrf._main_display.children = gui_decorr_srrf._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_srrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_srrf.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_srrf.shape[0]-1, value=0)\n", "gui_decorr_srrf.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", diff --git a/notebooks/NonLocalMeansDenoising.ipynb b/notebooks/NonLocalMeansDenoising.ipynb index 56e9e4c7..4fe964b1 100644 --- a/notebooks/NonLocalMeansDenoising.ipynb +++ b/notebooks/NonLocalMeansDenoising.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "e9506cc6", + "id": "d6df60cd", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -23,29 +23,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b563d1aa", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af5c8d8a", + "id": "a63bd5aa", "metadata": { "cellView": "form" }, @@ -77,7 +55,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -100,7 +81,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5ee5d3b4", + "id": "9d66588d", "metadata": { "cellView": "form" }, @@ -114,7 +95,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -125,7 +106,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -184,7 +165,7 @@ }, { "cell_type": "markdown", - "id": "ef4922fa", + "id": "479327f7", "metadata": {}, "source": [ "# Use Non-local means denoising on selected data\n", @@ -201,7 +182,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1ec558bb", + "id": "66b826f8", "metadata": { "cellView": "form" }, @@ -240,8 +221,8 @@ " tiff.imwrite(name + \"_nlm_denoised.tif\", dataset_nlm)\n", " gui_nlm._main_display.children = gui_nlm._main_display.children + (stackview.slice(dataset_nlm, colormap=gui_nlm[\"cmaps\"].value, continuous_update=True),)\n", "\n", - "gui_nlm.add_int_slider(\"patch_size\", description=\"Patch Size\", min=1, max=dataset_original.shape[-1]//2, value=5, remember_value=True)\n", - "gui_nlm.add_int_slider(\"patch_distance\", description=\"Patch Distance\", min=1, max=dataset_original.shape[-1]//2, value=10, remember_value=True)\n", + "gui_nlm.add_int_slider(\"patch_size\", description=\"Patch Size\", min=1, max=dataset_original.shape[-1]//2, value=5)\n", + "gui_nlm.add_int_slider(\"patch_distance\", description=\"Patch Distance\", min=1, max=dataset_original.shape[-1]//2, value=10)\n", "gui_nlm.add_float_text(\"h\", description=\"h\", value=0.1, remember_value=True)\n", "gui_nlm.add_float_text(\"sigma\", description=\"sigma\", value=0.1, remember_value=True)\n", "gui_nlm.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", diff --git a/notebooks/ParamSweepandeSRRF.ipynb b/notebooks/ParamSweepandeSRRF.ipynb index 1e88c5a5..b6aab1fa 100644 --- a/notebooks/ParamSweepandeSRRF.ipynb +++ b/notebooks/ParamSweepandeSRRF.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "405bfe1c", + "id": "0c5fd2df", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -28,29 +28,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d2cef25b", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7fb6b318", + "id": "5ee4bab7", "metadata": { "cellView": "form" }, @@ -82,7 +60,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -105,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c0ff8eff", + "id": "ae1cf4a9", "metadata": { "cellView": "form" }, @@ -119,7 +100,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -130,7 +111,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -189,7 +170,7 @@ }, { "cell_type": "markdown", - "id": "ddfd8f13", + "id": "0c6ad675", "metadata": {}, "source": [ "# Run a parameter sweep to find the best combination of parameters\n", @@ -206,7 +187,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7c94da97", + "id": "b49653f3", "metadata": { "cellView": "form" }, @@ -271,16 +252,19 @@ { "cell_type": "code", "execution_count": null, - "id": "45d467db", + "id": "619081d0", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create eSRRF GUI\n", + "# @title Create eSRRF GUI\n", "gui_esrrf = EasyGui(\"esrrf\")\n", "from nanopyx.methods import eSRRF\n", - "from nanopyx.core.transform.sr_temporal_correlations import calculate_eSRRF_temporal_correlations\n", + "from nanopyx.core.transform.sr_temporal_correlations import (\n", + " calculate_eSRRF_temporal_correlations,\n", + ")\n", + "\n", "\n", "def run_esrrf(b):\n", " clear_output()\n", @@ -290,7 +274,7 @@ " magnification = gui_esrrf[\"magnification\"].value\n", " frames_per_timepoint = gui_esrrf[\"frames_per_timepoint\"].value\n", " sensitivity = gui_esrrf[\"sensitivity\"].value\n", - "\n", + " mpcorrection = gui_esrrf[\"mpcorrection\"].value\n", " esrrf_order = gui_esrrf[\"esrrf_order\"].value\n", " if esrrf_order == 1:\n", " esrrf_order = \"AVG\"\n", @@ -306,14 +290,23 @@ " elif frames_per_timepoint > dataset_original.shape[0]:\n", " frames_per_timepoint = dataset_original.shape[0]\n", "\n", - " output= []\n", + " output = []\n", "\n", " for i in range(dataset_original.shape[0] // frames_per_timepoint):\n", - " block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint]\n", - " result = eSRRF(block, magnification=magnification, radius=ring_radius,\n", - " sensitivity=sensitivity,\n", - " doIntensityWeighting=True)\n", - " output.append(calculate_eSRRF_temporal_correlations(result[0], esrrf_order))\n", + " block = dataset_original[\n", + " i * frames_per_timepoint : (i + 1) * frames_per_timepoint\n", + " ]\n", + " result = eSRRF(\n", + " block,\n", + " magnification=magnification,\n", + " radius=ring_radius,\n", + " sensitivity=sensitivity,\n", + " doIntensityWeighting=True,\n", + " macro_pixel_correction=mpcorrection,\n", + " )\n", + " output.append(\n", + " calculate_eSRRF_temporal_correlations(result, esrrf_order)\n", + " )\n", "\n", " global dataset_esrrf\n", " dataset_esrrf = np.array(output)\n", @@ -326,27 +319,72 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_esrrf.tif\", dataset_esrrf)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_esrrf.tif\", dataset_esrrf)\n", - " gui_esrrf._main_display.children = gui_esrrf._main_display.children + (stackview.slice(dataset_esrrf, colormap=gui_esrrf[\"cmaps\"].value, continuous_update=True),)\n", + " gui_esrrf._main_display.children = gui_esrrf._main_display.children + (\n", + " stackview.slice(\n", + " dataset_esrrf,\n", + " colormap=gui_esrrf[\"cmaps\"].value,\n", + " continuous_update=True,\n", + " ),\n", + " )\n", "\n", "\n", "default_radius = 1.5\n", "default_sensitivity = 1\n", "default_magnification = 5\n", "default_esrrf_order = 1\n", - "gui_esrrf.add_float_slider(\"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=optimal_radius, remember_value=True)\n", - "gui_esrrf.add_int_slider(\"sensitivity\", description=\"Sensitivity:\", min=1, max=10, value=optimal_sensitivity)\n", - "gui_esrrf.add_int_slider(\"magnification\", description=\"Magnification:\", min=1, max=10, value=global_mag)\n", - "gui_esrrf.add_int_slider(\"esrrf_order\", description=\"eSRRF order:\", min=1, max=3, value=g_temp_corr)\n", - "gui_esrrf.add_label(\"-=-= Time-Lapse =-=-\")\n", - "gui_esrrf.add_int_slider(\"frames_per_timepoint\", description=\"Frames per time-point (0 - auto)\", min=0, max=dataset_original.shape[0], value=dataset_original.shape[0]//2)\n", + "gui_esrrf.add_float_slider(\n", + " \"ring_radius\",\n", + " description=\"Ring Radius:\",\n", + " min=0.1,\n", + " max=3.0,\n", + " value=optimal_radius,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"sensitivity\",\n", + " description=\"Sensitivity:\",\n", + " min=1,\n", + " max=10,\n", + " value=optimal_sensitivity,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"magnification\",\n", + " description=\"Magnification:\",\n", + " min=1,\n", + " max=10,\n", + " value=global_mag,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"esrrf_order\",\n", + " description=\"eSRRF order:\",\n", + " min=1,\n", + " max=3,\n", + " value=g_temp_corr,\n", + ")\n", + "gui_esrrf.add_label(value=\"-=-= Time-Lapse =-=-\")\n", + "gui_esrrf.add_int_slider(\n", + " \"frames_per_timepoint\",\n", + " description=\"Frames per time-point (0 - auto)\",\n", + " min=0,\n", + " max=dataset_original.shape[0],\n", + " value=dataset_original.shape[0] // 2,\n", + ")\n", + "gui_esrrf.add_checkbox(\n", + " \"mpcorrection\", description=\"Macro Pixel Correction\", value=True\n", + ")\n", "gui_esrrf.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", - "gui_esrrf.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_esrrf.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_esrrf.add_button(\"run\", description=\"Run\")\n", - "gui_esrrf['run'].on_click(run_esrrf)\n", + "gui_esrrf[\"run\"].on_click(run_esrrf)\n", "gui_esrrf.show()\n", "\n", "\n" @@ -354,7 +392,7 @@ }, { "cell_type": "markdown", - "id": "80358e39", + "id": "a718a9a5", "metadata": {}, "source": [ "## Calculate error map for the eSRRF image\n", @@ -364,13 +402,13 @@ { "cell_type": "code", "execution_count": null, - "id": "b9fbe131", + "id": "83d1042a", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create Error Map GUI\n", + "# @title Create Error Map GUI\n", "gui_error = EasyGui(\"Error\")\n", "\n", "import numpy as np\n", @@ -379,6 +417,7 @@ "from matplotlib import pyplot as plt\n", "from nanopyx.core.transform import ErrorMap\n", "\n", + "\n", "def run_error(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -387,7 +426,9 @@ " gui_error[\"run\"].description = \"Calculating...\"\n", " global errormap\n", " error_map = ErrorMap()\n", - " error_map.optimise(np.mean(dataset_original, axis=0), np.mean(dataset_esrrf, axis=0))\n", + " error_map.optimise(\n", + " np.mean(dataset_original, axis=0), np.mean(dataset_esrrf, axis=0)\n", + " )\n", " gui_error[\"run\"].disabled = False\n", " gui_error[\"run\"].description = \"Calculate\"\n", " print(\"RSE: \", error_map.getRSE())\n", @@ -399,7 +440,9 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_error_map.tif\", errormap)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map.tif\", errormap)\n", " plt.imshow(errormap)\n", " plt.axis(\"off\")\n", @@ -409,11 +452,13 @@ " with output_plot:\n", " display(Image.open(img_buf))\n", " gui_error._main_display.children = gui_error._main_display.children + (\n", - " widgets.Label(value=\"RSE: \"+str(error_map.getRSE())),\n", - " widgets.Label(value=\"RSP: \"+str(error_map.getRSP())),\n", - " output_plot)\n", + " widgets.Label(value=\"RSE: \" + str(error_map.getRSE())),\n", + " widgets.Label(value=\"RSP: \" + str(error_map.getRSP())),\n", + " output_plot,\n", + " )\n", " plt.clf()\n", "\n", + "\n", "def run_error_stack(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -427,27 +472,40 @@ " rse_rsp_table = []\n", "\n", " # Ensure datasets are 3D\n", - " if np.ndim(dataset_original) == 2: \n", - " dataset_original = np.expand_dims(dataset_original, axis=0) \n", - " if np.ndim(dataset_esrrf) == 2: \n", - " dataset_esrrf = np.expand_dims(dataset_esrrf, axis=0) \n", + " if np.ndim(dataset_original) == 2:\n", + " dataset_original = np.expand_dims(dataset_original, axis=0)\n", + " if np.ndim(dataset_esrrf) == 2:\n", + " dataset_esrrf = np.expand_dims(dataset_esrrf, axis=0)\n", + "\n", + " # Ensures datasets have same number of frames\n", + "\n", + " if dataset_original.shape[0] > dataset_esrrf.shape[0]:\n", + " factor = dataset_original.shape[0] // dataset_esrrf.shape[0]\n", + " remainder = dataset_original.shape[0] % dataset_esrrf.shape[0]\n", + " averaged_blocks = [\n", + " np.mean(dataset_original[i * factor : (i + 1) * factor], axis=0)\n", + " for i in range(dataset_esrrf.shape[0])\n", + " ]\n", + " if remainder > 0:\n", + " averaged_blocks.append(\n", + " np.mean(dataset_original[-remainder:], axis=0)\n", + " )\n", + " dataset_original = np.array(averaged_blocks)\n", "\n", " # Iterate through each slice\n", " print(\"Processing slices...\")\n", - " for i in tqdm(range(dataset_original.shape[0]),desc=\"Slices processed\"): \n", - " slice_df = dataset_original[i] # \n", - " slice_sr = dataset_esrrf[i] # \n", - " \n", + " for i in tqdm(range(dataset_original.shape[0]), desc=\"Slices processed\"):\n", + " slice_df = dataset_original[i] #\n", + " slice_sr = dataset_esrrf[i] #\n", + "\n", " error_map = ErrorMap()\n", " error_map.optimise(slice_df, slice_sr)\n", "\n", " # Store the error map and RSE/RSP values\n", " errormap_stack.append(np.array(error_map.imRSE))\n", - " rse_rsp_table.append({\n", - " \"Slice\": i,\n", - " \"RSE\": error_map.getRSE(),\n", - " \"RSP\": error_map.getRSP()\n", - " })\n", + " rse_rsp_table.append(\n", + " {\"Slice\": i, \"RSE\": error_map.getRSE(), \"RSP\": error_map.getRSP()}\n", + " )\n", "\n", " # Convert results to arrays\n", " errormap_stack = np.array(errormap_stack) # 3D stack of error maps\n", @@ -457,10 +515,16 @@ " if own_data:\n", " path = gui_data[\"upload\"].selected_path\n", " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", - " tiff.imwrite(path + os.sep + name + \"_error_map_stack.tif\", errormap_stack)\n", - " rse_rsp_table.to_csv(path + os.sep + name + \"_rse_rsp_table.csv\", index=False)\n", + " tiff.imwrite(\n", + " path + os.sep + name + \"_error_map_stack.tif\", errormap_stack\n", + " )\n", + " rse_rsp_table.to_csv(\n", + " path + os.sep + name + \"_rse_rsp_table.csv\", index=False\n", + " )\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map_stack.tif\", errormap_stack)\n", " rse_rsp_table.to_csv(name + \"_rse_rsp_table.csv\", index=False)\n", "\n", @@ -477,9 +541,13 @@ "\n", "\n", "gui_error.add_checkbox(\"save\", description=\"Save output\", value=True)\n", - "gui_error.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_error.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_error.add_button(\"run\", description=\"Calculate\")\n", "gui_error[\"run\"].on_click(run_error_stack)\n", "gui_error.show()\n", @@ -489,7 +557,7 @@ }, { "cell_type": "markdown", - "id": "c74572b3", + "id": "7acada4e", "metadata": {}, "source": [ "## Calculate FRC resolution of the diffraction limited image\n", @@ -505,7 +573,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b2909907", + "id": "5c44bfc2", "metadata": { "cellView": "form" }, @@ -551,7 +619,7 @@ " gui_frc._main_display.children = gui_frc._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=0)\n", "gui_frc.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=1)\n", @@ -565,7 +633,7 @@ }, { "cell_type": "markdown", - "id": "3b8a78c8", + "id": "7a8c60d9", "metadata": {}, "source": [ "## Calculate FRC resolution of the SR image\n", @@ -581,7 +649,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d3a2bfa7", + "id": "18f5b749", "metadata": { "cellView": "form" }, @@ -627,7 +695,7 @@ " gui_frc_esrrf._main_display.children = gui_frc_esrrf._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_esrrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_esrrf.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_esrrf[0].shape[0]-1, value=0)\n", "gui_frc_esrrf.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_esrrf[0].shape[0]-1, value=1)\n", @@ -641,7 +709,7 @@ }, { "cell_type": "markdown", - "id": "a14e3e50", + "id": "dfb690d0", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the diffraction limited image\n", @@ -658,7 +726,7 @@ { "cell_type": "code", "execution_count": null, - "id": "405400f8", + "id": "d6eccdf8", "metadata": { "cellView": "form" }, @@ -704,7 +772,7 @@ " gui_decorr._main_display.children = gui_decorr._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_original.shape[0]-1, value=0)\n", "gui_decorr.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", @@ -719,7 +787,7 @@ }, { "cell_type": "markdown", - "id": "93713482", + "id": "290a5fc0", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the SR image\n", @@ -736,7 +804,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25f90483", + "id": "60a23520", "metadata": { "cellView": "form" }, @@ -782,7 +850,7 @@ " gui_decorr_esrrf._main_display.children = gui_decorr_esrrf._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_esrrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_esrrf.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_esrrf.shape[0]-1, value=0)\n", "gui_decorr_esrrf.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", diff --git a/notebooks/SRMetrics.ipynb b/notebooks/SRMetrics.ipynb index 3f1034c6..fc0034c6 100644 --- a/notebooks/SRMetrics.ipynb +++ b/notebooks/SRMetrics.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "5622371f", + "id": "9742f460", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -26,29 +26,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9e477137", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d1d6a6dc", + "id": "ce41f905", "metadata": { "cellView": "form" }, @@ -80,7 +58,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -102,7 +83,7 @@ }, { "cell_type": "markdown", - "id": "efd3bfc6", + "id": "5feab865", "metadata": {}, "source": [ "## Load difraction limited image (only needed if you want to use the FRC and Decorrelation analysis on this image or if you want to perform the Error Map analysis)\n", @@ -112,7 +93,7 @@ { "cell_type": "code", "execution_count": null, - "id": "de432d18", + "id": "a5bb0805", "metadata": { "cellView": "form" }, @@ -126,7 +107,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data_df.add_label(\"Select data to use:\")\n", + " gui_data_df.add_label(value=\"Select data to use:\")\n", " gui_data_df.add_file_upload(\"upload\")\n", " gui_data_df.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -137,7 +118,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data_df.add_label(\"Select data to use:\")\n", + " gui_data_df.add_label(value=\"Select data to use:\")\n", " gui_data_df.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data_df.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -196,7 +177,7 @@ }, { "cell_type": "markdown", - "id": "2074fdd2", + "id": "f3e45bcc", "metadata": {}, "source": [ "## Load super-resolved image\n", @@ -206,7 +187,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1942d9ad", + "id": "79311067", "metadata": { "cellView": "form" }, @@ -220,7 +201,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data_sr.add_label(\"Select data to use:\")\n", + " gui_data_sr.add_label(value=\"Select data to use:\")\n", " gui_data_sr.add_file_upload(\"upload\")\n", " gui_data_sr.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -231,7 +212,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data_sr.add_label(\"Select data to use:\")\n", + " gui_data_sr.add_label(value=\"Select data to use:\")\n", " gui_data_sr.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data_sr.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -290,7 +271,7 @@ }, { "cell_type": "markdown", - "id": "9158987c", + "id": "830472cd", "metadata": {}, "source": [ "## Calculate Error Map\n", @@ -300,13 +281,13 @@ { "cell_type": "code", "execution_count": null, - "id": "2f078493", + "id": "10d68395", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create Error Map GUI\n", + "# @title Create Error Map GUI\n", "gui_error = EasyGui(\"Error\")\n", "\n", "import numpy as np\n", @@ -315,6 +296,7 @@ "from matplotlib import pyplot as plt\n", "from nanopyx.core.transform import ErrorMap\n", "\n", + "\n", "def run_error(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -323,7 +305,9 @@ " gui_error[\"run\"].description = \"Calculating...\"\n", " global errormap\n", " error_map = ErrorMap()\n", - " error_map.optimise(np.mean(dataset_df, axis=0), np.mean(dataset_sr, axis=0))\n", + " error_map.optimise(\n", + " np.mean(dataset_df, axis=0), np.mean(dataset_sr, axis=0)\n", + " )\n", " gui_error[\"run\"].disabled = False\n", " gui_error[\"run\"].description = \"Calculate\"\n", " print(\"RSE: \", error_map.getRSE())\n", @@ -335,7 +319,9 @@ " name = gui_data_sr[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_error_map.tif\", errormap)\n", " else:\n", - " name = gui_data_sr[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data_sr[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map.tif\", errormap)\n", " plt.imshow(errormap)\n", " plt.axis(\"off\")\n", @@ -345,11 +331,13 @@ " with output_plot:\n", " display(Image.open(img_buf))\n", " gui_error._main_display.children = gui_error._main_display.children + (\n", - " widgets.Label(value=\"RSE: \"+str(error_map.getRSE())),\n", - " widgets.Label(value=\"RSP: \"+str(error_map.getRSP())),\n", - " output_plot)\n", + " widgets.Label(value=\"RSE: \" + str(error_map.getRSE())),\n", + " widgets.Label(value=\"RSP: \" + str(error_map.getRSP())),\n", + " output_plot,\n", + " )\n", " plt.clf()\n", "\n", + "\n", "def run_error_stack(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -363,27 +351,40 @@ " rse_rsp_table = []\n", "\n", " # Ensure datasets are 3D\n", - " if np.ndim(dataset_df) == 2: \n", - " dataset_df = np.expand_dims(dataset_df, axis=0) \n", - " if np.ndim(dataset_sr) == 2: \n", - " dataset_sr = np.expand_dims(dataset_sr, axis=0) \n", + " if np.ndim(dataset_df) == 2:\n", + " dataset_df = np.expand_dims(dataset_df, axis=0)\n", + " if np.ndim(dataset_sr) == 2:\n", + " dataset_sr = np.expand_dims(dataset_sr, axis=0)\n", + "\n", + " # Ensures datasets have same number of frames\n", + "\n", + " if dataset_df.shape[0] > dataset_sr.shape[0]:\n", + " factor = dataset_df.shape[0] // dataset_sr.shape[0]\n", + " remainder = dataset_df.shape[0] % dataset_sr.shape[0]\n", + " averaged_blocks = [\n", + " np.mean(dataset_df[i * factor : (i + 1) * factor], axis=0)\n", + " for i in range(dataset_sr.shape[0])\n", + " ]\n", + " if remainder > 0:\n", + " averaged_blocks.append(\n", + " np.mean(dataset_df[-remainder:], axis=0)\n", + " )\n", + " dataset_df = np.array(averaged_blocks)\n", "\n", " # Iterate through each slice\n", " print(\"Processing slices...\")\n", - " for i in tqdm(range(dataset_df.shape[0]),desc=\"Slices processed\"): \n", - " slice_df = dataset_df[i] # \n", - " slice_sr = dataset_sr[i] # \n", - " \n", + " for i in tqdm(range(dataset_df.shape[0]), desc=\"Slices processed\"):\n", + " slice_df = dataset_df[i] #\n", + " slice_sr = dataset_sr[i] #\n", + "\n", " error_map = ErrorMap()\n", " error_map.optimise(slice_df, slice_sr)\n", "\n", " # Store the error map and RSE/RSP values\n", " errormap_stack.append(np.array(error_map.imRSE))\n", - " rse_rsp_table.append({\n", - " \"Slice\": i,\n", - " \"RSE\": error_map.getRSE(),\n", - " \"RSP\": error_map.getRSP()\n", - " })\n", + " rse_rsp_table.append(\n", + " {\"Slice\": i, \"RSE\": error_map.getRSE(), \"RSP\": error_map.getRSP()}\n", + " )\n", "\n", " # Convert results to arrays\n", " errormap_stack = np.array(errormap_stack) # 3D stack of error maps\n", @@ -393,10 +394,16 @@ " if own_data_sr:\n", " path = gui_data_sr[\"upload\"].selected_path\n", " name = gui_data_sr[\"upload\"].selected_filename.split(\".\")[0]\n", - " tiff.imwrite(path + os.sep + name + \"_error_map_stack.tif\", errormap_stack)\n", - " rse_rsp_table.to_csv(path + os.sep + name + \"_rse_rsp_table.csv\", index=False)\n", + " tiff.imwrite(\n", + " path + os.sep + name + \"_error_map_stack.tif\", errormap_stack\n", + " )\n", + " rse_rsp_table.to_csv(\n", + " path + os.sep + name + \"_rse_rsp_table.csv\", index=False\n", + " )\n", " else:\n", - " name = gui_data_sr[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data_sr[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map_stack.tif\", errormap_stack)\n", " rse_rsp_table.to_csv(name + \"_rse_rsp_table.csv\", index=False)\n", "\n", @@ -413,9 +420,13 @@ "\n", "\n", "gui_error.add_checkbox(\"save\", description=\"Save output\", value=True)\n", - "gui_error.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_error.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_error.add_button(\"run\", description=\"Calculate\")\n", "gui_error[\"run\"].on_click(run_error_stack)\n", "gui_error.show()\n", @@ -425,7 +436,7 @@ }, { "cell_type": "markdown", - "id": "cf64d5d3", + "id": "91e0077b", "metadata": {}, "source": [ "# Calculate FRC of the diffraction limited image\n", @@ -441,7 +452,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1dfcdb21", + "id": "fd5f7912", "metadata": { "cellView": "form" }, @@ -487,7 +498,7 @@ " gui_frc_df._main_display.children = gui_frc_df._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_df.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_df[0].shape[0]-1, value=0)\n", "gui_frc_df.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_df[0].shape[0]-1, value=1)\n", @@ -501,7 +512,7 @@ }, { "cell_type": "markdown", - "id": "733c185c", + "id": "6bd57aae", "metadata": {}, "source": [ "# Calculate FRC of the SR image\n", @@ -517,7 +528,7 @@ { "cell_type": "code", "execution_count": null, - "id": "83e6929a", + "id": "688b043c", "metadata": { "cellView": "form" }, @@ -563,7 +574,7 @@ " gui_frc_sr._main_display.children = gui_frc_sr._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_sr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_sr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_sr.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_sr.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_sr[0].shape[0]-1, value=0)\n", "gui_frc_sr.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_sr[0].shape[0]-1, value=1)\n", @@ -577,7 +588,7 @@ }, { "cell_type": "markdown", - "id": "d881c533", + "id": "e7fe12d3", "metadata": {}, "source": [ "# Calculate Decorrelation analysis of diffraction limited image\n", @@ -594,7 +605,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bb67c169", + "id": "2fc498d0", "metadata": { "cellView": "form" }, @@ -640,7 +651,7 @@ " gui_decorr_df._main_display.children = gui_decorr_df._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_df.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_df.shape[0]-1, value=0)\n", "gui_decorr_df.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", @@ -655,7 +666,7 @@ }, { "cell_type": "markdown", - "id": "320c5ae7", + "id": "61efd725", "metadata": {}, "source": [ "# Calculate Decorrelation analysis of SR image\n", @@ -672,7 +683,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77057b97", + "id": "812b3075", "metadata": { "cellView": "form" }, @@ -718,7 +729,7 @@ " gui_decorr_sr._main_display.children = gui_decorr_sr._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_sr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_sr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_sr.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_sr.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_sr.shape[0]-1, value=0)\n", "gui_decorr_sr.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", diff --git a/notebooks/SRRFandQC.ipynb b/notebooks/SRRFandQC.ipynb index 2cf3c7bc..4c169f13 100644 --- a/notebooks/SRRFandQC.ipynb +++ b/notebooks/SRRFandQC.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "17e14260", + "id": "127bc22a", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -28,29 +28,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7acbf83c", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8315ab2c", + "id": "f649e22a", "metadata": { "cellView": "form" }, @@ -82,7 +60,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -105,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5aeb0a4c", + "id": "ab45f6e3", "metadata": { "cellView": "form" }, @@ -119,7 +100,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -130,7 +111,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -189,7 +170,7 @@ }, { "cell_type": "markdown", - "id": "09c3f069", + "id": "988237bc", "metadata": {}, "source": [ "# Use SRRF to generate a super-resolved image\n", @@ -206,16 +187,19 @@ { "cell_type": "code", "execution_count": null, - "id": "85ced68d", + "id": "1efcc50d", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create SRRF GUI\n", + "# @title Create SRRF GUI\n", "gui_srrf = EasyGui(\"srrf\")\n", "from nanopyx.methods import SRRF\n", - "from nanopyx.core.transform.sr_temporal_correlations import calculate_SRRF_temporal_correlations\n", + "from nanopyx.core.transform.sr_temporal_correlations import (\n", + " calculate_SRRF_temporal_correlations,\n", + ")\n", + "\n", "\n", "def run_srrf(b):\n", " clear_output()\n", @@ -225,6 +209,7 @@ " magnification = gui_srrf[\"magnification\"].value\n", " frames_per_timepoint = gui_srrf[\"frames_per_timepoint\"].value\n", " srrf_order = gui_srrf[\"srrf_order\"].value\n", + " mpcorrection = gui_srrf[\"mpcorrection\"].value\n", " # disable button while running\n", " gui_srrf[\"run\"].disabled = True\n", " gui_srrf[\"run\"].description = \"Running...\"\n", @@ -233,14 +218,21 @@ " elif frames_per_timepoint > dataset_original.shape[0]:\n", " frames_per_timepoint = dataset_original.shape[0]\n", "\n", - " output= []\n", + " output = []\n", "\n", " for i in range(dataset_original.shape[0] // frames_per_timepoint):\n", - " block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint]\n", - " result = SRRF(block, magnification=magnification, ringRadius=ring_radius,\n", - " radialityPositivityConstraint=True,\n", - " doIntensityWeighting=True)\n", - " output.append(calculate_SRRF_temporal_correlations(result[0], srrf_order))\n", + " block = dataset_original[\n", + " i * frames_per_timepoint : (i + 1) * frames_per_timepoint\n", + " ]\n", + " result = SRRF(\n", + " block,\n", + " magnification=magnification,\n", + " ringRadius=ring_radius,\n", + " radialityPositivityConstraint=True,\n", + " doIntensityWeighting=True,\n", + " macro_pixel_correction=mpcorrection,\n", + " )\n", + " output.append(calculate_SRRF_temporal_correlations(result, srrf_order))\n", "\n", " global dataset_srrf\n", " dataset_srrf = np.array(output)\n", @@ -253,21 +245,49 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_srrf.tif\", dataset_srrf)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_srrf.tif\", dataset_srrf)\n", - " gui_srrf._main_display.children = gui_srrf._main_display.children + (stackview.slice(dataset_srrf, colormap=gui_srrf[\"cmaps\"].value, continuous_update=True),)\n", - "\n", - "gui_srrf.add_float_slider(\"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=0.5, remember_value=True)\n", - "gui_srrf.add_int_slider(\"magnification\", description=\"Magnification:\", min=1, max=10, value=5)\n", - "gui_srrf.add_int_slider(\"srrf_order\", description=\"SRRF order:\", min=-1, max=4, value=3)\n", - "gui_srrf.add_label(\"-=-= Time-Lapse =-=-\")\n", - "gui_srrf.add_int_slider(\"frames_per_timepoint\", description=\"Frames per time-point (0 - auto)\", min=1, max=dataset_original.shape[0], value=dataset_original.shape[0]//2)\n", + " gui_srrf._main_display.children = gui_srrf._main_display.children + (\n", + " stackview.slice(\n", + " dataset_srrf,\n", + " colormap=gui_srrf[\"cmaps\"].value,\n", + " continuous_update=True,\n", + " ),\n", + " )\n", + "\n", + "\n", + "gui_srrf.add_float_slider(\n", + " \"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=0.5\n", + ")\n", + "gui_srrf.add_int_slider(\n", + " \"magnification\", description=\"Magnification:\", min=1, max=10, value=5\n", + ")\n", + "gui_srrf.add_int_slider(\n", + " \"srrf_order\", description=\"SRRF order:\", min=-1, max=4, value=3\n", + ")\n", + "gui_srrf.add_label(value=\"-=-= Time-Lapse =-=-\")\n", + "gui_srrf.add_int_slider(\n", + " \"frames_per_timepoint\",\n", + " description=\"Frames per time-point (0 - auto)\",\n", + " min=1,\n", + " max=dataset_original.shape[0],\n", + " value=dataset_original.shape[0] // 2,\n", + ")\n", + "gui_srrf.add_checkbox(\n", + " \"mpcorrection\", description=\"Macro Pixel Correction\", value=True\n", + ")\n", "gui_srrf.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", - "gui_srrf.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_srrf.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_srrf.add_button(\"run\", description=\"Run\")\n", - "gui_srrf['run'].on_click(run_srrf)\n", + "gui_srrf[\"run\"].on_click(run_srrf)\n", "gui_srrf.show()\n", "\n", "\n" @@ -275,7 +295,7 @@ }, { "cell_type": "markdown", - "id": "1eadfed0", + "id": "e9c6c1cd", "metadata": {}, "source": [ "## Calculate error map for the SRRF image\n", @@ -285,13 +305,13 @@ { "cell_type": "code", "execution_count": null, - "id": "aeb89a7c", + "id": "b68a496e", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create Error Map GUI\n", + "# @title Create Error Map GUI\n", "gui_error = EasyGui(\"Error\")\n", "\n", "import numpy as np\n", @@ -300,6 +320,7 @@ "from matplotlib import pyplot as plt\n", "from nanopyx.core.transform import ErrorMap\n", "\n", + "\n", "def run_error(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -308,7 +329,9 @@ " gui_error[\"run\"].description = \"Calculating...\"\n", " global errormap\n", " error_map = ErrorMap()\n", - " error_map.optimise(np.mean(dataset_original, axis=0), np.mean(dataset_srrf, axis=0))\n", + " error_map.optimise(\n", + " np.mean(dataset_original, axis=0), np.mean(dataset_srrf, axis=0)\n", + " )\n", " gui_error[\"run\"].disabled = False\n", " gui_error[\"run\"].description = \"Calculate\"\n", " print(\"RSE: \", error_map.getRSE())\n", @@ -320,7 +343,9 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_error_map.tif\", errormap)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map.tif\", errormap)\n", " plt.imshow(errormap)\n", " plt.axis(\"off\")\n", @@ -330,11 +355,13 @@ " with output_plot:\n", " display(Image.open(img_buf))\n", " gui_error._main_display.children = gui_error._main_display.children + (\n", - " widgets.Label(value=\"RSE: \"+str(error_map.getRSE())),\n", - " widgets.Label(value=\"RSP: \"+str(error_map.getRSP())),\n", - " output_plot)\n", + " widgets.Label(value=\"RSE: \" + str(error_map.getRSE())),\n", + " widgets.Label(value=\"RSP: \" + str(error_map.getRSP())),\n", + " output_plot,\n", + " )\n", " plt.clf()\n", "\n", + "\n", "def run_error_stack(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -348,27 +375,40 @@ " rse_rsp_table = []\n", "\n", " # Ensure datasets are 3D\n", - " if np.ndim(dataset_original) == 2: \n", - " dataset_original = np.expand_dims(dataset_original, axis=0) \n", - " if np.ndim(dataset_srrf) == 2: \n", - " dataset_srrf = np.expand_dims(dataset_srrf, axis=0) \n", + " if np.ndim(dataset_original) == 2:\n", + " dataset_original = np.expand_dims(dataset_original, axis=0)\n", + " if np.ndim(dataset_srrf) == 2:\n", + " dataset_srrf = np.expand_dims(dataset_srrf, axis=0)\n", + "\n", + " # Ensures datasets have same number of frames\n", + "\n", + " if dataset_original.shape[0] > dataset_srrf.shape[0]:\n", + " factor = dataset_original.shape[0] // dataset_srrf.shape[0]\n", + " remainder = dataset_original.shape[0] % dataset_srrf.shape[0]\n", + " averaged_blocks = [\n", + " np.mean(dataset_original[i * factor : (i + 1) * factor], axis=0)\n", + " for i in range(dataset_srrf.shape[0])\n", + " ]\n", + " if remainder > 0:\n", + " averaged_blocks.append(\n", + " np.mean(dataset_original[-remainder:], axis=0)\n", + " )\n", + " dataset_original = np.array(averaged_blocks)\n", "\n", " # Iterate through each slice\n", " print(\"Processing slices...\")\n", - " for i in tqdm(range(dataset_original.shape[0]),desc=\"Slices processed\"): \n", - " slice_df = dataset_original[i] # \n", - " slice_sr = dataset_srrf[i] # \n", - " \n", + " for i in tqdm(range(dataset_original.shape[0]), desc=\"Slices processed\"):\n", + " slice_df = dataset_original[i] #\n", + " slice_sr = dataset_srrf[i] #\n", + "\n", " error_map = ErrorMap()\n", " error_map.optimise(slice_df, slice_sr)\n", "\n", " # Store the error map and RSE/RSP values\n", " errormap_stack.append(np.array(error_map.imRSE))\n", - " rse_rsp_table.append({\n", - " \"Slice\": i,\n", - " \"RSE\": error_map.getRSE(),\n", - " \"RSP\": error_map.getRSP()\n", - " })\n", + " rse_rsp_table.append(\n", + " {\"Slice\": i, \"RSE\": error_map.getRSE(), \"RSP\": error_map.getRSP()}\n", + " )\n", "\n", " # Convert results to arrays\n", " errormap_stack = np.array(errormap_stack) # 3D stack of error maps\n", @@ -378,10 +418,16 @@ " if own_data:\n", " path = gui_data[\"upload\"].selected_path\n", " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", - " tiff.imwrite(path + os.sep + name + \"_error_map_stack.tif\", errormap_stack)\n", - " rse_rsp_table.to_csv(path + os.sep + name + \"_rse_rsp_table.csv\", index=False)\n", + " tiff.imwrite(\n", + " path + os.sep + name + \"_error_map_stack.tif\", errormap_stack\n", + " )\n", + " rse_rsp_table.to_csv(\n", + " path + os.sep + name + \"_rse_rsp_table.csv\", index=False\n", + " )\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map_stack.tif\", errormap_stack)\n", " rse_rsp_table.to_csv(name + \"_rse_rsp_table.csv\", index=False)\n", "\n", @@ -398,9 +444,13 @@ "\n", "\n", "gui_error.add_checkbox(\"save\", description=\"Save output\", value=True)\n", - "gui_error.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_error.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_error.add_button(\"run\", description=\"Calculate\")\n", "gui_error[\"run\"].on_click(run_error_stack)\n", "gui_error.show()\n", @@ -410,7 +460,7 @@ }, { "cell_type": "markdown", - "id": "a1272841", + "id": "d5cfb112", "metadata": {}, "source": [ "## Calculate FRC resolution of the diffraction limited image\n", @@ -426,7 +476,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f62cd72a", + "id": "7cd4c902", "metadata": { "cellView": "form" }, @@ -472,7 +522,7 @@ " gui_frc_df._main_display.children = gui_frc_df._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_df.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=0)\n", "gui_frc_df.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=1)\n", @@ -486,7 +536,7 @@ }, { "cell_type": "markdown", - "id": "bf0fa835", + "id": "0e2e01fb", "metadata": {}, "source": [ "## Calculate FRC resolution of the SR image\n", @@ -502,7 +552,7 @@ { "cell_type": "code", "execution_count": null, - "id": "06e8367f", + "id": "69644270", "metadata": { "cellView": "form" }, @@ -548,7 +598,7 @@ " gui_frc_srrf._main_display.children = gui_frc_srrf._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_srrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_srrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_srrf.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_srrf[0].shape[0]-1, value=0)\n", "gui_frc_srrf.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_srrf[0].shape[0]-1, value=1)\n", @@ -562,7 +612,7 @@ }, { "cell_type": "markdown", - "id": "fb9621fc", + "id": "76beec23", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the diffraction limited image\n", @@ -579,7 +629,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14d30daa", + "id": "e47e802d", "metadata": { "cellView": "form" }, @@ -625,7 +675,7 @@ " gui_decorr_df._main_display.children = gui_decorr_df._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_df.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_df.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_df.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_original.shape[0]-1, value=0)\n", "gui_decorr_df.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", @@ -640,7 +690,7 @@ }, { "cell_type": "markdown", - "id": "a051a495", + "id": "dc0f812e", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the SR image\n", @@ -657,7 +707,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8dc2fbb2", + "id": "12dd4e97", "metadata": { "cellView": "form" }, @@ -703,7 +753,7 @@ " gui_decorr._main_display.children = gui_decorr._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_srrf.shape[0]-1, value=0)\n", "gui_decorr.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", diff --git a/notebooks/eSRRFandQC.ipynb b/notebooks/eSRRFandQC.ipynb index a0d5abd6..1b8c0946 100644 --- a/notebooks/eSRRFandQC.ipynb +++ b/notebooks/eSRRFandQC.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "d30993c0", + "id": "91304c56", "metadata": {}, "source": [ "# NanoPyx \"Codeless\" Jupyter Notebook\n", @@ -28,29 +28,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c035a99e", - "metadata": { - "cellView": "form" - }, - "outputs": [], - "source": [ - "#@title Fix OpenCL if needed in Google Colab\n", - "import sys\n", - "\n", - "IN_COLAB = 'google.colab' in sys.modules\n", - "if IN_COLAB:\n", - " !sudo apt-get update -qq\n", - " !sudo apt-get purge -qq *nvidia* -y\n", - " !sudo DEBIAN_FRONTEND=noninteractive apt-get install -qq nvidia-driver-530 -y\n", - " exit(0)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0d233e1", + "id": "a4b967bf", "metadata": { "cellView": "form" }, @@ -82,7 +60,10 @@ "from IPython.display import display, clear_output\n", "from matplotlib import pyplot as plt\n", "\n", - "from nanopyx.core.utils.easy_gui import EasyGui\n", + "try:\n", + " from ezinput import EZInput as EasyGui\n", + "except ImportError:\n", + " from nanopyx.core.utils.easy_gui import EasyGui\n", "from nanopyx.core.utils.find_files import find_files\n", "from nanopyx.data.download import ExampleDataManager\n", "\n", @@ -105,7 +86,7 @@ { "cell_type": "code", "execution_count": null, - "id": "82f1b92d", + "id": "28c5296b", "metadata": { "cellView": "form" }, @@ -119,7 +100,7 @@ "\n", "def on_button_select_own(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_file_upload(\"upload\")\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", " options=sorted(list(mpl.colormaps)),\n", @@ -130,7 +111,7 @@ "\n", "def on_button_select_example(b):\n", " clear_output()\n", - " gui_data.add_label(\"Select data to use:\")\n", + " gui_data.add_label(value=\"Select data to use:\")\n", " gui_data.add_dropdown(\"data_source\", options=image_files,\n", " value=\"Example dataset: \"+example_datasets[4], remember_value=True)\n", " gui_data.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", @@ -189,7 +170,7 @@ }, { "cell_type": "markdown", - "id": "9aff14d9", + "id": "cc7a9fd5", "metadata": {}, "source": [ "# Use eSRRF to generate a super-resolved image\n", @@ -206,16 +187,19 @@ { "cell_type": "code", "execution_count": null, - "id": "4f7338cf", + "id": "429e61b2", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create eSRRF GUI\n", + "# @title Create eSRRF GUI\n", "gui_esrrf = EasyGui(\"esrrf\")\n", "from nanopyx.methods import eSRRF\n", - "from nanopyx.core.transform.sr_temporal_correlations import calculate_eSRRF_temporal_correlations\n", + "from nanopyx.core.transform.sr_temporal_correlations import (\n", + " calculate_eSRRF_temporal_correlations,\n", + ")\n", + "\n", "\n", "def run_esrrf(b):\n", " clear_output()\n", @@ -225,7 +209,7 @@ " magnification = gui_esrrf[\"magnification\"].value\n", " frames_per_timepoint = gui_esrrf[\"frames_per_timepoint\"].value\n", " sensitivity = gui_esrrf[\"sensitivity\"].value\n", - "\n", + " mpcorrection = gui_esrrf[\"mpcorrection\"].value\n", " esrrf_order = gui_esrrf[\"esrrf_order\"].value\n", " if esrrf_order == 1:\n", " esrrf_order = \"AVG\"\n", @@ -241,14 +225,23 @@ " elif frames_per_timepoint > dataset_original.shape[0]:\n", " frames_per_timepoint = dataset_original.shape[0]\n", "\n", - " output= []\n", + " output = []\n", "\n", " for i in range(dataset_original.shape[0] // frames_per_timepoint):\n", - " block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint]\n", - " result = eSRRF(block, magnification=magnification, radius=ring_radius,\n", - " sensitivity=sensitivity,\n", - " doIntensityWeighting=True)\n", - " output.append(calculate_eSRRF_temporal_correlations(result[0], esrrf_order))\n", + " block = dataset_original[\n", + " i * frames_per_timepoint : (i + 1) * frames_per_timepoint\n", + " ]\n", + " result = eSRRF(\n", + " block,\n", + " magnification=magnification,\n", + " radius=ring_radius,\n", + " sensitivity=sensitivity,\n", + " doIntensityWeighting=True,\n", + " macro_pixel_correction=mpcorrection,\n", + " )\n", + " output.append(\n", + " calculate_eSRRF_temporal_correlations(result, esrrf_order)\n", + " )\n", "\n", " global dataset_esrrf\n", " dataset_esrrf = np.array(output)\n", @@ -261,27 +254,72 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_esrrf.tif\", dataset_esrrf)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_esrrf.tif\", dataset_esrrf)\n", - " gui_esrrf._main_display.children = gui_esrrf._main_display.children + (stackview.slice(dataset_esrrf, colormap=gui_esrrf[\"cmaps\"].value, continuous_update=True),)\n", + " gui_esrrf._main_display.children = gui_esrrf._main_display.children + (\n", + " stackview.slice(\n", + " dataset_esrrf,\n", + " colormap=gui_esrrf[\"cmaps\"].value,\n", + " continuous_update=True,\n", + " ),\n", + " )\n", "\n", "\n", "default_radius = 1.5\n", "default_sensitivity = 1\n", "default_magnification = 5\n", "default_esrrf_order = 1\n", - "gui_esrrf.add_float_slider(\"ring_radius\", description=\"Ring Radius:\", min=0.1, max=3.0, value=default_radius, remember_value=True)\n", - "gui_esrrf.add_int_slider(\"sensitivity\", description=\"Sensitivity:\", min=1, max=10, value=default_sensitivity)\n", - "gui_esrrf.add_int_slider(\"magnification\", description=\"Magnification:\", min=1, max=10, value=default_magnification)\n", - "gui_esrrf.add_int_slider(\"esrrf_order\", description=\"eSRRF order:\", min=1, max=3, value=default_esrrf_order)\n", - "gui_esrrf.add_label(\"-=-= Time-Lapse =-=-\")\n", - "gui_esrrf.add_int_slider(\"frames_per_timepoint\", description=\"Frames per time-point (0 - auto)\", min=0, max=dataset_original.shape[0], value=dataset_original.shape[0]//2)\n", + "gui_esrrf.add_float_slider(\n", + " \"ring_radius\",\n", + " description=\"Ring Radius:\",\n", + " min=0.1,\n", + " max=3.0,\n", + " value=default_radius,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"sensitivity\",\n", + " description=\"Sensitivity:\",\n", + " min=1,\n", + " max=10,\n", + " value=default_sensitivity,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"magnification\",\n", + " description=\"Magnification:\",\n", + " min=1,\n", + " max=10,\n", + " value=default_magnification,\n", + ")\n", + "gui_esrrf.add_int_slider(\n", + " \"esrrf_order\",\n", + " description=\"eSRRF order:\",\n", + " min=1,\n", + " max=3,\n", + " value=default_esrrf_order,\n", + ")\n", + "gui_esrrf.add_label(value=\"-=-= Time-Lapse =-=-\")\n", + "gui_esrrf.add_int_slider(\n", + " \"frames_per_timepoint\",\n", + " description=\"Frames per time-point (0 - auto)\",\n", + " min=0,\n", + " max=dataset_original.shape[0],\n", + " value=dataset_original.shape[0] // 2,\n", + ")\n", + "gui_esrrf.add_checkbox(\n", + " \"mpcorrection\", description=\"Macro Pixel Correction\", value=True\n", + ")\n", "gui_esrrf.add_checkbox(\"save\", description=\"Save Output\", value=True)\n", - "gui_esrrf.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_esrrf.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_esrrf.add_button(\"run\", description=\"Run\")\n", - "gui_esrrf['run'].on_click(run_esrrf)\n", + "gui_esrrf[\"run\"].on_click(run_esrrf)\n", "gui_esrrf.show()\n", "\n", "\n" @@ -289,7 +327,7 @@ }, { "cell_type": "markdown", - "id": "09c8f79f", + "id": "7ddaa874", "metadata": {}, "source": [ "## Calculate error map for the eSRRF image\n", @@ -299,13 +337,13 @@ { "cell_type": "code", "execution_count": null, - "id": "88af925f", + "id": "3cf50f12", "metadata": { "cellView": "form" }, "outputs": [], "source": [ - "#@title Create Error Map GUI\n", + "# @title Create Error Map GUI\n", "gui_error = EasyGui(\"Error\")\n", "\n", "import numpy as np\n", @@ -314,6 +352,7 @@ "from matplotlib import pyplot as plt\n", "from nanopyx.core.transform import ErrorMap\n", "\n", + "\n", "def run_error(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -322,7 +361,9 @@ " gui_error[\"run\"].description = \"Calculating...\"\n", " global errormap\n", " error_map = ErrorMap()\n", - " error_map.optimise(np.mean(dataset_original, axis=0), np.mean(dataset_esrrf, axis=0))\n", + " error_map.optimise(\n", + " np.mean(dataset_original, axis=0), np.mean(dataset_esrrf, axis=0)\n", + " )\n", " gui_error[\"run\"].disabled = False\n", " gui_error[\"run\"].description = \"Calculate\"\n", " print(\"RSE: \", error_map.getRSE())\n", @@ -334,7 +375,9 @@ " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", " tiff.imwrite(path + os.sep + name + \"_error_map.tif\", errormap)\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map.tif\", errormap)\n", " plt.imshow(errormap)\n", " plt.axis(\"off\")\n", @@ -344,11 +387,13 @@ " with output_plot:\n", " display(Image.open(img_buf))\n", " gui_error._main_display.children = gui_error._main_display.children + (\n", - " widgets.Label(value=\"RSE: \"+str(error_map.getRSE())),\n", - " widgets.Label(value=\"RSP: \"+str(error_map.getRSP())),\n", - " output_plot)\n", + " widgets.Label(value=\"RSE: \" + str(error_map.getRSE())),\n", + " widgets.Label(value=\"RSP: \" + str(error_map.getRSP())),\n", + " output_plot,\n", + " )\n", " plt.clf()\n", "\n", + "\n", "def run_error_stack(b):\n", " clear_output()\n", " gui_error.show()\n", @@ -362,27 +407,40 @@ " rse_rsp_table = []\n", "\n", " # Ensure datasets are 3D\n", - " if np.ndim(dataset_original) == 2: \n", - " dataset_original = np.expand_dims(dataset_original, axis=0) \n", - " if np.ndim(dataset_esrrf) == 2: \n", - " dataset_esrrf = np.expand_dims(dataset_esrrf, axis=0) \n", + " if np.ndim(dataset_original) == 2:\n", + " dataset_original = np.expand_dims(dataset_original, axis=0)\n", + " if np.ndim(dataset_esrrf) == 2:\n", + " dataset_esrrf = np.expand_dims(dataset_esrrf, axis=0)\n", + "\n", + " # Ensures datasets have same number of frames\n", + "\n", + " if dataset_original.shape[0] > dataset_esrrf.shape[0]:\n", + " factor = dataset_original.shape[0] // dataset_esrrf.shape[0]\n", + " remainder = dataset_original.shape[0] % dataset_esrrf.shape[0]\n", + " averaged_blocks = [\n", + " np.mean(dataset_original[i * factor : (i + 1) * factor], axis=0)\n", + " for i in range(dataset_esrrf.shape[0])\n", + " ]\n", + " if remainder > 0:\n", + " averaged_blocks.append(\n", + " np.mean(dataset_original[-remainder:], axis=0)\n", + " )\n", + " dataset_original = np.array(averaged_blocks)\n", "\n", " # Iterate through each slice\n", " print(\"Processing slices...\")\n", - " for i in tqdm(range(dataset_original.shape[0]),desc=\"Slices processed\"): \n", - " slice_df = dataset_original[i] # \n", - " slice_sr = dataset_esrrf[i] # \n", - " \n", + " for i in tqdm(range(dataset_original.shape[0]), desc=\"Slices processed\"):\n", + " slice_df = dataset_original[i] #\n", + " slice_sr = dataset_esrrf[i] #\n", + "\n", " error_map = ErrorMap()\n", " error_map.optimise(slice_df, slice_sr)\n", "\n", " # Store the error map and RSE/RSP values\n", " errormap_stack.append(np.array(error_map.imRSE))\n", - " rse_rsp_table.append({\n", - " \"Slice\": i,\n", - " \"RSE\": error_map.getRSE(),\n", - " \"RSP\": error_map.getRSP()\n", - " })\n", + " rse_rsp_table.append(\n", + " {\"Slice\": i, \"RSE\": error_map.getRSE(), \"RSP\": error_map.getRSP()}\n", + " )\n", "\n", " # Convert results to arrays\n", " errormap_stack = np.array(errormap_stack) # 3D stack of error maps\n", @@ -392,10 +450,16 @@ " if own_data:\n", " path = gui_data[\"upload\"].selected_path\n", " name = gui_data[\"upload\"].selected_filename.split(\".\")[0]\n", - " tiff.imwrite(path + os.sep + name + \"_error_map_stack.tif\", errormap_stack)\n", - " rse_rsp_table.to_csv(path + os.sep + name + \"_rse_rsp_table.csv\", index=False)\n", + " tiff.imwrite(\n", + " path + os.sep + name + \"_error_map_stack.tif\", errormap_stack\n", + " )\n", + " rse_rsp_table.to_csv(\n", + " path + os.sep + name + \"_rse_rsp_table.csv\", index=False\n", + " )\n", " else:\n", - " name = gui_data[\"data_source\"].value.replace(\"Example dataset: \", \"\")\n", + " name = gui_data[\"data_source\"].value.replace(\n", + " \"Example dataset: \", \"\"\n", + " )\n", " tiff.imwrite(name + \"_error_map_stack.tif\", errormap_stack)\n", " rse_rsp_table.to_csv(name + \"_rse_rsp_table.csv\", index=False)\n", "\n", @@ -412,9 +476,13 @@ "\n", "\n", "gui_error.add_checkbox(\"save\", description=\"Save output\", value=True)\n", - "gui_error.add_dropdown(\"cmaps\", description=\"Colormap:\",\n", - " options=sorted(list(mpl.colormaps)),\n", - " value=\"viridis\", remember_value=True)\n", + "gui_error.add_dropdown(\n", + " \"cmaps\",\n", + " description=\"Colormap:\",\n", + " options=sorted(list(mpl.colormaps)),\n", + " value=\"viridis\",\n", + " remember_value=True,\n", + ")\n", "gui_error.add_button(\"run\", description=\"Calculate\")\n", "gui_error[\"run\"].on_click(run_error_stack)\n", "gui_error.show()\n", @@ -424,7 +492,7 @@ }, { "cell_type": "markdown", - "id": "e08b5c91", + "id": "85b87835", "metadata": {}, "source": [ "## Calculate FRC resolution of the diffraction limited image\n", @@ -440,7 +508,7 @@ { "cell_type": "code", "execution_count": null, - "id": "816b51e1", + "id": "d116e1d7", "metadata": { "cellView": "form" }, @@ -486,7 +554,7 @@ " gui_frc._main_display.children = gui_frc._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=0)\n", "gui_frc.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_original[0].shape[0]-1, value=1)\n", @@ -500,7 +568,7 @@ }, { "cell_type": "markdown", - "id": "aa0a8a80", + "id": "a46f41b3", "metadata": {}, "source": [ "## Calculate FRC resolution of the SR image\n", @@ -516,7 +584,7 @@ { "cell_type": "code", "execution_count": null, - "id": "129e9f86", + "id": "989f8a2f", "metadata": { "cellView": "form" }, @@ -562,7 +630,7 @@ " gui_frc_esrrf._main_display.children = gui_frc_esrrf._main_display.children + (output_plot,)\n", " plt.clf()\n", " \n", - "gui_frc_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_frc_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_frc_esrrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_frc_esrrf.add_int_slider(\"first_frame\", description=\"First Frame:\", min=0, max=dataset_esrrf[0].shape[0]-1, value=0)\n", "gui_frc_esrrf.add_int_slider (\"second_frame\", description=\"Second Frame:\", min=0, max=dataset_esrrf[0].shape[0]-1, value=1)\n", @@ -576,7 +644,7 @@ }, { "cell_type": "markdown", - "id": "b3b15b1e", + "id": "0099c8b9", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the diffraction limited image\n", @@ -593,7 +661,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5bf7dcf9", + "id": "3fa7fe62", "metadata": { "cellView": "form" }, @@ -639,7 +707,7 @@ " gui_decorr._main_display.children = gui_decorr._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_original.shape[0]-1, value=0)\n", "gui_decorr.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", @@ -654,7 +722,7 @@ }, { "cell_type": "markdown", - "id": "55b06686", + "id": "b602fb43", "metadata": {}, "source": [ "## Calculate Decorrelation analysis resolution of the SR image\n", @@ -671,7 +739,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1e4a92ee", + "id": "b3e04bb2", "metadata": { "cellView": "form" }, @@ -717,7 +785,7 @@ " gui_decorr_esrrf._main_display.children = gui_decorr_esrrf._main_display.children + (output_plot,)\n", " plt.clf()\n", "\n", - "gui_decorr_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100, remember_value=True)\n", + "gui_decorr_esrrf.add_int_slider(\"pixel_size\", description=\"Pixel Size:\", min=0.01, max=1000, value=100)\n", "gui_decorr_esrrf.add_dropdown(\"units\", description=\"Units: \", options=[\"nm\", \"um\", \"mm\"], value=\"nm\")\n", "gui_decorr_esrrf.add_int_slider(\"first_frame\", description=\"Frame to be used:\", min=0, max=dataset_esrrf.shape[0]-1, value=0)\n", "gui_decorr_esrrf.add_float_slider(\"rmin\", description=\"Radius Min:\", min=0.0, max=0.5, value=0.0)\n", diff --git a/noxfile.py b/noxfile.py index f463dde8..86d51408 100644 --- a/noxfile.py +++ b/noxfile.py @@ -42,7 +42,9 @@ def build_wheel(session: nox.Session) -> None: # session.run("python", "-m", "build", "--wheel", "-o", temp_path) session.run("pip", "wheel", "--no-deps", "--wheel-dir", temp_path, ".") # get the produced wheel name - wheel_name = [name for name in os.listdir(temp_path) if name.endswith(".whl")][0] + wheel_name = [ + name for name in os.listdir(temp_path) if name.endswith(".whl") + ][0] if PLATFORM == "unix" and os.environ.get("NPX_LINUX_FIX_WHEELS", False): session.install("auditwheel") @@ -112,12 +114,16 @@ def test_wheel(session): python_version_str = f"cp{session.python.replace('.', '')}" # find the latest wheel wheel_names = [ - wheel for wheel in os.listdir("wheelhouse") if wheel.endswith(".whl") and python_version_str in wheel + wheel + for wheel in os.listdir("wheelhouse") + if wheel.endswith(".whl") and python_version_str in wheel ] wheel_names.sort() wheel_name = wheel_names[-1] - session.run("pip", "install", "-U", DIR / "wheelhouse" / f"{wheel_name}[test]") + session.run( + "pip", "install", "-U", DIR / "wheelhouse" / f"{wheel_name}[test]" + ) with session.chdir(".nox"): extra_args = os.environ.get("NPX_PYTEST_ARGS", "") if extra_args != "": @@ -129,7 +135,14 @@ def test_wheel(session): @nox.session(python=PYTHON_ALL_VERSIONS) def test_testpypi(session): - session.run("pip", "install", "-U", "--extra-index-url", "https://testpypi.python.org/pypi", "nanopyx[all]") + session.run( + "pip", + "install", + "-U", + "--extra-index-url", + "https://testpypi.python.org/pypi", + "nanopyx[all]", + ) with session.chdir(".nox"): extra_args = os.environ.get("NPX_PYTEST_ARGS", "") if extra_args != "": diff --git a/pyproject.toml b/pyproject.toml index 7e0e8090..d53796b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ build-backend = "setuptools.build_meta" name = "nanopyx" description = "Nanoscopy Python library (NanoPyx, the successor to NanoJ) - focused on light microscopy and super-resolution imaging" readme = "README.md" -requires-python = ">=3.9,<3.13" +requires-python = ">=3.9" license = { file = "LICENSE.txt" } keywords = [ "NanoJ", @@ -53,6 +53,7 @@ dependencies = [ "scikit-learn>=1.1.0", "matplotlib>=3.5", "importlib-resources", + "ezinput>=0.0.2", ] dynamic = ["version"] # changed in setup.py @@ -169,7 +170,7 @@ omit = [ [tool.cibuildwheel] # https://cibuildwheel.readthedocs.io/en/stable/options/ skip = ["pp*", "*musllinux*"] -build = ["cp39-*", "cp310-*", "cp311-*"] +build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*"] # it is not possible to test arm64 and the arm64 part of a universal2 wheel on this CI platform test-skip = ["*arm64"] # build-frontend = "pip" @@ -198,7 +199,7 @@ manylinux-x86_64-image = "manylinux2014" # repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel}" [tool.cibuildwheel.macos] -archs = ["x86_64", "arm64"] +archs = ["arm64"] before-all = ["brew install llvm libomp"] test-requires = ["nanopyx[test]"] #test-command = "pytest -n=1 --timeout=1200 {project}/tests" diff --git a/setup.py b/setup.py index 357b9926..389a3333 100644 --- a/setup.py +++ b/setup.py @@ -22,11 +22,13 @@ ] EXTRA_LING_ARGS = [] -VERSION = "1.1.0" # sets version number for whole package +VERSION = "1.2.0" # sets version number for whole package def run_command(command: str) -> str: - result = subprocess.run(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = subprocess.run( + command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) return result.stdout.decode("utf-8").strip() @@ -44,7 +46,9 @@ def is_xcode_installed() -> bool: def is_homebrew_installed() -> bool: try: - result = subprocess.run(["which", "brew"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = subprocess.run( + ["which", "brew"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) return result.returncode == 0 except Exception: return False @@ -131,7 +135,9 @@ def search_for_c_files_referrenced_in_pyx_text(text: str): # Lets check if homebrew is installed use_openmp_support = True - print("Checking for openmp support, to run code... ─=≡Σ((( つ◕ل͜◕)つ... blazing fast!!! ") + print( + "Checking for openmp support, to run code... ─=≡Σ((( つ◕ل͜◕)つ... blazing fast!!! " + ) BUILD_TOOLS_PATH = ( Path(os.path.dirname(__file__)) / "build_tools" / "libs_build" @@ -155,13 +161,19 @@ def search_for_c_files_referrenced_in_pyx_text(text: str): INCLUDE_DIRS += [os.path.join(libomp_path, "include")] LIBRARY_DIRS += [os.path.join(libomp_path, "lib")] else: - print(f"\t - {packages} instalation not detected: consider running 'brew install {' '.join(packages)}'") + print( + f"\t - {packages} instalation not detected: consider running 'brew install {' '.join(packages)}'" + ) use_openmp_support = False else: - print("\t - brew instalation not detected, consider installing from https://brew.sh/") + print( + "\t - brew instalation not detected, consider installing from https://brew.sh/" + ) use_openmp_support = False else: - print("\t - xcode instalation not detected, consider installing from the App Store") + print( + "\t - xcode instalation not detected, consider installing from the App Store" + ) use_openmp_support = False if use_openmp_support: @@ -203,15 +215,17 @@ def collect_extensions(): path = os.path.join("src") # Compile mako template(s) - lookup = TemplateLookup(directories = ['src/mako_templates']) - for template_ in os.listdir('src/mako_templates'): - if 'base' in template_: + lookup = TemplateLookup(directories=["src/mako_templates"]) + for template_ in os.listdir("src/mako_templates"): + if "base" in template_: continue - path2out = os.path.join(path,template_.replace('.',os.sep,template_.count('.')-1)) + path2out = os.path.join( + path, template_.replace(".", os.sep, template_.count(".") - 1) + ) rendered_output = lookup.get_template(template_).render_unicode() enconded_rendered_output = rendered_output.encode() try: - with open(path2out, 'r+b') as outfile: + with open(path2out, "r+b") as outfile: current_content = outfile.read() if current_content != enconded_rendered_output: @@ -225,27 +239,30 @@ def collect_extensions(): except FileNotFoundError: # If the file doesn't exist, create it with the new content - with open(path2out, 'wb') as outfile: + with open(path2out, "wb") as outfile: outfile.write(enconded_rendered_output) - #with open(path2out, 'wb') as outfile: + # with open(path2out, 'wb') as outfile: # outfile.write(rendered_output.encode()) - - #template_obj = lookup.get_template(template_) - #with open(path2out,'w') as outfile: + + # template_obj = lookup.get_template(template_) + # with open(path2out,'w') as outfile: # outfile.write(template_obj.render()) - cython_files = [ os.path.join(dir, file) for (dir, dirs, files) in os.walk(path) for file in files if file.endswith(".pyx") - or (file.endswith(".py") and "# nanopyx-cythonize: True\n" in open(os.path.join(dir, file)).read()) + or ( + file.endswith(".py") + and "# nanopyx-cythonize: True\n" + in open(os.path.join(dir, file)).read() + ) ] - + # remove mako templates - cython_files = [c for c in cython_files if 'mako' not in c] + cython_files = [c for c in cython_files if "mako" not in c] cython_extensions = [] extra_c_files = [] @@ -262,13 +279,17 @@ def collect_extensions(): ) if os.path.exists(pxd_file): with open(pxd_file, "r") as f: - extra_c_files_candadates = search_for_c_files_referrenced_in_pyx_text(f.read()) + extra_c_files_candadates = ( + search_for_c_files_referrenced_in_pyx_text(f.read()) + ) sources += extra_c_files_candadates extra_c_files += extra_c_files_candadates # Now search in the pyx file with open(file, "r") as f: - extra_c_files_candadates = search_for_c_files_referrenced_in_pyx_text(f.read()) + extra_c_files_candadates = ( + search_for_c_files_referrenced_in_pyx_text(f.read()) + ) sources += extra_c_files_candadates extra_c_files += extra_c_files_candadates @@ -278,7 +299,9 @@ def collect_extensions(): # Remove files that don't exist sources = [file for file in sources if os.path.exists(file)] - extra_c_files = [file for file in extra_c_files if os.path.exists(file)] + extra_c_files = [ + file for file in extra_c_files if os.path.exists(file) + ] # Make sure we have all the include paths for path in extra_c_files: @@ -291,9 +314,13 @@ def collect_extensions(): print(f"Found following .pyx files to build:\n {'; '.join(cython_files)}") print(f"Found the extra c files to build:\n {'; '.join(extra_c_files)}") - collected_extensions = cythonize(cython_extensions, annotate=True, language_level="3") + collected_extensions = cythonize( + cython_extensions, annotate=True, language_level="3" + ) return collected_extensions + + # Show the logo print( r""" diff --git a/src/include/_c_gradients.c b/src/include/_c_gradients.c index a4b7b5a3..da58a31a 100644 --- a/src/include/_c_gradients.c +++ b/src/include/_c_gradients.c @@ -65,40 +65,51 @@ void _c_gradient_roberts_cross(float* image, float* imGc, float* imGr, int rows, } } -// as in https://www.nature.com/articles/s41592-022-01669-y#MOESM1 -// 3D Gradient calculation + void _c_gradient_3d(float* image, float* imGc, float* imGr, float* imGs, int slices, int rows, int cols) { - float ip0, ip1, ip2, ip3, ip4, ip5, ip6, ip7; + float z0x0y0, z0x0y1, z0x1y0, z0x_1y0, z0x0y_1; + float z1x0y0, z_1x0y0; - int z_i, y_i, x_i, z_1, y_1, x_1; + int z_plus1, y_plus1, x_plus1, + z_minus1, y_minus1, x_minus1; + int z_i, y_i, x_i; + for (z_i = 0; z_i < slices; z_i++) { for (y_i = 0; y_i < rows; y_i++) { for (x_i = 0; x_i < cols; x_i++) { - z_1 = z_i >= slices - 1 ? slices - 1 : z_i + 1; - y_1 = y_i >= rows - 1 ? rows - 1 : y_i + 1; - x_1 = x_i >= cols - 1 ? cols - 1 : x_i + 1; - ip0 = image[z_i * rows * cols + y_i * cols + x_i]; - ip1 = image[z_i * rows * cols + y_i * cols + x_1]; - ip2 = image[z_i * rows * cols + y_1 * cols + x_i]; - ip3 = image[z_i * rows * cols + y_1 * cols + x_1]; - ip4 = image[z_1 * rows * cols + y_i * cols + x_i]; - ip5 = image[z_1 * rows * cols + y_i * cols + x_1]; - ip6 = image[z_1 * rows * cols + y_1 * cols + x_i]; - ip7 = image[z_1 * rows * cols + y_1 * cols + x_1]; - imGc[z_i * rows* cols + y_i * cols + x_i] = - (ip1 + ip3 + ip5 + ip7 - ip0 - ip2 - ip4 - ip6) / 4; - imGr[z_i * rows* cols + y_i * cols + x_i] = - (ip2 + ip3 + ip6 + ip7 - ip0 - ip1 - ip4 - ip5) / 4; - imGs[z_i * rows* cols + y_i * cols + x_i] = - (ip4 + ip5 + ip6 + ip7 - ip0 - ip1 - ip2 - ip3) / 4; + z_plus1 = z_i >= slices - 1 ? slices - 1 : z_i + 1; + y_plus1 = y_i >= rows - 1 ? rows - 1 : y_i + 1; + x_plus1 = x_i >= cols - 1 ? cols - 1 : x_i + 1; + + z_minus1 = z_i <= 0 ? 0 : z_i - 1; + y_minus1 = y_i <= 0 ? 0 : y_i - 1; + x_minus1 = x_i <= 0 ? 0 : x_i - 1; + + // z=0 + z0x0y0 = image[z_i * rows * cols + y_i * cols + x_i]; // central pixel + z0x0y1 = image[z_i * rows * cols + y_plus1 * cols + x_i]; // y+1 + z0x1y0 = image[z_i * rows * cols + y_i * cols + x_plus1]; // x+1 + z0x0y_1 = image[z_i * rows * cols + y_minus1 * cols + x_i]; // y-1 + z0x_1y0 = image[z_i * rows * cols + y_i * cols + x_minus1]; // x-1 + + // z=1 + z1x0y0 = image[z_plus1 * rows * cols + y_i * cols + x_i]; // z+1 + + // z=-1 + z_1x0y0 = image[z_minus1 * rows * cols + y_i * cols + x_i]; // z-1 + + imGc[z_i * rows* cols + y_i * cols + x_i] = (z0x1y0 - z0x_1y0)/2; + imGr[z_i * rows* cols + y_i * cols + x_i] = (z0x0y1 - z0x0y_1)/2; + imGs[z_i * rows* cols + y_i * cols + x_i] = (z0x0y0 - z_1x0y0)/2; } } } } + void _c_gradient_2_point_3d(float* image, float* imGc, float* imGr, float* imGs, int slices, int rows, int cols) { int s_i, y_i, x_i, s0, y0, x0; diff --git a/src/include/_c_sr_radial_gradient_convergence.c b/src/include/_c_sr_radial_gradient_convergence.c index 5f6850c3..7162dd46 100644 --- a/src/include/_c_sr_radial_gradient_convergence.c +++ b/src/include/_c_sr_radial_gradient_convergence.c @@ -28,6 +28,7 @@ void _rotate_vector(float* Gx, float* Gy, float angle) { float _c_calculate_rgc(int xM, int yM, float* imIntGx, float* imIntGy, int colsM, int rowsM, int magnification, float Gx_Gy_MAGNIFICATION, float fwhm, float tSO, float tSS, float sensitivity, float offset, float xyoffset, float angle) { float vx, vy, Gx, Gy, dx, dy, distance, distanceWeight, GdotR, Dk; + float correct_vx, correct_vy; float xc = (float)xM / magnification + offset; // offset in non-magnified space float yc = (float)yM / magnification + offset; @@ -35,8 +36,8 @@ float _c_calculate_rgc(int xM, int yM, float* imIntGx, float* imIntGy, int colsM float RGC = 0; float distanceWeightSum = 0; - int _start = -(int)(2 * fwhm); - int _end = (int)(2 * fwhm + 1); + int _start = -(int)(fwhm); + int _end = (int)(fwhm + 1); for (int j = _start; j < _end; j++) { vy = yc + j; @@ -51,8 +52,24 @@ float _c_calculate_rgc(int xM, int yM, float* imIntGx, float* imIntGy, int colsM distance = sqrt(dx * dx + dy * dy); if (distance != 0 && distance <= tSO) { - Gx = imIntGx[(int)((vy+xyoffset) * magnification * Gx_Gy_MAGNIFICATION * colsM * Gx_Gy_MAGNIFICATION) + (int)((vx+xyoffset) * magnification * Gx_Gy_MAGNIFICATION)]; - Gy = imIntGy[(int)((vy+xyoffset) * magnification * Gx_Gy_MAGNIFICATION * colsM * Gx_Gy_MAGNIFICATION) + (int)((vx+xyoffset) * magnification * Gx_Gy_MAGNIFICATION)]; + + correct_vx = vx+xyoffset; + correct_vy = vy+xyoffset; + + if (correct_vx= 0) { + if (RGC >= 0 && sensitivity > 1) { RGC = pow(RGC, sensitivity); - } else { + } else if (RGC < 0) { RGC = 0; } diff --git a/src/include/_c_sr_radial_gradient_convergence.h b/src/include/_c_sr_radial_gradient_convergence.h index 60d48153..1a7abb2c 100644 --- a/src/include/_c_sr_radial_gradient_convergence.h +++ b/src/include/_c_sr_radial_gradient_convergence.h @@ -21,8 +21,7 @@ double _c_calculate_dw_z(double distance_z, double tSS_z); double _c_calculate_dk3D(float Gx, float Gy, float Gz, float dx, float dy, float dz, float distance); -float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float ratio_px, float Gx_Gy_MAGNIFICATION, float Gz_MAGNIFICATION, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity); - +float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float voxel_ratio, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity); float _c_calculate_rgc_3d(int cM, int rM, int sM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float Gx_Gy_MAGNIFICATION, float fwhm, float fwhm_z, float tSO, float tSS, float sensitivity); diff --git a/src/liquid_benchmarks/_le_esrrf3d/eSRRF3D.yml b/src/liquid_benchmarks/_le_esrrf3d/eSRRF3D.yml index 8b5753be..cff089c5 100644 --- a/src/liquid_benchmarks/_le_esrrf3d/eSRRF3D.yml +++ b/src/liquid_benchmarks/_le_esrrf3d/eSRRF3D.yml @@ -1,36 +1,48 @@ -Threaded: - ? '([''shape(1, 10, 100, 100)''], {''magnification_xy'': 2, ''magnification_z'': - 2, ''radius'': 1.5, ''sensitivity'': 1.0, ''doIntensityWeighting'': True})' - : - 600000.0 - - 3.009124042 - - 3.0523655000000005 - - 3.0673777499999986 -Threaded_dynamic: - ? '([''shape(1, 10, 100, 100)''], {''magnification_xy'': 2, ''magnification_z'': - 2, ''radius'': 1.5, ''sensitivity'': 1.0, ''doIntensityWeighting'': True})' - : - 600000.0 - - 2.9377308749999997 - - 3.038488291 - - 2.9445285420000076 - - 3.01370875 -Threaded_guided: - ? '([''shape(1, 10, 100, 100)''], {''magnification_xy'': 2, ''magnification_z'': - 2, ''radius'': 1.5, ''sensitivity'': 1.0, ''doIntensityWeighting'': True})' - : - 600000.0 - - 2.9383910419999992 - - 3.179585459000002 - - 2.9465658749999903 -Threaded_static: - ? '([''shape(1, 10, 100, 100)''], {''magnification_xy'': 2, ''magnification_z'': - 2, ''radius'': 1.5, ''sensitivity'': 1.0, ''doIntensityWeighting'': True})' - : - 600000.0 - - 3.0556022499999997 - - 3.011091624999999 - - 3.0389940410000023 -Unthreaded: - ? '([''shape(1, 10, 100, 100)''], {''magnification_xy'': 2, ''magnification_z'': - 2, ''radius'': 1.5, ''sensitivity'': 1.0, ''doIntensityWeighting'': True})' - : - 600000.0 - - 10.075773250000001 - - 10.147714 - - 10.096515416999999 +opencl: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 0.534501292015193 + - 0.4527143339801114 + - 0.4526337919814978 +threaded: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 1.9790987920132466 + - 1.9240770420001354 + - 1.895047333004186 +threaded_dynamic: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 1.7660593329928815 + - 1.719053625012748 + - 1.7240022089972626 +threaded_guided: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 1.781112333002966 + - 1.8617710830003489 + - 2.0126889999955893 +threaded_static: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 1.8515684169833548 + - 1.8730584580043796 + - 1.8657334169838578 +unthreaded: + ? '([''shape(1, 101, 101, 101)''], {''magnification_xy'': 2, ''magnification_z'': + 2, ''radius'': 1.5, ''radius_z'': 0.5, ''voxel_ratio'': 4.0, ''sensitivity'': + 1.0, ''mode'': ''average'', ''doIntensityWeighting'': False})' + : - 12363612.0 + - 4.863078458001837 + - 4.9081600419885945 + - 4.920950291998452 diff --git a/src/mako_templates/nanopyx.core.transform._le_esrrf.pyx b/src/mako_templates/nanopyx.core.transform._le_esrrf.pyx index d1c5b98e..ea8afd15 100644 --- a/src/mako_templates/nanopyx.core.transform._le_esrrf.pyx +++ b/src/mako_templates/nanopyx.core.transform._le_esrrf.pyx @@ -29,15 +29,15 @@ class eSRRF(LiquidEngine): self._designation = "eSRRF_ST" super().__init__(clear_benchmarks=clear_benchmarks, testing=testing, verbose=verbose) - def run(self, image, magnification: int = 5, grad_magnification: int = 2, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True, run_type=None): + def run(self, image, magnification: int = 5, grad_magnification: int = 1, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True, run_type=None): image = check_image(image) return self._run(image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - def benchmark(self, image, magnification: int = 5, grad_magnification: int = 2, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True): + def benchmark(self, image, magnification: int = 5, grad_magnification: int = 1, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True): image = check_image(image) return super().benchmark(image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) - def _run_opencl(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True, device=None, mem_div=1): + def _run_opencl(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True, device=None, mem_div=1): """ @gpu """ @@ -92,7 +92,7 @@ class eSRRF(LiquidEngine): rgc_prg = cl.Program(cl_ctx, rgc_code).build(options=["-cl-mad-enable -cl-fast-relaxed-math"]) rgc_knl = rgc_prg.calculate_rgc - margin = int(radius*2*magnification) + margin = int(radius*magnification) lowest_row = margin # TODO discuss edges calculation highest_row = output_shape[1] - margin lowest_col = margin @@ -181,7 +181,7 @@ class eSRRF(LiquidEngine): return output_image % for sch in schedulers: - def _run_${sch}(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True): + def _run_${sch}(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True): """ @cpu @threaded diff --git a/src/mako_templates/nanopyx.core.transform._le_esrrf3d.pyx b/src/mako_templates/nanopyx.core.transform._le_esrrf3d.pyx index 78cb801c..d35aa728 100644 --- a/src/mako_templates/nanopyx.core.transform._le_esrrf3d.pyx +++ b/src/mako_templates/nanopyx.core.transform._le_esrrf3d.pyx @@ -1,6 +1,9 @@ -# cython: infer_types=True, wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, profile=False, autogen_pxd=False +<%! +schedulers = ['threaded','threaded_guided','threaded_dynamic','threaded_static', 'unthreaded'] +%># cython: infer_types=True, wraparound=True, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, profile=False, autogen_pxd=False import numpy as np import math +import time cimport numpy as np from libc.math cimport floor @@ -12,12 +15,15 @@ from .sr_temporal_correlations import calculate_eSRRF_temporal_correlations from ._interpolation import interpolate_3d, interpolate_3d_zlinear from ._le_interpolation_catmull_rom import ShiftAndMagnify from ...__liquid_engine__ import LiquidEngine +from ...__opencl__ import cl, cl_array, _fastest_device + +from scipy.stats import pearsonr as pearson_correlation cdef extern from "_c_gradients.h": void _c_gradient_3d(float* image, float* imGc, float* imGr, float* imGs, int slices, int rows, int cols) nogil cdef extern from "_c_sr_radial_gradient_convergence.h": - float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float PSF_voxel_ratio, float Gx_Gy_MAGNIFICATION, float Gz_MAGNIFICATION, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity) nogil + float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float voxel_ratio, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity) nogil class eSRRF3D(LiquidEngine): """ @@ -27,379 +33,363 @@ class eSRRF3D(LiquidEngine): def __init__(self, clear_benchmarks=False, testing=False, verbose=True): self._designation = "eSRRF_3D" super().__init__(clear_benchmarks=clear_benchmarks, testing=testing, verbose=verbose) - self._gradients_s_interpolated = None - self._gradients_r_interpolated = None - self._gradients_c_interpolated = None - self.keep_gradients = False - self.keep_interpolated = False - self._img_interpolated = None - - def run(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True, keep_gradients=False, keep_interpolated = False, run_type=None): - self.keep_gradients = keep_gradients - self.keep_interpolated = keep_interpolated + + def run(self, image, magnification_xy: int = 2, magnification_z: int = 2, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True, run_type=None): # TODO: complete and check _run inputs, need to complete variables? + if len(image.shape) == 3: + image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) + if len(image.shape) != 4: + print("Warning:image must either be 3D or 4D. If 3D, it will be reshaped to 4D.") + return None + if radius * 2 > (image.shape[2]) / 2 or radius * 2 > (image.shape[3] / 2): + print("Warning: Radius is too big for the image. Half the radius must be smaller than both half the number of columns and half number of rows of the image.") + return None + if radius_z * 2 > image.shape[1] / 2: + print("Warning: Radius_z is too big for the image. Half the radius_z must be smaller than half of number of Z planes.") + return None if image.dtype != np.float32: image = image.astype(np.float32) - if len(image.shape) == 4: - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - elif len(image.shape) == 3: - image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) + + return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio, sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - def benchmark(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + def benchmark(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): if image.dtype != np.float32: image = image.astype(np.float32) if len(image.shape) == 4: - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio,sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) + return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio,sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting) elif len(image.shape) == 3: image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) - return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) + return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio, sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting) - def _run_threaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + % for sch in schedulers: + def _run_${sch}(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu + % if sch!='unthreaded': @threaded + % endif @cython """ - cdef float sigma = radius / 2.355 - cdef float fwhm = radius - cdef float tSS = 2 * sigma * sigma - cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio - cdef float tSS_z = 2 * sigma_z * sigma_z - cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 - cdef int _magnification_xy = magnification_xy - cdef int _magnification_z = magnification_z - cdef int _doIntensityWeighting = doIntensityWeighting - - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum - n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() - - with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag): - for cM in range(0, n_cols_mag): - if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_guided(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): - """ - @cpu - @threaded - @cython - """ + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 - cdef int _magnification_xy = magnification_xy - cdef int _magnification_z = magnification_z - cdef int _doIntensityWeighting = doIntensityWeighting - - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum - n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() - - with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="guided"): - for cM in range(0, n_cols_mag): - if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_dynamic(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): - """ - @cpu - @threaded - @cython - """ - cdef float sigma = radius / 2.355 cdef float fwhm = radius - cdef float tSS = 2 * sigma * sigma - cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio - cdef float tSS_z = 2 * sigma_z * sigma_z - cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="dynamic"): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + % if sch=="unthreaded": + for rM in range(margin, n_rows_mag-margin): + % elif sch=="threaded": + for rM in prange(margin, n_rows_mag-margin): + % else: + for rM in prange(margin, n_rows_mag-margin, schedule="${sch.split('_')[1]}"): + % endif + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_static(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): - """ - @cpu - @threaded - @cython - """ - cdef float sigma = radius / 2.355 - cdef float fwhm = radius - cdef float tSS = 2 * sigma * sigma - cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio - cdef float tSS_z = 2 * sigma_z * sigma_z - cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 - cdef int _magnification_xy = magnification_xy - cdef int _magnification_z = magnification_z - cdef int _doIntensityWeighting = doIntensityWeighting - - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum - n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) + % endfor - with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="static"): - for cM in range(0, n_cols_mag): - if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_unthreaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + def _run_opencl(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True, device=None, mem_div=1): """ - @cpu - @cython + @gpu """ - cdef float sigma = radius / 2.355 - cdef float fwhm = radius - cdef float tSS = 2 * sigma * sigma - cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio - cdef float tSS_z = 2 * sigma_z * sigma_z - cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 - cdef int _magnification_xy = magnification_xy - cdef int _magnification_z = magnification_z - cdef int _doIntensityWeighting = doIntensityWeighting - - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum - n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() - - with nogil: - for sM in range(0, n_slices_mag): - for rM in range(0, n_rows_mag): - for cM in range(0, n_cols_mag): - if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val + # select cl device + if device is None: + device = _fastest_device - return np.asarray(rgc_map) - - def get_gradients(self): - if self._gradients_c_interpolated is None or self._gradients_r_interpolated is None or self._gradients_s_interpolated is None: - print("Gradients not yet calculated") + # create cl context and queue + cl_ctx = cl.Context([device['device']]) + dc = device['device'] + cl_queue = cl.CommandQueue(cl_ctx) + + output_shape = (image.shape[1] * magnification_z, image.shape[2] * magnification_xy, image.shape[3] * magnification_xy) + output_array = np.zeros(output_shape, dtype=np.float32) + + # create input cl buffers + input_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=np.ascontiguousarray(image)) + intermediate_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * magnification_xy * image.shape[3] * magnification_xy * np.dtype(np.float32).itemsize) + input_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create gradient buffers + slices_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + rows_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + cols_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + slices_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + rows_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + cols_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create rgc cl buffer + rgc_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create output cl buffer + output_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + if mode == "std": + mean_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create cl code, program and kernels + cl_code = self._get_cl_code("_le_esrrf3d_.cl", device["DP"]) + cl_prg = cl.Program(cl_ctx, cl_code).build(options=["-cl-fast-relaxed-math", "-cl-mad-enable"]) + interpolate_xy_kernel = cl_prg.interpolate_xy_2d + interpolate_z_kernel = cl_prg.interpolate_z_1d + gradients_kernel = cl_prg.gradients_3d + rgc_kernel = cl_prg.calculate_rgc3D + if mode == "average": + time_projection_kernel = cl_prg.time_projection_average + elif mode == "std": + time_projection_kernel = cl_prg.time_projection_std else: - return self._gradients_c_interpolated, self._gradients_r_interpolated, self._gradients_s_interpolated + raise ValueError("Invalid mode. Use 'average' or 'std'.") + + # set margins + margin = int(radius*magnification_xy) + margin_z = int(radius_z*magnification_z) + lowest_slice = margin_z + highest_slice = output_shape[0] - margin_z + lowest_row = margin + highest_row = output_shape[1] - margin + lowest_col = margin + highest_col = output_shape[2] - margin + + # set constants + cdef float sigma = radius / 2.355 + cdef float tss = 2 * sigma * sigma + cdef float tso = 2 * sigma + 1 + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef float tss_z = 2 * sigma_z * sigma_z + cdef float tso_z = 2 * sigma_z + 1 + + cdef float frame_div = 0.0 + + # loop over frames: + for frame_i in range(image.shape[0]): + # interpolate image + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + input_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(frame_i), + ).wait() + + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + input_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + # calculate gradients + gradients_kernel( + cl_queue, + (image.shape[1], image.shape[2], image.shape[3]), + None, + input_buffer, + slices_gradient_buffer, + cols_gradient_buffer, + rows_gradient_buffer, + np.int32(image.shape[1]), + np.int32(image.shape[2]), + np.int32(image.shape[3]), + np.int32(frame_i), + ).wait() + + # interpolate gradients + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + slices_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + slices_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + rows_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + rows_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + cols_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + cols_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + # calculate rgc + + rgc_kernel( + cl_queue, + (highest_slice - lowest_slice, highest_row - lowest_row, highest_col - lowest_col), + None, + slices_gradient_magnified_buffer, + rows_gradient_magnified_buffer, + cols_gradient_magnified_buffer, + input_magnified_buffer, + rgc_buffer, + np.int32(output_shape[0]), + np.int32(output_shape[1]), + np.int32(output_shape[2]), + np.int32(magnification_xy), + np.int32(magnification_z), + np.float32(voxel_ratio), + np.float32(radius), + np.float32(radius_z), + np.float32(tso), + np.float32(tss), + np.float32(tso_z), + np.float32(tss_z), + np.float32(sensitivity), + np.int32(doIntensityWeighting), + np.int32(frame_i), + ).wait() + + if mode == "std": + time_projection_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + rgc_buffer, + mean_buffer, + output_buffer, + np.int32(frame_i), + ).wait() + else: + time_projection_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + rgc_buffer, + output_buffer, + np.int32(frame_i), + ).wait() + cl_queue.finish() + cl.enqueue_copy(cl_queue, output_array, output_buffer).wait() + + if mode == "std": + return np.asarray(np.sqrt(output_array / image.shape[0])) + else: + return np.asarray(output_array) + + + def _compare_runs(self, output_1, output_2): + """@public""" + if output_1.ndim > 2: + pcc = 0 + count = 0 + for i in range(output_1.shape[0]): + pccresult = pearson_correlation(output_1[i, :, :].flatten(), output_2[i, :, :].flatten()).statistic + + if np.isnan(pccresult): + continue + else: + count += 1 + # calculate pcc for each frame + pcc += (pccresult-pcc) / count + else: + pcc = pearson_correlation(output_1.flatten(), output_2.flatten()).statistic - def get_interpolated_image(self): - return self._img_interpolated \ No newline at end of file + if pcc > 0.8: + return True + else: + return False \ No newline at end of file diff --git a/src/mako_templates/nanopyx.core.transform._le_radial_gradient_convergence.pyx b/src/mako_templates/nanopyx.core.transform._le_radial_gradient_convergence.pyx index fe64b25a..9302d6f8 100644 --- a/src/mako_templates/nanopyx.core.transform._le_radial_gradient_convergence.pyx +++ b/src/mako_templates/nanopyx.core.transform._le_radial_gradient_convergence.pyx @@ -47,7 +47,7 @@ class RadialGradientConvergence(LiquidEngine): """ cdef float sigma = radius / 2.355 cdef float fwhm = radius - cdef int margin = int(fwhm*2) * magnification + cdef int margin = int(fwhm*magnification) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 cdef float Gx_Gy_MAGNIFICATION = grad_magnification @@ -82,7 +82,7 @@ class RadialGradientConvergence(LiquidEngine): """ cdef float sigma = radius / 2.355 cdef float fwhm = radius - cdef int margin = int(fwhm*2) * magnification + cdef int margin = int(fwhm * magnification) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 cdef float Gx_Gy_MAGNIFICATION = grad_magnification @@ -131,7 +131,7 @@ class RadialGradientConvergence(LiquidEngine): # Parameters cdef float sigma = radius / 2.355 cdef float fwhm = radius - cdef int margin = int(fwhm*2) * magnification + cdef int margin = int(fwhm*magnification) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 cdef float Gx_Gy_MAGNIFICATION = grad_magnification diff --git a/src/nanopyx/__init__.py b/src/nanopyx/__init__.py index 49baf1ca..77035398 100644 --- a/src/nanopyx/__init__.py +++ b/src/nanopyx/__init__.py @@ -17,7 +17,6 @@ from .__agent__ import Agent # noqa: E402 - # TODO: allow benchmarking of only specific implementations # TODO: provide parallelized batch processing @@ -42,7 +41,7 @@ # Section for imports of high-level functions from .core.utils.benchmark import benchmark_all_le_methods as benchmark from .methods import non_local_means_denoising -from .methods import eSRRF, run_esrrf_parameter_sweep +from .methods import eSRRF, run_esrrf_parameter_sweep, eSRRF3D from .methods import SRRF from .methods import calculate_frc, calculate_decorr_analysis from .methods import calculate_error_map diff --git a/src/nanopyx/core/transform/__init__.py b/src/nanopyx/core/transform/__init__.py index f23a0806..bd34be2d 100644 --- a/src/nanopyx/core/transform/__init__.py +++ b/src/nanopyx/core/transform/__init__.py @@ -16,6 +16,7 @@ from ._le_radial_gradient_convergence import RadialGradientConvergence from ._le_roberts_cross_gradients import GradientRobertsCross from ._le_esrrf import eSRRF as eSRRF_ST +from ._le_esrrf3d import eSRRF3D as eSRRF3D_ST from ._le_convolution import Convolution as Convolution2D from ._le_nlm_denoising import NLMDenoising diff --git a/src/nanopyx/core/transform/_interpolation.pyx b/src/nanopyx/core/transform/_interpolation.pyx index ed9ab794..e3c6cd7c 100644 --- a/src/nanopyx/core/transform/_interpolation.pyx +++ b/src/nanopyx/core/transform/_interpolation.pyx @@ -4,9 +4,12 @@ import numpy as np cimport numpy as np import cython +from math import floor from ._le_interpolation_catmull_rom import ShiftAndMagnify as ShiftMagnify_CR +from cython.parallel import prange + cdef extern from "_c_interpolation_catmull_rom.h": float _c_cr_interpolate "_c_interpolate" (float *image, float row, float col, int rows, int cols) @@ -46,11 +49,53 @@ def linear_interpolation_1D_z(image, magnification): return image_interpolated +cdef _linear_interpolation_1D_z(float[:, :, :] image, int magnification_z): + + cdef int slices = image.shape[0] + cdef int slicesM = int(image.shape[0] * magnification_z) + cdef int rows = image.shape[1] + cdef int cols = image.shape[2] + + cdef int sM, r, c + cdef int slice0, slice1, slc + cdef float weight0, weight1 + + cdef float[:, :, :] image_out = np.zeros((slicesM, rows, cols), dtype=np.float32) + + + for sM in range(slicesM): + slc = sM / magnification_z + slice0 = int(floor(slc)) + slice1 = slice0 + 1 + weight1 = slc - slice0 + weight0 = 1.0 - weight1 + with nogil: + for r in prange(rows): + for c in prange(cols): + + + if slice0 >= 0 and slice1 < slices: + image_out[sM, r, c] = weight0 * image[slice0, r, c] + weight1 * image[slice1, r, c]; + elif slice0 >= 0: + image_out[sM, r, c] = image[slice0, r, c]; + elif slice1 < slices: + image_out[sM, r, c] = image[slice1, r, c]; + else: + image_out[sM, r, c] = 0.0; + + return image_out + def interpolate_3d_zlinear(image, magnification_xy: int = 5, magnification_z: int = 5): interpolator_xy = ShiftMagnify_CR(verbose=False) - xy_interpolated = interpolator_xy.run(np.ascontiguousarray(image), 0, 0, magnification_xy, magnification_xy) - z_interpolated = linear_interpolation_1D_z(xy_interpolated, magnification_z) + if magnification_xy > 1: + xy_interpolated = np.asarray(interpolator_xy.run(np.ascontiguousarray(image), 0, 0, magnification_xy, magnification_xy)) + else: + xy_interpolated = np.asarray(image) + if magnification_z > 1: + z_interpolated = _linear_interpolation_1D_z(xy_interpolated, magnification_z) + else: + z_interpolated = np.asarray(xy_interpolated) return z_interpolated diff --git a/src/nanopyx/core/transform/_le_esrrf.pyx b/src/nanopyx/core/transform/_le_esrrf.pyx index 860ab942..20e92b38 100644 --- a/src/nanopyx/core/transform/_le_esrrf.pyx +++ b/src/nanopyx/core/transform/_le_esrrf.pyx @@ -27,15 +27,15 @@ class eSRRF(LiquidEngine): self._designation = "eSRRF_ST" super().__init__(clear_benchmarks=clear_benchmarks, testing=testing, verbose=verbose) - def run(self, image, magnification: int = 5, grad_magnification: int = 2, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True, run_type=None): + def run(self, image, magnification: int = 5, grad_magnification: int = 1, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True, run_type=None): image = check_image(image) return self._run(image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - def benchmark(self, image, magnification: int = 5, grad_magnification: int = 2, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True): + def benchmark(self, image, magnification: int = 5, grad_magnification: int = 1, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True): image = check_image(image) return super().benchmark(image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) - def _run_opencl(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True, device=None, mem_div=1): + def _run_opencl(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True, device=None, mem_div=1): """ @gpu """ @@ -90,7 +90,7 @@ class eSRRF(LiquidEngine): rgc_prg = cl.Program(cl_ctx, rgc_code).build(options=["-cl-mad-enable -cl-fast-relaxed-math"]) rgc_knl = rgc_prg.calculate_rgc - margin = int(radius*2*magnification) + margin = int(radius*magnification) lowest_row = margin # TODO discuss edges calculation highest_row = output_shape[1] - margin lowest_col = margin @@ -178,7 +178,7 @@ class eSRRF(LiquidEngine): return output_image - def _run_threaded(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True): + def _run_threaded(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True): """ @cpu @threaded @@ -200,7 +200,7 @@ class eSRRF(LiquidEngine): radial_gradients = rgc.run(gradient_col_interp, gradient_row_interp, magnified_image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, offset=0, xyoffset=-0.5, angle=np.pi/4, run_type=runtype) return radial_gradients - def _run_threaded_guided(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True): + def _run_threaded_guided(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True): """ @cpu @threaded @@ -222,7 +222,7 @@ class eSRRF(LiquidEngine): radial_gradients = rgc.run(gradient_col_interp, gradient_row_interp, magnified_image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, offset=0, xyoffset=-0.5, angle=np.pi/4, run_type=runtype) return radial_gradients - def _run_threaded_dynamic(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True): + def _run_threaded_dynamic(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True): """ @cpu @threaded @@ -244,7 +244,7 @@ class eSRRF(LiquidEngine): radial_gradients = rgc.run(gradient_col_interp, gradient_row_interp, magnified_image, magnification=magnification, grad_magnification=grad_magnification, radius=radius, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, offset=0, xyoffset=-0.5, angle=np.pi/4, run_type=runtype) return radial_gradients - def _run_threaded_static(self, image, magnification=5, grad_magnification=2, radius=1.5, sensitivity=1, doIntensityWeighting=True): + def _run_threaded_static(self, image, magnification=5, grad_magnification=1, radius=1.5, sensitivity=1, doIntensityWeighting=True): """ @cpu @threaded diff --git a/src/nanopyx/core/transform/_le_esrrf3d.pyx b/src/nanopyx/core/transform/_le_esrrf3d.pyx index 78cb801c..7af43854 100644 --- a/src/nanopyx/core/transform/_le_esrrf3d.pyx +++ b/src/nanopyx/core/transform/_le_esrrf3d.pyx @@ -1,6 +1,7 @@ -# cython: infer_types=True, wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, profile=False, autogen_pxd=False +# cython: infer_types=True, wraparound=True, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, profile=False, autogen_pxd=False import numpy as np import math +import time cimport numpy as np from libc.math cimport floor @@ -12,12 +13,15 @@ from .sr_temporal_correlations import calculate_eSRRF_temporal_correlations from ._interpolation import interpolate_3d, interpolate_3d_zlinear from ._le_interpolation_catmull_rom import ShiftAndMagnify from ...__liquid_engine__ import LiquidEngine +from ...__opencl__ import cl, cl_array, _fastest_device + +from scipy.stats import pearsonr as pearson_correlation cdef extern from "_c_gradients.h": void _c_gradient_3d(float* image, float* imGc, float* imGr, float* imGs, int slices, int rows, int cols) nogil cdef extern from "_c_sr_radial_gradient_convergence.h": - float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float PSF_voxel_ratio, float Gx_Gy_MAGNIFICATION, float Gz_MAGNIFICATION, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity) nogil + float _c_calculate_rgc3D(int xM, int yM, int sliceM, float* imIntGx, float* imIntGy, float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float voxel_ratio, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity) nogil class eSRRF3D(LiquidEngine): """ @@ -27,379 +31,660 @@ class eSRRF3D(LiquidEngine): def __init__(self, clear_benchmarks=False, testing=False, verbose=True): self._designation = "eSRRF_3D" super().__init__(clear_benchmarks=clear_benchmarks, testing=testing, verbose=verbose) - self._gradients_s_interpolated = None - self._gradients_r_interpolated = None - self._gradients_c_interpolated = None - self.keep_gradients = False - self.keep_interpolated = False - self._img_interpolated = None - - def run(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True, keep_gradients=False, keep_interpolated = False, run_type=None): - self.keep_gradients = keep_gradients - self.keep_interpolated = keep_interpolated + + def run(self, image, magnification_xy: int = 2, magnification_z: int = 2, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True, run_type=None): # TODO: complete and check _run inputs, need to complete variables? + if len(image.shape) == 3: + image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) + if len(image.shape) != 4: + print("Warning:image must either be 3D or 4D. If 3D, it will be reshaped to 4D.") + return None + if radius * 2 > (image.shape[2]) / 2 or radius * 2 > (image.shape[3] / 2): + print("Warning: Radius is too big for the image. Half the radius must be smaller than both half the number of columns and half number of rows of the image.") + return None + if radius_z * 2 > image.shape[1] / 2: + print("Warning: Radius_z is too big for the image. Half the radius_z must be smaller than half of number of Z planes.") + return None if image.dtype != np.float32: image = image.astype(np.float32) - if len(image.shape) == 4: - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - elif len(image.shape) == 3: - image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting, run_type=run_type) + + return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio, sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting, run_type=run_type) - def benchmark(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + def benchmark(self, image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): if image.dtype != np.float32: image = image.astype(np.float32) if len(image.shape) == 4: - return self._run(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio,sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) + return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio,sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting) elif len(image.shape) == 3: image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) - return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, PSF_voxel_ratio=PSF_voxel_ratio, sensitivity=sensitivity, doIntensityWeighting=doIntensityWeighting) + return super().benchmark(image, magnification_xy=magnification_xy, magnification_z=magnification_z, radius=radius, radius_z=radius_z, voxel_ratio=voxel_ratio, sensitivity=sensitivity, mode=mode, doIntensityWeighting=doIntensityWeighting) - def _run_threaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + def _run_threaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu @threaded @cython """ + + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm = radius + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + for rM in prange(margin, n_rows_mag-margin): + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_guided(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) + def _run_threaded_guided(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu @threaded @cython """ + + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm = radius + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="guided"): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + for rM in prange(margin, n_rows_mag-margin, schedule="guided"): + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_dynamic(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) + def _run_threaded_dynamic(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu @threaded @cython """ + + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm = radius + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="dynamic"): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + for rM in prange(margin, n_rows_mag-margin, schedule="dynamic"): + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_threaded_static(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) + def _run_threaded_static(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu @threaded @cython """ + + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm = radius + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof - - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] - - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() - - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in prange(0, n_rows_mag, schedule="static"): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + for rM in prange(margin, n_rows_mag-margin, schedule="static"): + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) - def _run_unthreaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, PSF_voxel_ratio: float = 4.0, sensitivity: float = 1, doIntensityWeighting: bool = True): + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) + def _run_unthreaded(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True): """ @cpu @cython """ + + time_start = time.time() + # calculate all constants cdef float sigma = radius / 2.355 - cdef float fwhm = radius + cdef int margin = int(radius * magnification_xy) cdef float tSS = 2 * sigma * sigma cdef float tSO = 2 * sigma + 1 - cdef float sigma_z = radius * PSF_voxel_ratio / 2.355 # Taking voxel size into account - cdef float fwhm_z = radius * PSF_voxel_ratio + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef int margin_z = int(radius_z*magnification_z) cdef float tSS_z = 2 * sigma_z * sigma_z cdef float tSO_z = 2 * sigma_z + 1 - cdef int Gx_Gy_MAGNIFICATION = 2 + cdef float fwhm = radius + cdef float fwhm_z = radius_z cdef int _magnification_xy = magnification_xy cdef int _magnification_z = magnification_z + cdef float _voxel_ratio = voxel_ratio cdef int _doIntensityWeighting = doIntensityWeighting - cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum + cdef int n_frames, n_slices, n_rows, n_cols, n_slices_mag, n_rows_mag, n_cols_mag n_frames, n_slices, n_rows, n_cols = image.shape[0], image.shape[1], image.shape[2], image.shape[3] - - cdef float[:, :, :, :] rgc_map = np.zeros((n_frames, n_slices*magnification_z, n_rows*magnification_xy, n_cols*magnification_xy), dtype=np.float32) - - cdef float[:, :, :] image_interpolated, gradients_s, gradients_r, gradients_c, gradients_s_interpolated, gradients_r_interpolated, gradients_c_interpolated, padded, img_dum - - cdef int f, n_slices_mag, n_rows_mag, n_cols_mag, sM, rM, cM, z0 - - cdef float rgc_val, zcof + n_slices_mag = n_slices * _magnification_z + n_rows_mag = n_rows * _magnification_xy + n_cols_mag = n_cols * _magnification_xy - for f in range(n_frames): - image_interpolated = interpolate_3d_zlinear(image[f,:,:,:], _magnification_xy, _magnification_z) - - n_slices_mag, n_rows_mag, n_cols_mag = image_interpolated.shape[0], image_interpolated.shape[1], image_interpolated.shape[2] - - img_dum = interpolate_3d_zlinear(image[f], Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION) - n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum = img_dum.shape[0], img_dum.shape[1], img_dum.shape[2] + cdef float[:, :, :] rgc_mean + # create all necessary arrays + cdef float[:, :, :] rgc_out = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + if mode == "std": + rgc_mean = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] image_interpolated = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_col = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_row = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_slices = np.zeros((n_slices, n_rows, n_cols), dtype=np.float32) + cdef float[:, :, :] gradients_col_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_row_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float[:, :, :] gradients_slices_mag = np.zeros((n_slices_mag, n_rows_mag, n_cols_mag), dtype=np.float32) + cdef float delta, delta_2, rgc_val + cdef int f_i, sM, rM, cM + + for f_i in range(n_frames): + # interpolate frame + image_interpolated = interpolate_3d_zlinear(image[f_i,:,:,:], _magnification_xy, _magnification_z) - gradients_c = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_r = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) - gradients_s = np.zeros((n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum), dtype=np.float32) with nogil: - _c_gradient_3d(&img_dum[0, 0, 0], &gradients_c[0, 0, 0], &gradients_r[0, 0, 0], &gradients_s[0, 0, 0], n_slices_mag_dum, n_rows_mag_dum, n_cols_mag_dum) - - gradients_s_interpolated = interpolate_3d_zlinear(gradients_s, _magnification_xy, _magnification_z) - gradients_r_interpolated = interpolate_3d_zlinear(gradients_r, _magnification_xy, _magnification_z) - gradients_c_interpolated = interpolate_3d_zlinear(gradients_c, _magnification_xy, _magnification_z) - - if self.keep_gradients: - self._gradients_s_interpolated = gradients_s_interpolated.copy() - self._gradients_r_interpolated = gradients_r_interpolated.copy() - self._gradients_c_interpolated = gradients_c_interpolated.copy() + # calculate gradients + _c_gradient_3d(&image[f_i, 0, 0, 0], &gradients_col[0, 0, 0], &gradients_row[0, 0, 0], &gradients_slices[0, 0, 0], n_slices, n_rows, n_cols) - if self.keep_interpolated: - self._img_interpolated = img_dum.copy() + # interpolate gradients + gradients_slices_mag = interpolate_3d_zlinear(gradients_slices, _magnification_xy, _magnification_z) + gradients_row_mag = interpolate_3d_zlinear(gradients_row, _magnification_xy, _magnification_z) + gradients_col_mag = interpolate_3d_zlinear(gradients_col, _magnification_xy, _magnification_z) with nogil: - for sM in range(0, n_slices_mag): - for rM in range(0, n_rows_mag): - for cM in range(0, n_cols_mag): + for sM in range(margin_z, n_slices_mag-margin_z): + for rM in range(margin, n_rows_mag-margin): + for cM in range(margin, n_cols_mag-margin): + rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_col_mag[0,0,0], &gradients_row_mag[0,0,0], &gradients_slices_mag[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, _voxel_ratio, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) if _doIntensityWeighting: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val * image_interpolated[sM, rM, cM] - else: - rgc_val = _c_calculate_rgc3D(cM, rM, sM, &gradients_c_interpolated[0,0,0], &gradients_r_interpolated[0,0,0], &gradients_s_interpolated[0,0,0], n_cols_mag, n_rows_mag, n_slices_mag, _magnification_xy, _magnification_z, PSF_voxel_ratio, Gx_Gy_MAGNIFICATION, Gx_Gy_MAGNIFICATION, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) - rgc_map[f, sM, rM, cM] = rgc_val - - return np.asarray(rgc_map) + rgc_val = rgc_val * image_interpolated[sM, rM, cM] + if mode == "average": + rgc_out[sM, rM, cM] = rgc_out[sM, rM, cM] + (rgc_val - rgc_out[sM, rM, cM]) / (f_i + 1) + elif mode == "std": + delta = rgc_val - rgc_mean[sM, rM, cM] + rgc_mean[sM, rM, cM] += delta / (f_i + 1) + delta_2 = rgc_val - rgc_mean[sM, rM, cM] + rgc_out[sM, rM, cM] += delta * delta_2 + if mode == "std": + rgc_out = np.sqrt(np.asarray(rgc_out) / n_frames) + return rgc_out + else: + return np.asarray(rgc_out) - def get_gradients(self): - if self._gradients_c_interpolated is None or self._gradients_r_interpolated is None or self._gradients_s_interpolated is None: - print("Gradients not yet calculated") + def _run_opencl(self, float[:,:,:,:] image, magnification_xy: int = 5, magnification_z: int = 5, radius: float = 1.5, radius_z: float = 1.5, voxel_ratio: float = 4.0, sensitivity: float = 1, mode: str = "average", doIntensityWeighting: bool = True, device=None, mem_div=1): + """ + @gpu + """ + # select cl device + if device is None: + device = _fastest_device + + # create cl context and queue + cl_ctx = cl.Context([device['device']]) + dc = device['device'] + cl_queue = cl.CommandQueue(cl_ctx) + + output_shape = (image.shape[1] * magnification_z, image.shape[2] * magnification_xy, image.shape[3] * magnification_xy) + output_array = np.zeros(output_shape, dtype=np.float32) + + # create input cl buffers + input_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=np.ascontiguousarray(image)) + intermediate_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * magnification_xy * image.shape[3] * magnification_xy * np.dtype(np.float32).itemsize) + input_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create gradient buffers + slices_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + rows_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + cols_gradient_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=image.shape[1] * image.shape[2] * image.shape[3] * np.dtype(np.float32).itemsize) + slices_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + rows_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + cols_gradient_magnified_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create rgc cl buffer + rgc_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create output cl buffer + output_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + if mode == "std": + mean_buffer = cl.Buffer(cl_ctx, cl.mem_flags.READ_WRITE, size=output_array.nbytes) + + # create cl code, program and kernels + cl_code = self._get_cl_code("_le_esrrf3d_.cl", device["DP"]) + cl_prg = cl.Program(cl_ctx, cl_code).build(options=["-cl-fast-relaxed-math", "-cl-mad-enable"]) + interpolate_xy_kernel = cl_prg.interpolate_xy_2d + interpolate_z_kernel = cl_prg.interpolate_z_1d + gradients_kernel = cl_prg.gradients_3d + rgc_kernel = cl_prg.calculate_rgc3D + if mode == "average": + time_projection_kernel = cl_prg.time_projection_average + elif mode == "std": + time_projection_kernel = cl_prg.time_projection_std else: - return self._gradients_c_interpolated, self._gradients_r_interpolated, self._gradients_s_interpolated + raise ValueError("Invalid mode. Use 'average' or 'std'.") + + # set margins + margin = int(radius*magnification_xy) + margin_z = int(radius_z*magnification_z) + lowest_slice = margin_z + highest_slice = output_shape[0] - margin_z + lowest_row = margin + highest_row = output_shape[1] - margin + lowest_col = margin + highest_col = output_shape[2] - margin + + # set constants + cdef float sigma = radius / 2.355 + cdef float tss = 2 * sigma * sigma + cdef float tso = 2 * sigma + 1 + cdef float sigma_z = radius_z / 2.355 # Taking voxel size into account + cdef float tss_z = 2 * sigma_z * sigma_z + cdef float tso_z = 2 * sigma_z + 1 + + cdef float frame_div = 0.0 + + # loop over frames: + for frame_i in range(image.shape[0]): + # interpolate image + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + input_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(frame_i), + ).wait() + + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + input_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + # calculate gradients + gradients_kernel( + cl_queue, + (image.shape[1], image.shape[2], image.shape[3]), + None, + input_buffer, + slices_gradient_buffer, + cols_gradient_buffer, + rows_gradient_buffer, + np.int32(image.shape[1]), + np.int32(image.shape[2]), + np.int32(image.shape[3]), + np.int32(frame_i), + ).wait() + + # interpolate gradients + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + slices_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + slices_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + rows_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + rows_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + interpolate_xy_kernel( + cl_queue, + (image.shape[1], output_shape[1], output_shape[2]), + None, + cols_gradient_buffer, + intermediate_buffer, + np.float32(magnification_xy), + np.int32(0), + ).wait() + interpolate_z_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + intermediate_buffer, + cols_gradient_magnified_buffer, + np.float32(magnification_z), + np.int32(0), + ).wait() + + # calculate rgc + + rgc_kernel( + cl_queue, + (highest_slice - lowest_slice, highest_row - lowest_row, highest_col - lowest_col), + None, + slices_gradient_magnified_buffer, + rows_gradient_magnified_buffer, + cols_gradient_magnified_buffer, + input_magnified_buffer, + rgc_buffer, + np.int32(output_shape[0]), + np.int32(output_shape[1]), + np.int32(output_shape[2]), + np.int32(magnification_xy), + np.int32(magnification_z), + np.float32(voxel_ratio), + np.float32(radius), + np.float32(radius_z), + np.float32(tso), + np.float32(tss), + np.float32(tso_z), + np.float32(tss_z), + np.float32(sensitivity), + np.int32(doIntensityWeighting), + np.int32(frame_i), + ).wait() + + if mode == "std": + time_projection_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + rgc_buffer, + mean_buffer, + output_buffer, + np.int32(frame_i), + ).wait() + else: + time_projection_kernel( + cl_queue, + (output_shape[0], output_shape[1], output_shape[2]), + None, + rgc_buffer, + output_buffer, + np.int32(frame_i), + ).wait() + cl_queue.finish() + cl.enqueue_copy(cl_queue, output_array, output_buffer).wait() + + if mode == "std": + return np.asarray(np.sqrt(output_array / image.shape[0])) + else: + return np.asarray(output_array) + + + def _compare_runs(self, output_1, output_2): + """@public""" + if output_1.ndim > 2: + pcc = 0 + count = 0 + for i in range(output_1.shape[0]): + pccresult = pearson_correlation(output_1[i, :, :].flatten(), output_2[i, :, :].flatten()).statistic + + if np.isnan(pccresult): + continue + else: + count += 1 + # calculate pcc for each frame + pcc += (pccresult-pcc) / count + else: + pcc = pearson_correlation(output_1.flatten(), output_2.flatten()).statistic - def get_interpolated_image(self): - return self._img_interpolated \ No newline at end of file + if pcc > 0.8: + return True + else: + return False \ No newline at end of file diff --git a/src/nanopyx/core/transform/_le_esrrf3d_.cl b/src/nanopyx/core/transform/_le_esrrf3d_.cl new file mode 100644 index 00000000..f5d65dfb --- /dev/null +++ b/src/nanopyx/core/transform/_le_esrrf3d_.cl @@ -0,0 +1,368 @@ +__kernel void interpolate_z_1d(__global float* image, __global float* image_out, float magnification_z, int frame_i) { + int sM = get_global_id(0); + int r = get_global_id(1); + int c = get_global_id(2); + float slice = sM / magnification_z; + + int slicesM = get_global_size(0); + int rows = get_global_size(1); + int cols = get_global_size(2); + int slices = (int)(slicesM / magnification_z); + + int slice0 = (int)floor(slice); + int slice1 = slice0 + 1; + + float weight1 = slice - slice0; + float weight0 = 1.0f - weight1; + + if (magnification_z == 1) { + image_out[sM * rows * cols + r * cols + c] = + image[frame_i * slices * rows * cols + slice0 * rows * cols + r * cols + c]; + } + else if (slice0 >= 0 && slice1 < slices) { + image_out[sM * rows * cols + r * cols + c] = + weight0 * image[frame_i * slices * rows * cols + slice0 * rows * cols + r * cols + c] + + weight1 * image[frame_i * slices * rows * cols + slice1 * rows * cols + r * cols + c]; + } else if (slice0 >= 0) { + image_out[sM * rows * cols + r * cols + c] = + image[frame_i * slices * rows * cols + slice0 * rows * cols + r * cols + c]; + } else if (slice1 < slices) { + image_out[sM * rows * cols + r * cols + c] = + image[frame_i * slices * rows * cols + slice1 * rows * cols + r * cols + c]; + } else { + image_out[sM * rows * cols + r * cols + c] = 0.0f; + } +} + +float _c_cubic(float v) { + float a = 0.5; + float z = 0; + if (v < 0) { + v = -v; + } + if (v < 1) { + z = v * v * (v * (-a + 2) + (a - 3)) + 1; + } else if (v < 2) { + z = -a * v * v * v + 5 * a * v * v - 8 * a * v + 4 * a; + } + return z; +} + +float _c_interpolate(__global float *image, float row, float col, int rows, int cols) { + int r = (int)row; + int c = (int)col; + if (r < 0 || r >= rows || c < 0 || c >= cols) { + return 0; + } + return image[r * cols + c]; +} + +float _c_interpolate_cr(__global float *image, float r, float c, int rows, int cols) { + // return 0 if r OR c positions do not exist in image + if (r < 0 || r >= rows || c < 0 || c >= cols) { + return 0; + } + + const int r_int = (int)floor((float) (r - 0.5)); + const int c_int = (int)floor((float) (c - 0.5)); + float q = 0; + float p = 0; + + int r_neighbor, c_neighbor; + + for (int j = 0; j < 4; j++) { + c_neighbor = c_int - 1 + j; + p = 0; + if (c_neighbor < 0 || c_neighbor >= cols) { + continue; + } + + for (int i = 0; i < 4; i++) { + r_neighbor = r_int - 1 + i; + if (r_neighbor < 0 || r_neighbor >= rows) { + continue; + } + p = p + image[r_neighbor * cols + c_neighbor] * + _c_cubic(r - (r_neighbor + 0.5)); + } + q = q + p * _c_cubic(c - (c_neighbor + 0.5)); + } + return q; +} + +__kernel void interpolate_xy_2d(__global float* image, __global float* image_out, float magnification_xy, int frame_i) { + int s = get_global_id(0); + int rM = get_global_id(1); + int cM = get_global_id(2); + + float row = rM / magnification_xy; + float col = cM / magnification_xy; + + int slices = get_global_size(0); + int rowsM = get_global_size(1); + int colsM = get_global_size(2); + + int rows = (int)(rowsM / magnification_xy); + int cols = (int)(colsM / magnification_xy); + + if (magnification_xy == 1) { + image_out[s * rowsM * colsM + rM * colsM + cM] = + image[frame_i * slices * rows * cols + s * rows * cols + rM * cols + cM]; + } + else { + image_out[s * rowsM * colsM + rM * colsM + cM] = + _c_interpolate_cr(&image[frame_i * slices * rows * cols + s * rows * cols], row, col, rows, cols); + } +} + + +void _c_gradient_3d(__global float* image, __global float* imGc, __global float* imGr, __global float* imGs, int slices, int rows, int cols, int z_i, int y_i, int x_i) { + float z0x0y0, z0x0y1, z0x1y0, z0x_1y0, z0x0y_1; + float z1x0y0, z_1x0y0; + + int z_plus1, y_plus1, x_plus1, + z_minus1, y_minus1, x_minus1; + + z_plus1 = z_i >= slices - 1 ? slices - 1 : z_i + 1; + y_plus1 = y_i >= rows - 1 ? rows - 1 : y_i + 1; + x_plus1 = x_i >= cols - 1 ? cols - 1 : x_i + 1; + + z_minus1 = z_i <= 0 ? 0 : z_i - 1; + y_minus1 = y_i <= 0 ? 0 : y_i - 1; + x_minus1 = x_i <= 0 ? 0 : x_i - 1; + + // z=0 + z0x0y0 = image[z_i * rows * cols + y_i * cols + x_i]; // central pixel + z0x0y1 = image[z_i * rows * cols + y_plus1 * cols + x_i]; // y+1 + z0x1y0 = image[z_i * rows * cols + y_i * cols + x_plus1]; // x+1 + z0x0y_1 = image[z_i * rows * cols + y_minus1 * cols + x_i]; // y-1 + z0x_1y0 = image[z_i * rows * cols + y_i * cols + x_minus1]; // x-1 + + // z=1 + z1x0y0 = image[z_plus1 * rows * cols + y_i * cols + x_i]; // z+1 + + // z=-1 + z_1x0y0 = image[z_minus1 * rows * cols + y_i * cols + x_i]; // z-1 + + imGc[z_i * rows* cols + y_i * cols + x_i] = (z0x1y0 - z0x_1y0)/2; + imGr[z_i * rows* cols + y_i * cols + x_i] = (z0x0y1 - z0x0y_1)/2; + imGs[z_i * rows* cols + y_i * cols + x_i] = (z0x0y0 - z_1x0y0)/2; + +} + +__kernel void gradients_3d(__global float* image, __global float* imGs, __global float* imGc, __global float* imGr, int slices, int rows, int cols, int frame_index) { + int z_i = get_global_id(0); + int y_i = get_global_id(1); + int x_i = get_global_id(2); + + if (z_i < slices && y_i < rows && x_i < cols) { + _c_gradient_3d(&image[frame_index*slices*rows*cols], &imGc[0], &imGr[0], &imGs[0], slices, rows, cols, z_i, y_i, x_i); + } +} + +float _c_calculate_dw3D(float distance, float distance_xy, float distance_z,float tSS, float tSS_z) { + float D_weight_xy, D_weight_z, D_weight; + D_weight_xy = (exp((-distance_xy * distance_xy) / tSS)); + D_weight_z = (exp((-distance_z * distance_z) / tSS_z)); + D_weight = distance * (D_weight_xy * D_weight_z); + return pow(D_weight, 4); +} + +double _c_calculate_dw_3d(double distance_xy, double distance_z, double tSS, double tSS_z) { + double weight_xy = distance_xy * exp((-distance_xy * distance_xy) / tSS); + double weight_z = distance_z * exp((-distance_z * distance_z) / tSS_z); + return pow((weight_xy * weight_z), 4); +} + +float _c_calculate_dk3D(float Gx, float Gy, float Gz, float dx, float dy, float dz, float distance) { + float Dk = sqrt((Gy * dz - Gz * dy) * (Gy * dz - Gz * dy) + (Gz * dx - Gx * dz) * (Gz * dx - Gx * dz) + (Gx * dy - Gy * dx) * (Gx * dy - Gy * dx)) / sqrt(Gx * Gx + Gy * Gy + Gz * Gz); + if (isnan(Dk)) { + Dk = distance; + } + Dk = 1 - Dk / distance; + return Dk; +} + +float _c_calculate_dk_3d(float Gx, float Gy, float Gz, float dx, float dy, float dz, float distance) { + // Compute the cross product magnitude in 3D + float cross_magnitude = sqrt( + pow(Gy * dz - Gz * dy, 2) + + pow(Gz * dx - Gx * dz, 2) + + pow(Gx * dy - Gy * dx, 2) + ); + + // Compute the magnitude of the gradient vector + float gradient_magnitude = sqrt(Gx * Gx + Gy * Gy + Gz * Gz); + + // Compute Dk + float Dk = cross_magnitude / gradient_magnitude; + + // Handle NaN case + if (isnan(Dk)) { + Dk = distance; + } + + // Normalize Dk + Dk = 1 - Dk / distance; + + return Dk; +} + +float _c_calculate_rgc3D(int xM, int yM, int sliceM, __global float* imIntGx, __global float* imIntGy, __global float* imIntGz, int colsM, int rowsM, int slicesM, int magnification_xy, int magnification_z, float voxel_ratio, float fwhm, float fwhm_z, float tSO, float tSO_z, float tSS, float tSS_z, float sensitivity) { + + float vx, vy, vz, Gx, Gy, Gz, dx, dy, dz, dz_real, distance, distance_xy, distance_z, distanceWeight, GdotR, Dk; + + float xc = (float)(xM) / magnification_xy; + float yc = (float)(yM) / magnification_xy; + float zc = (float)(sliceM) / magnification_z; + + float RGC = 0.0f; + float distanceWeightSum = 0.0f; + + int _start = -(int)(fwhm); + int _end = (int)(fwhm + 1); + + int _start_z = -(int)(fwhm_z); + int _end_z = (int)(fwhm_z + 1); + + for (int j = _start; j <= _end; j++) { + vy = yc + j; + + if (0 < vy && vy <= (rowsM/magnification_xy) - 1) { + for (int i = _start; i <= _end; i++) { + vx = xc + i; + + if (0 < vx && vx <= (colsM/magnification_xy) - 1) { + for (int k = _start_z; k <= _end_z; k++) { + vz = zc + k; + + if (0 < vz && vz <= (slicesM/magnification_z) - 1) { + dx = vx - xc; + dy = vy - yc; + dz = vz - zc; + dz_real = dz * voxel_ratio; + distance = sqrt(dx * dx + dy * dy + dz_real * dz_real); + distance_xy = sqrt(dx * dx + dy * dy); + distance_z = dz_real; + + if (distance != 0 && distance_xy <= tSO && distance_z <= tSO_z) { + int linear_index = (int)(vz * magnification_z) * rowsM * colsM + + (int)(magnification_xy * vy) * colsM + + (int)(magnification_xy * vx); + + Gx = imIntGx[linear_index]; + Gy = imIntGy[linear_index]; + Gz = imIntGz[linear_index]; + + // distanceWeight = _c_calculate_dw3D_isotropic(distance, tSS); + distanceWeight = _c_calculate_dw3D(distance, distance_xy, distance_z, tSS, tSS_z); + //distanceWeight = _c_calculate_dw_3d(distance_xy, distance_z, tSS, tSS_z); + + // distanceWeight_xy = _c_calculate_dw_xy(distance_xy, tSS); + // distanceWeight_z = _c_calculate_dw_z(distance_z, tSS_z); + + distanceWeightSum = distanceWeightSum + distanceWeight; + // distanceWeightSum_xy += distanceWeight_xy; + // distanceWeightSum_z += distanceWeight_z; + GdotR = Gx*dx + Gy*dy + Gz*dz_real; + + if (GdotR < 0) { + Dk = _c_calculate_dk3D(Gx, Gy, Gz, dx, dy, dz_real, distance); + RGC = RGC + (Dk * distanceWeight); + } + } + } + } + } + } + } + } + + if (distanceWeightSum == 0) { + return 0; + } + + RGC = RGC / distanceWeightSum; + + if (RGC >= 0 && sensitivity > 1) { + RGC = pow(RGC, sensitivity); + } else if (RGC < 0) { + RGC = 0; + } + + if (isnan(RGC)) { + RGC = 0; + } + + return RGC; +} + +__kernel void calculate_rgc3D(__global float* imIntGz, __global float* imIntGy, __global float* imIntGx, __global float* imM, __global float* tmp_slice, int slicesM, int rowsM, int colsM, int magnification_xy, int magnification_z, float ratio_px, float fwhm, float fwhm_z, float tSO, float tSS, float tSO_z, float tSS_z, float sensitivity, int doIntensityWeighting, int f) { + + // Index of the current pixel + int s = get_global_id(0); + int row = get_global_id(1); + int col = get_global_id(2); + + // Output image dimensions + int nPixels_out = slicesM * rowsM * colsM; + + row = row + fwhm*magnification_xy; + col = col + fwhm*magnification_xy; + s = s + fwhm_z*magnification_z; + + if (doIntensityWeighting == 1) { + tmp_slice[s * rowsM * colsM + row * colsM + col] = _c_calculate_rgc3D(col, row, s, &imIntGx[0], &imIntGy[0], &imIntGz[0], colsM, rowsM, slicesM, magnification_xy, magnification_z, ratio_px, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity) * imM[s * rowsM * colsM + row * colsM + col]; + } else { + tmp_slice[s * rowsM * colsM + row * colsM + col] = _c_calculate_rgc3D(col, row, s, &imIntGx[0], &imIntGy[0], &imIntGz[0], colsM, rowsM, slicesM, magnification_xy, magnification_z, ratio_px, fwhm, fwhm_z, tSO, tSO_z, tSS, tSS_z, sensitivity); + } +} + +__kernel void time_projection_average(__global float* current_slice, __global float* output, int frame_i) { + int s = get_global_id(0); + int row = get_global_id(1); + int col = get_global_id(2); + + int rows = get_global_size(1); + int cols = get_global_size(2); + + int current_index = s * rows * cols + row * cols + col; + + // Ensure proper initialization for the first frame + if (frame_i == 0) { + output[current_index] = current_slice[current_index] / (frame_i + 1); + } else { + // Accumulate the average + // output[current_index] = output[current_index]; + output[current_index] = output[current_index] + ((current_slice[current_index] - output[current_index]) / (frame_i + 1)); + } +} + +__kernel void time_projection_std( + __global float* current_slice, + __global float* mean_output, + __global float* variance_output, + int frame_i +) { + int s = get_global_id(0); + int row = get_global_id(1); + int col = get_global_id(2); + + int rows = get_global_size(1); + int cols = get_global_size(2); + + int current_index = s * rows * cols + row * cols + col; + + // Ensure proper initialization for the first frame + if (frame_i == 0) { + mean_output[current_index] = current_slice[current_index]; + variance_output[current_index] = 0.0f; + } else { + // Update the running mean + float delta = current_slice[current_index] - mean_output[current_index]; + mean_output[current_index] += delta / (frame_i + 1); + float delta2 = current_slice[current_index] - mean_output[current_index]; + // Update the running variance + variance_output[current_index] += delta * delta2; + } +} \ No newline at end of file diff --git a/src/nanopyx/core/transform/_le_radial_gradient_convergence.cl b/src/nanopyx/core/transform/_le_radial_gradient_convergence.cl index 746b34ef..c1caea2e 100644 --- a/src/nanopyx/core/transform/_le_radial_gradient_convergence.cl +++ b/src/nanopyx/core/transform/_le_radial_gradient_convergence.cl @@ -47,6 +47,7 @@ float _c_calculate_rgc(int xM, int yM, __global float* imIntGx, __global float* float vx, vy, Gx, Gy, dx, dy, distance, distanceWeight, GdotR, Dk; float2 correctedv; float2 correctedd; + float correct_vx, correct_vy; float xc = (float)xM / magnification + offset; // offset in non-magnified space float yc = (float)yM / magnification + offset; @@ -54,8 +55,8 @@ float _c_calculate_rgc(int xM, int yM, __global float* imIntGx, __global float* float RGC = 0; float distanceWeightSum = 0; - int _start = -(int)(2 * fwhm); //changed to have "Factor Cagança" but with properly iterating over the desired range - int _end = (int)(2 * fwhm + 1); // TODO discuss with Ricardo + int _start = -(int)(fwhm); + int _end = (int)(fwhm + 1); for (int j = _start; j < _end; j++) { vy = yc + j; @@ -70,8 +71,24 @@ float _c_calculate_rgc(int xM, int yM, __global float* imIntGx, __global float* distance = sqrt(dx * dx + dy * dy); if (distance != 0 && distance <= tSO) { - Gx = imIntGx[(int)((vy+xyoffset) * magnification * Gx_Gy_MAGNIFICATION * colsM * Gx_Gy_MAGNIFICATION) + (int)((vx+xyoffset) * magnification * Gx_Gy_MAGNIFICATION)]; - Gy = imIntGy[(int)((vy+xyoffset) * magnification * Gx_Gy_MAGNIFICATION * colsM * Gx_Gy_MAGNIFICATION) + (int)((vx+xyoffset) * magnification * Gx_Gy_MAGNIFICATION)]; + + correct_vx = vx+xyoffset; + correct_vy = vy+xyoffset; + + if (correct_vx np.ndarray: + """ + Corrects the macro-pixel effect. + + Parameters + ---------- + img : np.ndarray + The input image to be corrected. + magnification : int + The magnification factor used. + + Returns + ------- + np.ndarray + The corrected image. + """ + + return np.asarray(_macro_pixel_corrector(img.astype(np.float32), magnification), dtype=np.float32) + +cdef float[:, :, :] _macro_pixel_corrector(float[:, :, :] img, int magnification): + """ + Cython implementation of the macro-pixel correction. + + Parameters + ---------- + img : float[:, :, :] + The input image to be corrected. + magnification : int + The magnification factor used. + + Returns + ------- + float[:, :, :] + The corrected image. + """ + cdef int slices = img.shape[0] + cdef int rowsM = img.shape[1] + cdef int colsM = img.shape[2] + cdef int rows = rowsM // magnification + cdef int cols = colsM // magnification + + cdef float map_value, correction + cdef int x, y, offset, s, r, c, gx, gy, y_offset, x_offset + cdef float[:, :] correction_map + + for s in range(slices): + correction_map = np.zeros((magnification, magnification), dtype=np.float32) + for ry in range(rows): + for rx in range(cols): + for y in range(magnification): + for x in range(magnification): + # global coordinates in original image + gx = rx * magnification + x + gy = ry * magnification + y + correction_map[y, x] += img[s, gy, gx] / (rows * cols) + + for yM in range(rowsM): + for xM in range(colsM): + y = yM // magnification + x = xM // magnification + y_offset = yM - y * magnification + x_offset = xM - x * magnification + correction = correction_map[y_offset, x_offset] + if correction != 0: + img[s, yM, xM] /= correction + + return np.asarray(img, dtype=np.float32) + \ No newline at end of file diff --git a/src/nanopyx/core/utils/benchmark.py b/src/nanopyx/core/utils/benchmark.py index be30ea57..dcfce019 100644 --- a/src/nanopyx/core/utils/benchmark.py +++ b/src/nanopyx/core/utils/benchmark.py @@ -2,10 +2,19 @@ import nanopyx import numpy as np -from ..generate.beads import generate_channel_misalignment, generate_timelapse_drift +from ..generate.beads import ( + generate_channel_misalignment, + generate_timelapse_drift, +) + def benchmark_all_le_methods( - n_benchmark_runs=3, img_dims=100, shift=1, magnification=2, rotation=math.radians(15), conv_kernel_dims=5 + n_benchmark_runs=3, + img_dims=100, + shift=1, + magnification=2, + rotation=math.radians(15), + conv_kernel_dims=5, ): """ Runs benchmark tests for all LE methods. @@ -21,26 +30,47 @@ def benchmark_all_le_methods( """ img = np.random.random((img_dims, img_dims)).astype(np.float32) - img_int = np.random.random((img_dims * magnification, img_dims * magnification)).astype(np.float32) + img_int = np.random.random( + (img_dims * magnification, img_dims * magnification) + ).astype(np.float32) kernel = np.ones((conv_kernel_dims, conv_kernel_dims)).astype(np.float32) - bicubic_sm = nanopyx.core.transform._le_interpolation_bicubic.ShiftAndMagnify() - bicubic_ssr = nanopyx.core.transform._le_interpolation_bicubic.ShiftScaleRotate() - cr_sm = nanopyx.core.transform._le_interpolation_catmull_rom.ShiftAndMagnify() - cr_ssr = nanopyx.core.transform._le_interpolation_catmull_rom.ShiftScaleRotate() + bicubic_sm = ( + nanopyx.core.transform._le_interpolation_bicubic.ShiftAndMagnify() + ) + bicubic_ssr = ( + nanopyx.core.transform._le_interpolation_bicubic.ShiftScaleRotate() + ) + cr_sm = ( + nanopyx.core.transform._le_interpolation_catmull_rom.ShiftAndMagnify() + ) + cr_ssr = ( + nanopyx.core.transform._le_interpolation_catmull_rom.ShiftScaleRotate() + ) l_sm = nanopyx.core.transform._le_interpolation_lanczos.ShiftAndMagnify() l_ssr = nanopyx.core.transform._le_interpolation_lanczos.ShiftScaleRotate() - nn_sm = nanopyx.core.transform._le_interpolation_nearest_neighbor.ShiftAndMagnify() - nn_ssr = nanopyx.core.transform._le_interpolation_nearest_neighbor.ShiftScaleRotate() - nn_pt = nanopyx.core.transform._le_interpolation_nearest_neighbor.PolarTransform() + nn_sm = ( + nanopyx.core.transform._le_interpolation_nearest_neighbor.ShiftAndMagnify() + ) + nn_ssr = ( + nanopyx.core.transform._le_interpolation_nearest_neighbor.ShiftScaleRotate() + ) + nn_pt = ( + nanopyx.core.transform._le_interpolation_nearest_neighbor.PolarTransform() + ) conv2d = nanopyx.core.transform._le_convolution.Convolution() rad = nanopyx.core.transform._le_radiality.Radiality() - rc = nanopyx.core.transform._le_roberts_cross_gradients.GradientRobertsCross() - rgc = nanopyx.core.transform._le_radial_gradient_convergence.RadialGradientConvergence() + rc = ( + nanopyx.core.transform._le_roberts_cross_gradients.GradientRobertsCross() + ) + rgc = ( + nanopyx.core.transform._le_radial_gradient_convergence.RadialGradientConvergence() + ) esrrf = nanopyx.core.transform._le_esrrf.eSRRF() + esrrf3d = nanopyx.core.transform._le_esrrf3d.eSRRF3D() nlm = nanopyx.core.transform._le_nlm_denoising.NLMDenoising() @@ -54,13 +84,21 @@ def benchmark_all_le_methods( nn_sm.benchmark(img, shift, shift, magnification, magnification) for i in range(n_benchmark_runs): - bicubic_ssr.benchmark(img, shift, shift, magnification, magnification, rotation) + bicubic_ssr.benchmark( + img, shift, shift, magnification, magnification, rotation + ) for i in range(n_benchmark_runs): - cr_ssr.benchmark(img, shift, shift, magnification, magnification, rotation) + cr_ssr.benchmark( + img, shift, shift, magnification, magnification, rotation + ) for i in range(n_benchmark_runs): - l_ssr.benchmark(img, shift, shift, magnification, magnification, rotation) + l_ssr.benchmark( + img, shift, shift, magnification, magnification, rotation + ) for i in range(n_benchmark_runs): - nn_ssr.benchmark(img, shift, shift, magnification, magnification, rotation) + nn_ssr.benchmark( + img, shift, shift, magnification, magnification, rotation + ) for i in range(n_benchmark_runs): nn_pt.benchmark(img, (img_dims, img_dims), "log") @@ -78,10 +116,15 @@ def benchmark_all_le_methods( for i in range(n_benchmark_runs): esrrf.benchmark(img) + for i in range(n_benchmark_runs): + esrrf3d.benchmark(img[np.newaxis, ...]) + for i in range(n_benchmark_runs): nlm.benchmark(img) - channel_reg = nanopyx.core.analysis._le_channel_registration.ChannelRegistrationEstimator() + channel_reg = ( + nanopyx.core.analysis._le_channel_registration.ChannelRegistrationEstimator() + ) drift_reg = nanopyx.core.analysis._le_drift_calculator.DriftEstimator() @@ -92,4 +135,4 @@ def benchmark_all_le_methods( channel_reg.benchmark(channels_img, 0, 10, 3, 0.5) for i in range(n_benchmark_runs): - drift_reg.benchmark(drift_img) \ No newline at end of file + drift_reg.benchmark(drift_img) diff --git a/src/nanopyx/core/utils/easy_gui.py b/src/nanopyx/core/utils/easy_gui.py index 9c9e739d..70bba1be 100644 --- a/src/nanopyx/core/utils/easy_gui.py +++ b/src/nanopyx/core/utils/easy_gui.py @@ -8,6 +8,7 @@ import numpy as np from ipyfilechooser import FileChooser from skimage.exposure import rescale_intensity +import warnings # import cache if python >= 3.9, otherwise import lru_cache if platform.python_version_tuple() >= ("3", "9"): @@ -15,13 +16,21 @@ else: from functools import lru_cache as cache +warnings.warn( + "The EasyGui class is deprecated.\nConsider using ezinput (the updated version of EasyGui) instead.\nYou can install ezinput with 'pip install ezinput'.\nThe API is similar to EasyGui, but with additional features and improvements.\nIt also allows to run the same widget code in both Jupyter Notebooks and on the terminal.\nFor more information: https://github.com/henriqueslab/ezinput", + DeprecationWarning, + stacklevel=2, +) + try: import ipywidgets as widgets from IPython import display as dp from IPython.display import display, clear_output from matplotlib import pyplot as plt except ImportError: - print("jupyter optional-dependencies not installed, conside installing with 'pip install nanopyx[jupyter]'") + print( + "jupyter optional-dependencies not installed, conside installing with 'pip install nanopyx[jupyter]'" + ) raise ImportError @@ -102,7 +111,9 @@ def add_label(self, *args, **kwargs): :param kwargs: kwargs for the widget """ self._nLabels += 1 - self._widgets[f"label_{self._nLabels}"] = widgets.Label(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[f"label_{self._nLabels}"] = widgets.Label( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_button(self, tag, *args, **kwargs): """ @@ -111,7 +122,9 @@ def add_button(self, tag, *args, **kwargs): :param args: args for the widget :param kwargs: kwargs for the widget """ - self._widgets[tag] = widgets.Button(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.Button( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_text(self, tag, *args, **kwargs): """ @@ -120,7 +133,9 @@ def add_text(self, tag, *args, **kwargs): :param args: args for the widget :param kwargs: kwargs for the widget """ - self._widgets[tag] = widgets.Text(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.Text( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_int_slider(self, tag, *args, remember_value=False, **kwargs): """ @@ -130,9 +145,15 @@ def add_int_slider(self, tag, *args, remember_value=False, **kwargs): :param remember_value: remember the last value :param kwargs: kwargs for the widget """ - if remember_value and tag in self.cfg and kwargs["min"] <= self.cfg[tag] <= kwargs["max"]: + if ( + remember_value + and tag in self.cfg + and kwargs["min"] <= self.cfg[tag] <= kwargs["max"] + ): kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.IntSlider(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.IntSlider( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_float_slider(self, tag, *args, remember_value=False, **kwargs): """ @@ -144,7 +165,9 @@ def add_float_slider(self, tag, *args, remember_value=False, **kwargs): """ if remember_value and tag in self.cfg: kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.FloatSlider(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.FloatSlider( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_checkbox(self, tag, *args, remember_value=False, **kwargs): """ @@ -156,7 +179,9 @@ def add_checkbox(self, tag, *args, remember_value=False, **kwargs): """ if remember_value and tag in self.cfg: kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.Checkbox(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.Checkbox( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_int_text(self, tag, *args, remember_value=False, **kwargs): """ @@ -169,7 +194,9 @@ def add_int_text(self, tag, *args, remember_value=False, **kwargs): if remember_value and tag in self.cfg: kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.IntText(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.IntText( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_float_text(self, tag, *args, remember_value=False, **kwargs): """ @@ -181,7 +208,9 @@ def add_float_text(self, tag, *args, remember_value=False, **kwargs): """ if remember_value and tag in self.cfg: kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.FloatText(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.FloatText( + *args, **kwargs, layout=self._layout, style=self._style + ) def add_dropdown(self, tag, *args, remember_value=False, **kwargs): """ @@ -191,11 +220,19 @@ def add_dropdown(self, tag, *args, remember_value=False, **kwargs): :param remember_value: remember the last value :param kwargs: kwargs for the widget """ - if remember_value and tag in self.cfg and self.cfg[tag] in kwargs["options"]: + if ( + remember_value + and tag in self.cfg + and self.cfg[tag] in kwargs["options"] + ): kwargs["value"] = self.cfg[tag] - self._widgets[tag] = widgets.Dropdown(*args, **kwargs, layout=self._layout, style=self._style) + self._widgets[tag] = widgets.Dropdown( + *args, **kwargs, layout=self._layout, style=self._style + ) - def add_file_upload(self, tag, *args, accept=None, multiple=False, **kwargs): + def add_file_upload( + self, tag, *args, accept=None, multiple=False, **kwargs + ): """ Add a file upload widget to the container. :param tag: tag to identify the widget @@ -224,7 +261,7 @@ def show(self): Show the widgets in the container. """ # display the widgets - self._main_display.children = (tuple(self._widgets.values())) + self._main_display.children = tuple(self._widgets.values()) clear_output() display(self._main_display) diff --git a/src/nanopyx/methods/__init__.py b/src/nanopyx/methods/__init__.py index fe53a7f6..df619b24 100644 --- a/src/nanopyx/methods/__init__.py +++ b/src/nanopyx/methods/__init__.py @@ -3,6 +3,7 @@ from .restoration import non_local_means_denoising from .esrrf.eSRRF_workflow import eSRRF +from .esrrf_3d.eSRRF3D_workflow import eSRRF3D from .esrrf import run_esrrf_parameter_sweep from .srrf.SRRF_workflow import SRRF from .squirrel import calculate_frc, calculate_decorr_analysis, calculate_error_map diff --git a/src/nanopyx/methods/esrrf/eSRRF_workflow.py b/src/nanopyx/methods/esrrf/eSRRF_workflow.py index 42e8ea12..48f7e250 100644 --- a/src/nanopyx/methods/esrrf/eSRRF_workflow.py +++ b/src/nanopyx/methods/esrrf/eSRRF_workflow.py @@ -1,5 +1,6 @@ from ..workflow import Workflow from ...core.transform import eSRRF_ST +from ...core.transform.mpcorrector import macro_pixel_corrector import numpy as np # TODO check correlations and error map @@ -8,9 +9,11 @@ def eSRRF( image, magnification: int = 5, + grad_magnification: int = 1, radius: float = 1.5, sensitivity: float = 1, doIntensityWeighting: bool = True, + macro_pixel_correction: bool = True, _force_run_type=None, ): """ @@ -22,6 +25,7 @@ def eSRRF( radius (float, optional): Radius parameter for eSRRF analysis (default is 1.5). sensitivity (float, optional): Sensitivity parameter for eSRRF analysis (default is 1). doIntensityWeighting (bool, optional): Enable intensity weighting (default is True). + macro_pixel_correction (bool, optional): Enable macro pixel correction (default is True). _force_run_type (str, optional): Force a specific run type for the analysis (default is None). Returns: @@ -47,11 +51,17 @@ def eSRRF( (image,), { "magnification": magnification, + "grad_magnification": grad_magnification, "radius": radius, "sensitivity": sensitivity, "doIntensityWeighting": doIntensityWeighting, }, ) ) - - return _eSRRF.calculate(_force_run_type=_force_run_type) + if macro_pixel_correction: + return macro_pixel_corrector( + _eSRRF.calculate(_force_run_type=_force_run_type)[0], + magnification=magnification, + ) + else: + return _eSRRF.calculate(_force_run_type=_force_run_type)[0] diff --git a/src/nanopyx/methods/esrrf_3d/eSRRF3D_workflow.py b/src/nanopyx/methods/esrrf_3d/eSRRF3D_workflow.py new file mode 100644 index 00000000..c524e3cc --- /dev/null +++ b/src/nanopyx/methods/esrrf_3d/eSRRF3D_workflow.py @@ -0,0 +1,75 @@ +from ..workflow import Workflow +from ...core.transform._le_esrrf3d import eSRRF3D as eSRRF3D_ST +from ...core.transform.mpcorrector import macro_pixel_corrector + +import numpy as np + + +def eSRRF3D( + img, + magnification_xy=2, + magnification_z=2, + radius: float = 1.5, + radius_z: float = 0.5, + voxel_ratio: float = 4.0, + sensitivity: float = 1, + mode: str = "average", + doIntensityWeighting: bool = True, + macro_pixel_correction: bool = True, + _force_run_type=None, +): + """ + Perform eSRRF3D analysis on an image. + + Args: + img (numpy.ndarray): The input image for eSRRF3D analysis. + magnification_xy (int, optional): Magnification factor in XY plane (default is 2). + magnification_z (int, optional): Magnification factor in Z plane (default is 2). + radius (float, optional): Radius parameter for eSRRF3D analysis (default is 1.5). + radius_z (float, optional): Radius parameter in Z direction for eSRRF3D analysis (default is 0.5). + voxel_ratio (float, optional): Ratio of voxel size in XY to Z direction (default is 4.0). + sensitivity (float, optional): Sensitivity parameter for eSRRF3D analysis (default is 1). + mode (str, optional): Time projection mode (default is "average"). + doIntensityWeighting (bool, optional): Enable intensity weighting (default is True). + macro_pixel_correction (bool, optional): Enable macro pixel correction (default is True). + _force_run_type (str, optional): Force a specific run type for the analysis (default is None). + + Returns: + numpy.ndarray: The result of eSRRF3D analysis, typically representing the localizations. + + Example: + result = eSRRF3D(image, magnification_xy=2, magnification_z=2, radius=1.5, sensitivity=1, doIntensityWeighting=True) + + Note: + - eSRRF3D (enhanced Super-Resolution Radial Fluctuations 3D) is a method for super-resolution localization microscopy in three dimensions. + - This function sets up a workflow to perform eSRRF3D analysis on the input image. + + See Also: + - eSRRF3D_ST: The eSRRF3D step that performs the actual analysis. + - Workflow: The class used to define and run analysis workflows. + + """ + + _eSRRF3D = Workflow( + ( + eSRRF3D_ST(verbose=False), + (img,), + { + "magnification_xy": magnification_xy, + "magnification_z": magnification_z, + "radius": radius, + "radius_z": radius_z, + "voxel_ratio": voxel_ratio, + "sensitivity": sensitivity, + "mode": mode, + "doIntensityWeighting": doIntensityWeighting, + }, + ) + ) + if macro_pixel_correction: + return macro_pixel_corrector( + _eSRRF3D.calculate(_force_run_type=_force_run_type)[0], + magnification=magnification_xy, + ) + else: + return _eSRRF3D.calculate(_force_run_type=_force_run_type)[0] diff --git a/src/nanopyx/methods/esrrf_3d/run.py b/src/nanopyx/methods/esrrf_3d/run.py deleted file mode 100644 index 4ac718b7..00000000 --- a/src/nanopyx/methods/esrrf_3d/run.py +++ /dev/null @@ -1,37 +0,0 @@ -from ...core.transform._le_esrrf3d import eSRRF3D -from ...core.transform.sr_temporal_correlations import ( - calculate_eSRRF3d_temporal_correlations, -) - - -def run_esrrf3d( - img, correlation="AVG", framewindow=5, rollingoverlap=2, **kwargs -): - """ - Calculate the eSRRF3D temporal correlations for the given image. - - Args: - img: The input 3D image. - magnification_xy: The magnification factor for the x and y axes. - magnification_z: The magnification factor for the z axis. - radius: The radius for the xy plane. - radius_z: The radius for the z axis. - sensitivity: The sensitivity for the calculation. - doIntensityWeighting: Whether to perform intensity weighting. - run_type: The type of the run. - keep_gradients: Whether to keep the gradients. - keep_interpolated: Whether to keep the interpolated values. - correlation: The type of correlation to use. - framewindow: The window size for frame. - rollingoverlap: The overlap size for rolling. - - Returns: - The calculated eSRRF3D temporal correlations. - """ - esrrf_calculator = eSRRF3D() - return calculate_eSRRF3d_temporal_correlations( - esrrf_calculator.run(img, **kwargs), - correlation=correlation, - framewindow=framewindow, - rollingoverlap=rollingoverlap, - ) diff --git a/src/nanopyx/methods/srrf/SRRF_workflow.py b/src/nanopyx/methods/srrf/SRRF_workflow.py index 09a7c59e..d2e18f95 100644 --- a/src/nanopyx/methods/srrf/SRRF_workflow.py +++ b/src/nanopyx/methods/srrf/SRRF_workflow.py @@ -1,5 +1,6 @@ from ..workflow import Workflow from ...core.transform import Radiality, CRShiftAndMagnify +from ...core.transform.mpcorrector import macro_pixel_corrector import numpy as np @@ -12,6 +13,7 @@ def SRRF( border=0, radialityPositivityConstraint=True, doIntensityWeighting=True, + macro_pixel_correction=True, _force_run_type=None, ): """ @@ -24,6 +26,7 @@ def SRRF( border (int, optional): Border parameter for radiality analysis (default is 0). radialityPositivityConstraint (bool, optional): Enable radiality positivity constraint (default is True). doIntensityWeighting (bool, optional): Enable intensity weighting (default is True). + macro_pixel_correction (bool, optional): Enable macro pixel correction (default is True). _force_run_type (str, optional): Force a specific run type for the analysis (default is None). Returns: @@ -45,7 +48,11 @@ def SRRF( """ _SRRF = Workflow( - (CRShiftAndMagnify(verbose=False), (image, 0, 0, magnification, magnification), {}), + ( + CRShiftAndMagnify(verbose=False), + (image, 0, 0, magnification, magnification), + {}, + ), ( Radiality(verbose=False), (image, "PREV_RETURN_VALUE_0_0"), @@ -59,4 +66,11 @@ def SRRF( ), ) - return _SRRF.calculate(_force_run_type=_force_run_type) + if macro_pixel_correction: + return macro_pixel_corrector( + _SRRF.calculate(_force_run_type=_force_run_type)[0], + magnification=magnification, + ) + + else: + return _SRRF.calculate(_force_run_type=_force_run_type)[0] diff --git a/src/notebookchef/pantry/image_loading.py b/src/notebookchef/pantry/image_loading.py index 0078c682..a8c27b9c 100644 --- a/src/notebookchef/pantry/image_loading.py +++ b/src/notebookchef/pantry/image_loading.py @@ -6,7 +6,7 @@ def on_button_select_own(b): clear_output() - gui_data.add_label("Select data to use:") + gui_data.add_label(value="Select data to use:") gui_data.add_file_upload("upload") gui_data.add_dropdown("cmaps", description="Colormap:", options=sorted(list(mpl.colormaps)), @@ -17,7 +17,7 @@ def on_button_select_own(b): def on_button_select_example(b): clear_output() - gui_data.add_label("Select data to use:") + gui_data.add_label(value="Select data to use:") gui_data.add_dropdown("data_source", options=image_files, value="Example dataset: "+example_datasets[4], remember_value=True) gui_data.add_dropdown("cmaps", description="Colormap:", diff --git a/src/notebookchef/pantry/methods/channel_registration.py b/src/notebookchef/pantry/methods/channel_registration.py index 26ef263e..2bab319a 100644 --- a/src/notebookchef/pantry/methods/channel_registration.py +++ b/src/notebookchef/pantry/methods/channel_registration.py @@ -42,7 +42,7 @@ def on_button_register(b): gui_reg._main_display.children = gui_reg._main_display.children + (stackview.slice(dataset_registered, colormap=gui_reg["cmaps"].value, continuous_update=True),) -gui_reg.add_label("Channel Registration parameters:") +gui_reg.add_label(value="Channel Registration parameters:") gui_reg.add_int_slider("ref", description="Reference channel", min=0, max=dataset_original.shape[0]-1, value=0) gui_reg.add_int_slider("max", description="Max expected drift", min=0, max=1000, value=10) gui_reg.add_int_slider("blocks", description="Blocks per axis", min=1, max=10, value=5) diff --git a/src/notebookchef/pantry/methods/channel_registration_apply.py b/src/notebookchef/pantry/methods/channel_registration_apply.py index 17be0de8..994b9f24 100644 --- a/src/notebookchef/pantry/methods/channel_registration_apply.py +++ b/src/notebookchef/pantry/methods/channel_registration_apply.py @@ -47,9 +47,9 @@ def on_button_apply(b): gui_reg_apply["Register Image"].description = "Align" gui_reg_apply._main_display.children = gui_reg_apply._main_display.children + (stackview.slice(aligned_image, colormap=gui_reg_apply["cmaps"].value, continuous_update=True),) -gui_reg_apply.add_label("Load translation mask:") +gui_reg_apply.add_label(value="Load translation mask:") gui_reg_apply.add_file_upload("upload") -gui_reg_apply.add_label("Load image to register:") +gui_reg_apply.add_label(value="Load image to register:") gui_reg_apply.add_file_upload("upload image") gui_reg_apply.add_dropdown("cmaps", description="Colormap:", options=sorted(list(mpl.colormaps)), diff --git a/src/notebookchef/pantry/methods/decorr.py b/src/notebookchef/pantry/methods/decorr.py index 65f187b8..58ce131f 100644 --- a/src/notebookchef/pantry/methods/decorr.py +++ b/src/notebookchef/pantry/methods/decorr.py @@ -38,7 +38,7 @@ def run_decorr(b): gui_decorr._main_display.children = gui_decorr._main_display.children + (output_plot,) plt.clf() -gui_decorr.add_int_slider("pixel_size", description="Pixel Size:", min=0.01, max=1000, value=100, remember_value=True) +gui_decorr.add_int_slider("pixel_size", description="Pixel Size:", min=0.01, max=1000, value=100) gui_decorr.add_dropdown("units", description="Units: ", options=["nm", "um", "mm"], value="nm") gui_decorr.add_int_slider("first_frame", description="Frame to be used:", min=0, max=dataset_original.shape[0]-1, value=0) gui_decorr.add_float_slider("rmin", description="Radius Min:", min=0.0, max=0.5, value=0.0) diff --git a/src/notebookchef/pantry/methods/drift_correction.py b/src/notebookchef/pantry/methods/drift_correction.py index 358403ff..639c6ce4 100644 --- a/src/notebookchef/pantry/methods/drift_correction.py +++ b/src/notebookchef/pantry/methods/drift_correction.py @@ -68,30 +68,13 @@ def on_button_align(b): ) -gui_drift.add_label("Drift Correction parameters:") -gui_drift.add_dropdown( - "ref", - description="Reference frame", - options=["First frame", "Previous frame"], - value="First frame", -) -gui_drift.add_int_slider( - "max", description="Max expected drift", min=0, max=1000, value=10 -) -gui_drift.add_int_slider( - "time_averaging", - description="Time averaging", - min=1, - max=dataset_original.shape[0], - value=1, -) -gui_drift.add_dropdown( - "cmaps", - description="Colormap:", - options=sorted(list(mpl.colormaps)), - value="viridis", - remember_value=True, -) +gui_drift.add_label(value="Drift Correction parameters:") +gui_drift.add_dropdown("ref", description="Reference frame", options=["First frame", "Previous frame"], value="First frame") +gui_drift.add_int_slider("max", description="Max expected drift", min=0, max=1000, value=10) +gui_drift.add_int_slider("time_averaging", description="Time averaging", min=1, max=dataset_original.shape[0], value=1) +gui_drift.add_dropdown("cmaps", description="Colormap:", + options=sorted(list(mpl.colormaps)), + value="viridis", remember_value=True) gui_drift.add_checkbox("save", description="Save Output", value=True) gui_drift.add_button("align", description="Align") gui_drift["align"].on_click(on_button_align) diff --git a/src/notebookchef/pantry/methods/drift_correction_apply.py b/src/notebookchef/pantry/methods/drift_correction_apply.py index ba33431d..3955e9c5 100644 --- a/src/notebookchef/pantry/methods/drift_correction_apply.py +++ b/src/notebookchef/pantry/methods/drift_correction_apply.py @@ -49,9 +49,9 @@ def on_button_apply(b): gui_drift_apply["Align image"].description = "Align" gui_drift_apply._main_display.children = gui_drift_apply._main_display.children + (stackview.slice(aligned_image, colormap=gui_drift_apply["cmaps"].value, continuous_update=True),) -gui_drift_apply.add_label("Load drift table:") +gui_drift_apply.add_label(value="Load drift table:") gui_drift_apply.add_file_upload("upload") -gui_drift_apply.add_label("Load image to align:") +gui_drift_apply.add_label(value="Load image to align:") gui_drift_apply.add_file_upload("upload image") gui_drift_apply.add_dropdown("cmaps", description="Colormap:", options=sorted(list(mpl.colormaps)), diff --git a/src/notebookchef/pantry/methods/error_map.py b/src/notebookchef/pantry/methods/error_map.py index 69964a03..50053164 100644 --- a/src/notebookchef/pantry/methods/error_map.py +++ b/src/notebookchef/pantry/methods/error_map.py @@ -1,4 +1,4 @@ -#@title Create Error Map GUI +# @title Create Error Map GUI gui_error = EasyGui("Error") import numpy as np @@ -7,6 +7,7 @@ from matplotlib import pyplot as plt from nanopyx.core.transform import ErrorMap + def run_error(b): clear_output() gui_error.show() @@ -15,7 +16,9 @@ def run_error(b): gui_error["run"].description = "Calculating..." global errormap error_map = ErrorMap() - error_map.optimise(np.mean(dataset_original, axis=0), np.mean(dataset_sr, axis=0)) + error_map.optimise( + np.mean(dataset_original, axis=0), np.mean(dataset_sr, axis=0) + ) gui_error["run"].disabled = False gui_error["run"].description = "Calculate" print("RSE: ", error_map.getRSE()) @@ -27,7 +30,9 @@ def run_error(b): name = gui_data["upload"].selected_filename.split(".")[0] tiff.imwrite(path + os.sep + name + "_error_map.tif", errormap) else: - name = gui_data["data_source"].value.replace("Example dataset: ", "") + name = gui_data["data_source"].value.replace( + "Example dataset: ", "" + ) tiff.imwrite(name + "_error_map.tif", errormap) plt.imshow(errormap) plt.axis("off") @@ -37,11 +42,13 @@ def run_error(b): with output_plot: display(Image.open(img_buf)) gui_error._main_display.children = gui_error._main_display.children + ( - widgets.Label(value="RSE: "+str(error_map.getRSE())), - widgets.Label(value="RSP: "+str(error_map.getRSP())), - output_plot) + widgets.Label(value="RSE: " + str(error_map.getRSE())), + widgets.Label(value="RSP: " + str(error_map.getRSP())), + output_plot, + ) plt.clf() + def run_error_stack(b): clear_output() gui_error.show() @@ -55,27 +62,40 @@ def run_error_stack(b): rse_rsp_table = [] # Ensure datasets are 3D - if np.ndim(dataset_original) == 2: - dataset_original = np.expand_dims(dataset_original, axis=0) - if np.ndim(dataset_sr) == 2: - dataset_sr = np.expand_dims(dataset_sr, axis=0) + if np.ndim(dataset_original) == 2: + dataset_original = np.expand_dims(dataset_original, axis=0) + if np.ndim(dataset_sr) == 2: + dataset_sr = np.expand_dims(dataset_sr, axis=0) + + # Ensures datasets have same number of frames + + if dataset_original.shape[0] > dataset_sr.shape[0]: + factor = dataset_original.shape[0] // dataset_sr.shape[0] + remainder = dataset_original.shape[0] % dataset_sr.shape[0] + averaged_blocks = [ + np.mean(dataset_original[i * factor : (i + 1) * factor], axis=0) + for i in range(dataset_sr.shape[0]) + ] + if remainder > 0: + averaged_blocks.append( + np.mean(dataset_original[-remainder:], axis=0) + ) + dataset_original = np.array(averaged_blocks) # Iterate through each slice print("Processing slices...") - for i in tqdm(range(dataset_original.shape[0]),desc="Slices processed"): - slice_df = dataset_original[i] # - slice_sr = dataset_sr[i] # - + for i in tqdm(range(dataset_original.shape[0]), desc="Slices processed"): + slice_df = dataset_original[i] # + slice_sr = dataset_sr[i] # + error_map = ErrorMap() error_map.optimise(slice_df, slice_sr) # Store the error map and RSE/RSP values errormap_stack.append(np.array(error_map.imRSE)) - rse_rsp_table.append({ - "Slice": i, - "RSE": error_map.getRSE(), - "RSP": error_map.getRSP() - }) + rse_rsp_table.append( + {"Slice": i, "RSE": error_map.getRSE(), "RSP": error_map.getRSP()} + ) # Convert results to arrays errormap_stack = np.array(errormap_stack) # 3D stack of error maps @@ -85,10 +105,16 @@ def run_error_stack(b): if own_data: path = gui_data["upload"].selected_path name = gui_data["upload"].selected_filename.split(".")[0] - tiff.imwrite(path + os.sep + name + "_error_map_stack.tif", errormap_stack) - rse_rsp_table.to_csv(path + os.sep + name + "_rse_rsp_table.csv", index=False) + tiff.imwrite( + path + os.sep + name + "_error_map_stack.tif", errormap_stack + ) + rse_rsp_table.to_csv( + path + os.sep + name + "_rse_rsp_table.csv", index=False + ) else: - name = gui_data["data_source"].value.replace("Example dataset: ", "") + name = gui_data["data_source"].value.replace( + "Example dataset: ", "" + ) tiff.imwrite(name + "_error_map_stack.tif", errormap_stack) rse_rsp_table.to_csv(name + "_rse_rsp_table.csv", index=False) @@ -105,9 +131,13 @@ def run_error_stack(b): gui_error.add_checkbox("save", description="Save output", value=True) -gui_error.add_dropdown("cmaps", description="Colormap:", - options=sorted(list(mpl.colormaps)), - value="viridis", remember_value=True) +gui_error.add_dropdown( + "cmaps", + description="Colormap:", + options=sorted(list(mpl.colormaps)), + value="viridis", + remember_value=True, +) gui_error.add_button("run", description="Calculate") gui_error["run"].on_click(run_error_stack) -gui_error.show() \ No newline at end of file +gui_error.show() diff --git a/src/notebookchef/pantry/methods/esrrf.py b/src/notebookchef/pantry/methods/esrrf.py index 0f162923..76ead076 100644 --- a/src/notebookchef/pantry/methods/esrrf.py +++ b/src/notebookchef/pantry/methods/esrrf.py @@ -1,7 +1,10 @@ -#@title Create eSRRF GUI +# @title Create eSRRF GUI gui_esrrf = EasyGui("esrrf") from nanopyx.methods import eSRRF -from nanopyx.core.transform.sr_temporal_correlations import calculate_eSRRF_temporal_correlations +from nanopyx.core.transform.sr_temporal_correlations import ( + calculate_eSRRF_temporal_correlations, +) + def run_esrrf(b): clear_output() @@ -11,7 +14,7 @@ def run_esrrf(b): magnification = gui_esrrf["magnification"].value frames_per_timepoint = gui_esrrf["frames_per_timepoint"].value sensitivity = gui_esrrf["sensitivity"].value - + mpcorrection = gui_esrrf["mpcorrection"].value esrrf_order = gui_esrrf["esrrf_order"].value if esrrf_order == 1: esrrf_order = "AVG" @@ -27,14 +30,23 @@ def run_esrrf(b): elif frames_per_timepoint > dataset_original.shape[0]: frames_per_timepoint = dataset_original.shape[0] - output= [] + output = [] for i in range(dataset_original.shape[0] // frames_per_timepoint): - block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint] - result = eSRRF(block, magnification=magnification, radius=ring_radius, - sensitivity=sensitivity, - doIntensityWeighting=True) - output.append(calculate_eSRRF_temporal_correlations(result[0], esrrf_order)) + block = dataset_original[ + i * frames_per_timepoint : (i + 1) * frames_per_timepoint + ] + result = eSRRF( + block, + magnification=magnification, + radius=ring_radius, + sensitivity=sensitivity, + doIntensityWeighting=True, + macro_pixel_correction=mpcorrection, + ) + output.append( + calculate_eSRRF_temporal_correlations(result, esrrf_order) + ) global dataset_esrrf dataset_esrrf = np.array(output) @@ -47,25 +59,70 @@ def run_esrrf(b): name = gui_data["upload"].selected_filename.split(".")[0] tiff.imwrite(path + os.sep + name + "_esrrf.tif", dataset_esrrf) else: - name = gui_data["data_source"].value.replace("Example dataset: ", "") + name = gui_data["data_source"].value.replace( + "Example dataset: ", "" + ) tiff.imwrite(name + "_esrrf.tif", dataset_esrrf) - gui_esrrf._main_display.children = gui_esrrf._main_display.children + (stackview.slice(dataset_esrrf, colormap=gui_esrrf["cmaps"].value, continuous_update=True),) + gui_esrrf._main_display.children = gui_esrrf._main_display.children + ( + stackview.slice( + dataset_esrrf, + colormap=gui_esrrf["cmaps"].value, + continuous_update=True, + ), + ) default_radius = 1.5 default_sensitivity = 1 default_magnification = 5 default_esrrf_order = 1 -gui_esrrf.add_float_slider("ring_radius", description="Ring Radius:", min=0.1, max=3.0, value=default_radius, remember_value=True) -gui_esrrf.add_int_slider("sensitivity", description="Sensitivity:", min=1, max=10, value=default_sensitivity) -gui_esrrf.add_int_slider("magnification", description="Magnification:", min=1, max=10, value=default_magnification) -gui_esrrf.add_int_slider("esrrf_order", description="eSRRF order:", min=1, max=3, value=default_esrrf_order) -gui_esrrf.add_label("-=-= Time-Lapse =-=-") -gui_esrrf.add_int_slider("frames_per_timepoint", description="Frames per time-point (0 - auto)", min=0, max=dataset_original.shape[0], value=dataset_original.shape[0]//2) +gui_esrrf.add_float_slider( + "ring_radius", + description="Ring Radius:", + min=0.1, + max=3.0, + value=default_radius, +) +gui_esrrf.add_int_slider( + "sensitivity", + description="Sensitivity:", + min=1, + max=10, + value=default_sensitivity, +) +gui_esrrf.add_int_slider( + "magnification", + description="Magnification:", + min=1, + max=10, + value=default_magnification, +) +gui_esrrf.add_int_slider( + "esrrf_order", + description="eSRRF order:", + min=1, + max=3, + value=default_esrrf_order, +) +gui_esrrf.add_label(value="-=-= Time-Lapse =-=-") +gui_esrrf.add_int_slider( + "frames_per_timepoint", + description="Frames per time-point (0 - auto)", + min=0, + max=dataset_original.shape[0], + value=dataset_original.shape[0] // 2, +) +gui_esrrf.add_checkbox( + "mpcorrection", description="Macro Pixel Correction", value=True +) gui_esrrf.add_checkbox("save", description="Save Output", value=True) -gui_esrrf.add_dropdown("cmaps", description="Colormap:", - options=sorted(list(mpl.colormaps)), - value="viridis", remember_value=True) +gui_esrrf.add_dropdown( + "cmaps", + description="Colormap:", + options=sorted(list(mpl.colormaps)), + value="viridis", + remember_value=True, +) gui_esrrf.add_button("run", description="Run") -gui_esrrf['run'].on_click(run_esrrf) -gui_esrrf.show() \ No newline at end of file +gui_esrrf["run"].on_click(run_esrrf) +gui_esrrf.show() diff --git a/src/notebookchef/pantry/methods/frc.py b/src/notebookchef/pantry/methods/frc.py index d1702373..e421d01a 100644 --- a/src/notebookchef/pantry/methods/frc.py +++ b/src/notebookchef/pantry/methods/frc.py @@ -38,7 +38,7 @@ def run_frc(b): gui_frc._main_display.children = gui_frc._main_display.children + (output_plot,) plt.clf() -gui_frc.add_int_slider("pixel_size", description="Pixel Size:", min=0.01, max=1000, value=100, remember_value=True) +gui_frc.add_int_slider("pixel_size", description="Pixel Size:", min=0.01, max=1000, value=100) gui_frc.add_dropdown("units", description="Units: ", options=["nm", "um", "mm"], value="nm") gui_frc.add_int_slider("first_frame", description="First Frame:", min=0, max=dataset_original[0].shape[0]-1, value=0) gui_frc.add_int_slider ("second_frame", description="Second Frame:", min=0, max=dataset_original[0].shape[0]-1, value=1) diff --git a/src/notebookchef/pantry/methods/nlm_denoising.py b/src/notebookchef/pantry/methods/nlm_denoising.py index 0933b7a4..c1de211d 100644 --- a/src/notebookchef/pantry/methods/nlm_denoising.py +++ b/src/notebookchef/pantry/methods/nlm_denoising.py @@ -31,8 +31,8 @@ def run_nlm(b): tiff.imwrite(name + "_nlm_denoised.tif", dataset_nlm) gui_nlm._main_display.children = gui_nlm._main_display.children + (stackview.slice(dataset_nlm, colormap=gui_nlm["cmaps"].value, continuous_update=True),) -gui_nlm.add_int_slider("patch_size", description="Patch Size", min=1, max=dataset_original.shape[-1]//2, value=5, remember_value=True) -gui_nlm.add_int_slider("patch_distance", description="Patch Distance", min=1, max=dataset_original.shape[-1]//2, value=10, remember_value=True) +gui_nlm.add_int_slider("patch_size", description="Patch Size", min=1, max=dataset_original.shape[-1]//2, value=5) +gui_nlm.add_int_slider("patch_distance", description="Patch Distance", min=1, max=dataset_original.shape[-1]//2, value=10) gui_nlm.add_float_text("h", description="h", value=0.1, remember_value=True) gui_nlm.add_float_text("sigma", description="sigma", value=0.1, remember_value=True) gui_nlm.add_checkbox("save", description="Save Output", value=True) diff --git a/src/notebookchef/pantry/methods/srrf.py b/src/notebookchef/pantry/methods/srrf.py index 4c34da86..aebbfc17 100644 --- a/src/notebookchef/pantry/methods/srrf.py +++ b/src/notebookchef/pantry/methods/srrf.py @@ -1,7 +1,10 @@ -#@title Create SRRF GUI +# @title Create SRRF GUI gui_srrf = EasyGui("srrf") from nanopyx.methods import SRRF -from nanopyx.core.transform.sr_temporal_correlations import calculate_SRRF_temporal_correlations +from nanopyx.core.transform.sr_temporal_correlations import ( + calculate_SRRF_temporal_correlations, +) + def run_srrf(b): clear_output() @@ -11,6 +14,7 @@ def run_srrf(b): magnification = gui_srrf["magnification"].value frames_per_timepoint = gui_srrf["frames_per_timepoint"].value srrf_order = gui_srrf["srrf_order"].value + mpcorrection = gui_srrf["mpcorrection"].value # disable button while running gui_srrf["run"].disabled = True gui_srrf["run"].description = "Running..." @@ -19,14 +23,21 @@ def run_srrf(b): elif frames_per_timepoint > dataset_original.shape[0]: frames_per_timepoint = dataset_original.shape[0] - output= [] + output = [] for i in range(dataset_original.shape[0] // frames_per_timepoint): - block = dataset_original[i*frames_per_timepoint:(i+1)*frames_per_timepoint] - result = SRRF(block, magnification=magnification, ringRadius=ring_radius, - radialityPositivityConstraint=True, - doIntensityWeighting=True) - output.append(calculate_SRRF_temporal_correlations(result[0], srrf_order)) + block = dataset_original[ + i * frames_per_timepoint : (i + 1) * frames_per_timepoint + ] + result = SRRF( + block, + magnification=magnification, + ringRadius=ring_radius, + radialityPositivityConstraint=True, + doIntensityWeighting=True, + macro_pixel_correction=mpcorrection, + ) + output.append(calculate_SRRF_temporal_correlations(result, srrf_order)) global dataset_srrf dataset_srrf = np.array(output) @@ -39,19 +50,47 @@ def run_srrf(b): name = gui_data["upload"].selected_filename.split(".")[0] tiff.imwrite(path + os.sep + name + "_srrf.tif", dataset_srrf) else: - name = gui_data["data_source"].value.replace("Example dataset: ", "") + name = gui_data["data_source"].value.replace( + "Example dataset: ", "" + ) tiff.imwrite(name + "_srrf.tif", dataset_srrf) - gui_srrf._main_display.children = gui_srrf._main_display.children + (stackview.slice(dataset_srrf, colormap=gui_srrf["cmaps"].value, continuous_update=True),) + gui_srrf._main_display.children = gui_srrf._main_display.children + ( + stackview.slice( + dataset_srrf, + colormap=gui_srrf["cmaps"].value, + continuous_update=True, + ), + ) + -gui_srrf.add_float_slider("ring_radius", description="Ring Radius:", min=0.1, max=3.0, value=0.5, remember_value=True) -gui_srrf.add_int_slider("magnification", description="Magnification:", min=1, max=10, value=5) -gui_srrf.add_int_slider("srrf_order", description="SRRF order:", min=-1, max=4, value=3) -gui_srrf.add_label("-=-= Time-Lapse =-=-") -gui_srrf.add_int_slider("frames_per_timepoint", description="Frames per time-point (0 - auto)", min=1, max=dataset_original.shape[0], value=dataset_original.shape[0]//2) +gui_srrf.add_float_slider( + "ring_radius", description="Ring Radius:", min=0.1, max=3.0, value=0.5 +) +gui_srrf.add_int_slider( + "magnification", description="Magnification:", min=1, max=10, value=5 +) +gui_srrf.add_int_slider( + "srrf_order", description="SRRF order:", min=-1, max=4, value=3 +) +gui_srrf.add_label(value="-=-= Time-Lapse =-=-") +gui_srrf.add_int_slider( + "frames_per_timepoint", + description="Frames per time-point (0 - auto)", + min=1, + max=dataset_original.shape[0], + value=dataset_original.shape[0] // 2, +) +gui_srrf.add_checkbox( + "mpcorrection", description="Macro Pixel Correction", value=True +) gui_srrf.add_checkbox("save", description="Save Output", value=True) -gui_srrf.add_dropdown("cmaps", description="Colormap:", - options=sorted(list(mpl.colormaps)), - value="viridis", remember_value=True) +gui_srrf.add_dropdown( + "cmaps", + description="Colormap:", + options=sorted(list(mpl.colormaps)), + value="viridis", + remember_value=True, +) gui_srrf.add_button("run", description="Run") -gui_srrf['run'].on_click(run_srrf) -gui_srrf.show() \ No newline at end of file +gui_srrf["run"].on_click(run_srrf) +gui_srrf.show() diff --git a/src/notebookchef/pantry/notebook_setup.py b/src/notebookchef/pantry/notebook_setup.py index 81b5a9c1..b2a32b7f 100644 --- a/src/notebookchef/pantry/notebook_setup.py +++ b/src/notebookchef/pantry/notebook_setup.py @@ -24,7 +24,10 @@ from IPython.display import display, clear_output from matplotlib import pyplot as plt -from nanopyx.core.utils.easy_gui import EasyGui +try: + from ezinput import EZInput as EasyGui +except ImportError: + from nanopyx.core.utils.easy_gui import EasyGui from nanopyx.core.utils.find_files import find_files from nanopyx.data.download import ExampleDataManager diff --git a/src/notebookchef/recipes/ExampleDataSRRFandQC.txt b/src/notebookchef/recipes/ExampleDataSRRFandQC.txt index 6fa57b64..a695743b 100644 --- a/src/notebookchef/recipes/ExampleDataSRRFandQC.txt +++ b/src/notebookchef/recipes/ExampleDataSRRFandQC.txt @@ -9,9 +9,6 @@ $include: citations/frc.txt $include: citations/decorr.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $markdown diff --git a/src/notebookchef/recipes/NonLocalMeansDenoising.txt b/src/notebookchef/recipes/NonLocalMeansDenoising.txt index 25f81402..cc1ab889 100644 --- a/src/notebookchef/recipes/NonLocalMeansDenoising.txt +++ b/src/notebookchef/recipes/NonLocalMeansDenoising.txt @@ -7,9 +7,6 @@ $include: notebook_intro.txt $include: citations/nlm_denoising.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $code diff --git a/src/notebookchef/recipes/ParamSweepandeSRRF.txt b/src/notebookchef/recipes/ParamSweepandeSRRF.txt index 09259839..d608dc2d 100644 --- a/src/notebookchef/recipes/ParamSweepandeSRRF.txt +++ b/src/notebookchef/recipes/ParamSweepandeSRRF.txt @@ -10,9 +10,6 @@ $include: citations/frc.txt $include: citations/decorr.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $code diff --git a/src/notebookchef/recipes/SRMetrics.txt b/src/notebookchef/recipes/SRMetrics.txt index 60dc424f..52bd849d 100644 --- a/src/notebookchef/recipes/SRMetrics.txt +++ b/src/notebookchef/recipes/SRMetrics.txt @@ -9,9 +9,6 @@ $include: citations/frc.txt $include: citations/decorr.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $markdown diff --git a/src/notebookchef/recipes/SRRFandQC.txt b/src/notebookchef/recipes/SRRFandQC.txt index 82a11123..8c7b22b2 100644 --- a/src/notebookchef/recipes/SRRFandQC.txt +++ b/src/notebookchef/recipes/SRRFandQC.txt @@ -10,9 +10,6 @@ $include: citations/frc.txt $include: citations/decorr.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $code diff --git a/src/notebookchef/recipes/eSRRFandQC.txt b/src/notebookchef/recipes/eSRRFandQC.txt index f87b9c38..dacc4157 100644 --- a/src/notebookchef/recipes/eSRRFandQC.txt +++ b/src/notebookchef/recipes/eSRRFandQC.txt @@ -10,9 +10,6 @@ $include: citations/frc.txt $include: citations/decorr.txt __cellbreak__ $code -$include: opencl_colab_fix.py -__cellbreak__ -$code $include: notebook_setup.py __cellbreak__ $code diff --git a/tests/test_benchmarking.py b/tests/test_benchmarking.py index c5a63013..3afe3bd3 100644 --- a/tests/test_benchmarking.py +++ b/tests/test_benchmarking.py @@ -45,6 +45,9 @@ def test_benchmark_esrrf(random_image_with_ramp): esrrf = nanopyx.core.transform._le_esrrf.eSRRF() esrrf.benchmark(random_image_with_ramp) +def test_benchmark_esrrf3d(): + esrrf = nanopyx.core.transform._le_esrrf3d.eSRRF3D() + esrrf.benchmark(np.random.random((1,10,10,10)).astype(np.float32)) def test_benchmark_nlm(random_image_with_ramp): nlm = nanopyx.core.transform._le_nlm_denoising.NLMDenoising() diff --git a/tests/test_conv2d.py b/tests/test_conv2d.py index 145284d3..bcd0d61a 100644 --- a/tests/test_conv2d.py +++ b/tests/test_conv2d.py @@ -2,17 +2,25 @@ from nanopyx.core.transform._le_convolution import Convolution from nanopyx.core.transform.convolution import convolution2D_numba +import nanopyx.core.transform._transonic + + +def test_convolution2D(): + img = np.random.random((10, 100, 100)).astype(np.float32) + kernel = np.random.random((3, 3)).astype(np.float32) + + nanopyx.core.transform._transonic.convolution2D(img, kernel) def test_conv_small(): - small = np.random.random((10,100, 100)).astype(np.float32) + small = np.random.random((10, 100, 100)).astype(np.float32) kernel = np.ones((23, 23)).astype(np.float32) conv = Convolution() conv.benchmark(small, kernel) def test_convolution2D_numba(): - img = np.random.random((10,100, 100)).astype(np.float32) + img = np.random.random((10, 100, 100)).astype(np.float32) kernel = np.random.random((3, 3)).astype(np.float32) convolution2D_numba(img, kernel) @@ -23,4 +31,3 @@ def test_conv_small_2d(): kernel = np.ones((23, 23)).astype(np.float32) conv = Convolution() conv.benchmark(small, kernel) - diff --git a/tests/test_esrrf3d.py b/tests/test_esrrf3d.py new file mode 100644 index 00000000..69d46546 --- /dev/null +++ b/tests/test_esrrf3d.py @@ -0,0 +1,99 @@ +import numpy as np +from nanopyx.methods import eSRRF3D as eSRRF3D_w +from nanopyx.core.transform import eSRRF3D_ST + + +def test_esrrf3d_workflow(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + eSRRF3D_w(small_dataset) + + +def test_esrrf3d_mag11(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + e3d.benchmark(small_dataset, magnification_xy=1, magnification_z=1) + + +def test_esrrf3d_mag12(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + e3d.benchmark(small_dataset, magnification_xy=1, magnification_z=2) + + +def test_esrrf3d_mag21(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + e3d.benchmark(small_dataset, magnification_xy=2, magnification_z=1) + + +def test_esrrf3d_mag22(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + e3d.benchmark(small_dataset, magnification_xy=2, magnification_z=2) + + +def test_esrrf3d_radius_too_high(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + assert e3d.run(small_dataset, radius=15) is None + + +def test_esrrf3d_radiusz_too_high(downloader): + + dataset = downloader.get_ZipTiffIterator( + "SMLMS2013_HDTubulinAlexa647", as_ndarray=True + ) + small_dataset = dataset[:10, :20, :20] + + dataset = dataset[np.newaxis, ...] + + e3d = eSRRF3D_ST(testing=True, clear_benchmarks=True) + + assert e3d.run(small_dataset, radius_z=15) is None diff --git a/tests/test_package_level_calls.py b/tests/test_package_level_calls.py index 9b3a5b39..147d9fb5 100644 --- a/tests/test_package_level_calls.py +++ b/tests/test_package_level_calls.py @@ -6,22 +6,27 @@ def test_package_nlm(): img = np.random.random((100, 100)).astype(np.float32) nanopyx.non_local_means_denoising(img) + def test_package_SRRF(): img = np.random.random((10, 100, 100)).astype(np.float32) nanopyx.SRRF(img) + def test_package_eSRRF(): img = np.random.random((10, 100, 100)).astype(np.float32) nanopyx.eSRRF(img) + def test_package_frc(): img = np.random.random((2, 100, 100)).astype(np.float32) nanopyx.calculate_frc(img[0], img[1]) + def test_package_decorr(): img = np.random.random((100, 100)).astype(np.float32) nanopyx.calculate_decorr_analysis(img) + def test_package_error_map(): img = np.random.random((100, 100)).astype(np.float32) img_2 = np.random.random((500, 500)).astype(np.float32)