From 6b6ac0ceb705d3c63293ad78c7c6787af057c3a2 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 12:36:28 -0400 Subject: [PATCH 01/10] docs: add nb for image tiling workflow --- notebooks/preprocessing-workflow/tiling.ipynb | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 notebooks/preprocessing-workflow/tiling.ipynb diff --git a/notebooks/preprocessing-workflow/tiling.ipynb b/notebooks/preprocessing-workflow/tiling.ipynb new file mode 100644 index 00000000..139bd9ed --- /dev/null +++ b/notebooks/preprocessing-workflow/tiling.ipynb @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "HOME = \"../..\" # path to the root of the project two levels up\n", + "\n", + "# Activate the environment\n", + "using Pkg\n", + "Pkg.activate(HOME)\n", + "Pkg.precompile()\n", + "\n", + "using IceFloeTracker: get_tiles, get_tile_dims, load\n", + "using ColorTypes: RGBA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = load(\"bering_strait/truecolor/20200504.aqua.truecolor.250m.tiff\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Say we want to split the image into roughly 8x8 tiles\n", + "size(img) .÷ 8" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tile size\n", + "Let us choose tiles of size 450x450. To do that use the `get_tiles` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's view the documentation for the function\n", + "@info @doc get_tiles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tiles = get_tiles(img, 450)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Top left tile dimensions\n", + "get_tile_dims(tiles[1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Bottom right tile dimensions\n", + "get_tile_dims(tiles[end])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the bottom right tile has been extended to cover the rest of the image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# View the first tile\n", + "img[tiles[1]...]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Further, note that the tiles on the right and bottom edges are slightly bigger." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### View the full tiling" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "function build_tiling_illustration(img, side_length)\n", + "\n", + " # Create new canvas to draw on\n", + " newimg = similar(img, RGBA{Float64})\n", + "\n", + " # Apply transparency to the tiles\n", + " for tile_coords in get_tiles(img, side_length)\n", + " tile = @view img[tile_coords...]\n", + " alpha = rand(0.5:0.05:1)\n", + " transparent_tile = map(c -> RGBA(c.r, c.g, c.b, alpha), tile)\n", + " newimg[tile_coords...] .= transparent_tile\n", + " end\n", + "\n", + " # View the image\n", + " newimg\n", + "end\n", + "\n", + "build_tiling_illustration(img, 450)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Optimal tile side length\n", + "\n", + "Perhaps there is a better way to split the image into tiles. We can use the `get_optimal_tile_size` function to determine a better tiling given an initial tile side length." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using IceFloeTracker: get_optimal_tile_size\n", + "\n", + "@info @doc get_optimal_tile_size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "best_side_length = get_optimal_tile_size(450, size(img))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, a tile size of 450 is not optimal for this image. The function get_optimal_tile_size suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "build_tiling_illustration(img, 451)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Area of corner tile with side length 451\n", + "get_tile_dims(get_tiles(img, 451)[end]) |> prod" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the area of the corner tile for the 450-tiling is larger." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_tile_dims(get_tiles(img, 450)[end]) |> prod" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 2da24d0ad8a0a6dbef91cf6cf3eef20c9948d7ca Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 12:55:12 -0400 Subject: [PATCH 02/10] experiment: add GitHub Actions workflow to test Julia notebooks --- .github/workflows/exercise-nb.yml | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/exercise-nb.yml diff --git a/.github/workflows/exercise-nb.yml b/.github/workflows/exercise-nb.yml new file mode 100644 index 00000000..3caedc3c --- /dev/null +++ b/.github/workflows/exercise-nb.yml @@ -0,0 +1,33 @@ +name: Test Julia Notebooks + +on: [pull_request] + +jobs: + run-notebooks: + runs-on: ubuntu-latest + strategy: + matrix: + version: [1.9, 1.10, 1.11] + arch: [x64, x86] + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: update pip + run: python -m pip install -U pip + - name: install python deps + run: python -m pip install -U -r requirements.txt + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 + env: + PYTHON: python + - name: Run Jupyter Notebooks + uses: yaananth/run-notebook@v2 + with: + notebook: 'notebooks/preprocessing-workflow/tiling.ipynb' \ No newline at end of file From 67d20a27bd2261bbbb8d76ca971d214a6b97ead6 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 13:28:07 -0400 Subject: [PATCH 03/10] ci: update GitHub Actions workflow to test only Julia version 1.10 --- .github/workflows/exercise-nb.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/exercise-nb.yml b/.github/workflows/exercise-nb.yml index 3caedc3c..b192fa9d 100644 --- a/.github/workflows/exercise-nb.yml +++ b/.github/workflows/exercise-nb.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - version: [1.9, 1.10, 1.11] + version: [1.10] arch: [x64, x86] steps: From 559a97e257a2d5dbc38e21fa0359c604c760d4e9 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 13:32:26 -0400 Subject: [PATCH 04/10] Revert "docs: add nb for image tiling workflow" This reverts commit 6b6ac0ceb705d3c63293ad78c7c6787af057c3a2. --- notebooks/preprocessing-workflow/tiling.ipynb | 229 ------------------ 1 file changed, 229 deletions(-) delete mode 100644 notebooks/preprocessing-workflow/tiling.ipynb diff --git a/notebooks/preprocessing-workflow/tiling.ipynb b/notebooks/preprocessing-workflow/tiling.ipynb deleted file mode 100644 index 139bd9ed..00000000 --- a/notebooks/preprocessing-workflow/tiling.ipynb +++ /dev/null @@ -1,229 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "HOME = \"../..\" # path to the root of the project two levels up\n", - "\n", - "# Activate the environment\n", - "using Pkg\n", - "Pkg.activate(HOME)\n", - "Pkg.precompile()\n", - "\n", - "using IceFloeTracker: get_tiles, get_tile_dims, load\n", - "using ColorTypes: RGBA" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "img = load(\"bering_strait/truecolor/20200504.aqua.truecolor.250m.tiff\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Say we want to split the image into roughly 8x8 tiles\n", - "size(img) .÷ 8" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tile size\n", - "Let us choose tiles of size 450x450. To do that use the `get_tiles` function." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Let's view the documentation for the function\n", - "@info @doc get_tiles" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tiles = get_tiles(img, 450)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Top left tile dimensions\n", - "get_tile_dims(tiles[1])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Bottom right tile dimensions\n", - "get_tile_dims(tiles[end])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the bottom right tile has been extended to cover the rest of the image." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# View the first tile\n", - "img[tiles[1]...]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Further, note that the tiles on the right and bottom edges are slightly bigger." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### View the full tiling" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "function build_tiling_illustration(img, side_length)\n", - "\n", - " # Create new canvas to draw on\n", - " newimg = similar(img, RGBA{Float64})\n", - "\n", - " # Apply transparency to the tiles\n", - " for tile_coords in get_tiles(img, side_length)\n", - " tile = @view img[tile_coords...]\n", - " alpha = rand(0.5:0.05:1)\n", - " transparent_tile = map(c -> RGBA(c.r, c.g, c.b, alpha), tile)\n", - " newimg[tile_coords...] .= transparent_tile\n", - " end\n", - "\n", - " # View the image\n", - " newimg\n", - "end\n", - "\n", - "build_tiling_illustration(img, 450)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Optimal tile side length\n", - "\n", - "Perhaps there is a better way to split the image into tiles. We can use the `get_optimal_tile_size` function to determine a better tiling given an initial tile side length." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "using IceFloeTracker: get_optimal_tile_size\n", - "\n", - "@info @doc get_optimal_tile_size" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "best_side_length = get_optimal_tile_size(450, size(img))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, a tile size of 450 is not optimal for this image. The function get_optimal_tile_size suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "build_tiling_illustration(img, 451)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Area of corner tile with side length 451\n", - "get_tile_dims(get_tiles(img, 451)[end]) |> prod" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the area of the corner tile for the 450-tiling is larger." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "get_tile_dims(get_tiles(img, 450)[end]) |> prod" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.9.3", - "language": "julia", - "name": "julia-1.9" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 05c64d84ec1c4146db62349e7cf0ef890e3b03f1 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 13:38:49 -0400 Subject: [PATCH 05/10] docs: add nb for image tiling workflow --- notebooks/preprocessing-workflow/tiling.ipynb | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 notebooks/preprocessing-workflow/tiling.ipynb diff --git a/notebooks/preprocessing-workflow/tiling.ipynb b/notebooks/preprocessing-workflow/tiling.ipynb new file mode 100644 index 00000000..139bd9ed --- /dev/null +++ b/notebooks/preprocessing-workflow/tiling.ipynb @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "HOME = \"../..\" # path to the root of the project two levels up\n", + "\n", + "# Activate the environment\n", + "using Pkg\n", + "Pkg.activate(HOME)\n", + "Pkg.precompile()\n", + "\n", + "using IceFloeTracker: get_tiles, get_tile_dims, load\n", + "using ColorTypes: RGBA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = load(\"bering_strait/truecolor/20200504.aqua.truecolor.250m.tiff\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Say we want to split the image into roughly 8x8 tiles\n", + "size(img) .÷ 8" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tile size\n", + "Let us choose tiles of size 450x450. To do that use the `get_tiles` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's view the documentation for the function\n", + "@info @doc get_tiles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tiles = get_tiles(img, 450)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Top left tile dimensions\n", + "get_tile_dims(tiles[1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Bottom right tile dimensions\n", + "get_tile_dims(tiles[end])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the bottom right tile has been extended to cover the rest of the image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# View the first tile\n", + "img[tiles[1]...]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Further, note that the tiles on the right and bottom edges are slightly bigger." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### View the full tiling" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "function build_tiling_illustration(img, side_length)\n", + "\n", + " # Create new canvas to draw on\n", + " newimg = similar(img, RGBA{Float64})\n", + "\n", + " # Apply transparency to the tiles\n", + " for tile_coords in get_tiles(img, side_length)\n", + " tile = @view img[tile_coords...]\n", + " alpha = rand(0.5:0.05:1)\n", + " transparent_tile = map(c -> RGBA(c.r, c.g, c.b, alpha), tile)\n", + " newimg[tile_coords...] .= transparent_tile\n", + " end\n", + "\n", + " # View the image\n", + " newimg\n", + "end\n", + "\n", + "build_tiling_illustration(img, 450)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Optimal tile side length\n", + "\n", + "Perhaps there is a better way to split the image into tiles. We can use the `get_optimal_tile_size` function to determine a better tiling given an initial tile side length." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using IceFloeTracker: get_optimal_tile_size\n", + "\n", + "@info @doc get_optimal_tile_size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "best_side_length = get_optimal_tile_size(450, size(img))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, a tile size of 450 is not optimal for this image. The function get_optimal_tile_size suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "build_tiling_illustration(img, 451)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Area of corner tile with side length 451\n", + "get_tile_dims(get_tiles(img, 451)[end]) |> prod" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the area of the corner tile for the 450-tiling is larger." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_tile_dims(get_tiles(img, 450)[end]) |> prod" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From bf06484de578259f04348e346c541453ec3991b1 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 26 Sep 2024 13:39:06 -0400 Subject: [PATCH 06/10] ci: remove exercise-nb workflow for testing Julia notebooks --- .github/workflows/exercise-nb.yml | 33 ------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/exercise-nb.yml diff --git a/.github/workflows/exercise-nb.yml b/.github/workflows/exercise-nb.yml deleted file mode 100644 index b192fa9d..00000000 --- a/.github/workflows/exercise-nb.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Test Julia Notebooks - -on: [pull_request] - -jobs: - run-notebooks: - runs-on: ubuntu-latest - strategy: - matrix: - version: [1.10] - arch: [x64, x86] - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: update pip - run: python -m pip install -U pip - - name: install python deps - run: python -m pip install -U -r requirements.txt - - uses: julia-actions/setup-julia@v2 - with: - version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - uses: julia-actions/cache@v2 - - uses: julia-actions/julia-buildpkg@v1 - env: - PYTHON: python - - name: Run Jupyter Notebooks - uses: yaananth/run-notebook@v2 - with: - notebook: 'notebooks/preprocessing-workflow/tiling.ipynb' \ No newline at end of file From 91206eee0a770100edd9828c5f474cedeedcbaac Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 3 Oct 2024 11:01:39 -0400 Subject: [PATCH 07/10] fix: remove unnecessary area calculation in get_optimal_tile_size function --- src/tilingutils.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tilingutils.jl b/src/tilingutils.jl index babcd993..f3221a90 100644 --- a/src/tilingutils.jl +++ b/src/tilingutils.jl @@ -24,13 +24,12 @@ function get_optimal_tile_size(l0::Int, dims::Tuple{Int,Int})::Int l0 < 2 && error("l0 must be at least 2") any(l0 .> dims) && error("l0 = $l0 is too large for the given dimensions $dims") - area = prod(dims) minimal_shift = l0 == 2 ? 0 : 1 candidates = [l0 + i for i in -minimal_shift:1] minl, M = 0, Inf for side_length in candidates - missedarea = get_area_missed(side_length, dims, area) + missedarea = get_area_missed(side_length, dims) if missedarea <= M # prefer larger side_length in case of tie M, minl = missedarea, side_length end From ffe2f4e146e4753ec07733f01f326d97231c4009 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 3 Oct 2024 11:03:37 -0400 Subject: [PATCH 08/10] feat: add new tile utility functions and enhance documentation --- src/tilingutils.jl | 82 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/tilingutils.jl b/src/tilingutils.jl index f3221a90..1df1ceff 100644 --- a/src/tilingutils.jl +++ b/src/tilingutils.jl @@ -1,18 +1,62 @@ + +""" + getfit(dims::Tuple{Int,Int}, side_length::Int)::Tuple{Int,Int} + +Calculate how many tiles of a given side length fit into the given dimensions. + +# Arguments +- `dims::Tuple{Int,Int}`: A tuple representing the dimensions (width, height). +- `side_length::Int`: The side length of the tile. + +# Returns +- `Tuple{Int,Int}`: A tuple representing the number of tiles that fit along each dimension. + +# Examples +``` +julia> getfit((10, 20), 5) +(2, 4) + +julia> getfit((15, 25), 5) +(3, 5) +""" function getfit(dims::Tuple{Int,Int}, side_length::Int)::Tuple{Int,Int} return dims .÷ side_length end -function get_area_missed(side_length::Int, dims::Tuple{Int,Int}, area::Int)::Float64 + +""" + get_area_missed(side_length::Int, dims::Tuple{Int,Int})::Float64 + +Calculate the proportion of the area that is not covered by tiles of a given side length. + +# Arguments +- `side_length::Int`: The side length of the tile. +- `dims::Tuple{Int,Int}`: A tuple representing the dimensions (width, height). + +# Returns +- `Float64`: The proportion of the area that is not covered by the tiles. + +# Examples +``` +julia> get_area_missed(5, (10, 20)) +0.0 + +julia> get_area_missed(7, (10, 20)) +0.51 +""" +function get_area_missed(side_length::Int, dims::Tuple{Int,Int})::Float64 + area = prod(dims) return 1 - prod(getfit(dims, side_length)) * side_length^2 / area end + """ get_optimal_tile_size(l0::Int, dims::Tuple{Int,Int}) -> Int Calculate the optimal tile size in the range [l0-1, l0+1] for the given size `l0` and image dimensions `dims`. # Description -This function computes the optimal tile size for tiling an area with given dimensions. It ensures that the initial tile size `l0` is at least 2 and not larger than any of the given dimensions. The function evaluates candidate tile sizes and selects the one that minimizes the area missed during tiling. In case of a tie, it prefers the larger tile size. +This function computes the optimal tile size for tiling an area with given dimensions. It ensures that the initial tile size `l0` is at least 2 and not larger than any of the given dimensions. The function evaluates candidate tile sizes and selects the one that minimizes the area missed by its corresponding tiling. In case of a tie, it prefers the larger tile size. # Example ``` @@ -58,8 +102,24 @@ function get_tile_meta(tile) return [a, b, c, d] end +""" + bump_tile(tile::Tuple{UnitRange{Int64}, UnitRange{Int64}}, dims::Tuple{Int,Int})::Tuple{UnitRange{Int}, UnitRange{Int}} + +Adjust the tile dimensions by adding extra rows and columns. + +# Arguments +- `tile::Tuple{Int,Int,Int,Int}`: A tuple representing the tile dimensions (a, b, c, d). +- `dims::Tuple{Int,Int}`: A tuple representing the extra rows and columns to add (extrarows, extracols). + +# Returns +- `Tuple{UnitRange{Int}, UnitRange{Int}}`: A tuple of ranges representing the new tile dimensions. -function bump_tile(tile, dims) +# Examples +```julia +julia> bump_tile((1:3, 1:4), (1, 1)) +(1:4, 1:5) +""" +function bump_tile(tile::Tuple{UnitRange{S},UnitRange{S}}, dims::Tuple{S,S}) where {S<:Int} extrarows, extracols = dims a, b, c, d = get_tile_meta(tile) b += extrarows @@ -67,6 +127,22 @@ function bump_tile(tile, dims) return (a:b, c:d) end +""" + get_tile_dims(tile) + +Calculate the dimensions of a tile. + +# Arguments +- `tile::Tuple{UnitRange{Int},UnitRange{Int}}`: A tuple representing the tile dimensions. + +# Returns +- `Tuple{Int,Int}`: A tuple representing the width and height of the tile. + +# Examples +```julia +julia> get_tile_dims((1:3, 1:4)) +(4, 3) +""" function get_tile_dims(tile) a, b, c, d = get_tile_meta(tile) width, height = d - c + 1, b - a + 1 From 28a33c66f96b7c84437859cf7582d508a2d6a9d3 Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Thu, 3 Oct 2024 11:11:14 -0400 Subject: [PATCH 09/10] docs: enhance tiling notebook with detailed explanations and markdown sections --- notebooks/preprocessing-workflow/tiling.ipynb | 95 +++++++++++++++---- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/notebooks/preprocessing-workflow/tiling.ipynb b/notebooks/preprocessing-workflow/tiling.ipynb index 139bd9ed..7645ce05 100644 --- a/notebooks/preprocessing-workflow/tiling.ipynb +++ b/notebooks/preprocessing-workflow/tiling.ipynb @@ -1,5 +1,24 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tiling Utilities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook contains a demo of the tiling utilities included in `IceFloeTracker.jl`. In particular, the following workflows are illustrated:\n", + "\n", + "- Getting tiling with tiles of a given size\n", + "- Getting the optimal tile size given an initial tile side length\n", + "\n", + "Run the cell below to set up the computation environment." + ] + }, { "cell_type": "code", "execution_count": null, @@ -17,6 +36,13 @@ "using ColorTypes: RGBA" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Load the image" + ] + }, { "cell_type": "code", "execution_count": null, @@ -26,13 +52,22 @@ "img = load(\"bering_strait/truecolor/20200504.aqua.truecolor.250m.tiff\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Estimate tile size\n", + "\n", + "Say we want to split the image into roughly 8x8 tiles." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "# Say we want to split the image into roughly 8x8 tiles\n", + "\n", "size(img) .÷ 8" ] }, @@ -40,8 +75,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Tile size\n", - "Let us choose tiles of size 450x450. To do that use the `get_tiles` function." + "#### Choosing tile size and building tilings\n", + "\n", + "The `get_tiles` function builds a tiling given an image (array) and a tile side length.\n", + "\n" ] }, { @@ -73,21 +110,11 @@ "get_tile_dims(tiles[1])" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Bottom right tile dimensions\n", - "get_tile_dims(tiles[end])" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the bottom right tile has been extended to cover the rest of the image." + "Note that the bottom right tile has been extended to cover the rest of the image as a uniform tiling of side length `450` fails to cover the full image." ] }, { @@ -107,6 +134,16 @@ "Further, note that the tiles on the right and bottom edges are slightly bigger." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Bottom right tile dimensions\n", + "get_tile_dims(tiles[end])" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -146,7 +183,7 @@ "source": [ "### Optimal tile side length\n", "\n", - "Perhaps there is a better way to split the image into tiles. We can use the `get_optimal_tile_size` function to determine a better tiling given an initial tile side length." + "Perhaps there is a fitter tiling that is close to the originally desired tiling. We can use the `get_optimal_tile_size` function to determine whether this is possible." ] }, { @@ -173,7 +210,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As expected, a tile size of 450 is not optimal for this image. The function get_optimal_tile_size suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." + "As expected, a tile size of 450 is not optimal for this image. The function `get_optimal_tile_size` suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." ] }, { @@ -210,6 +247,32 @@ "source": [ "get_tile_dims(get_tiles(img, 450)[end]) |> prod" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The proportion area missed by a uniform tiling can be computed with `get_area_missed`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using IceFloeTracker: get_area_missed\n", + "get_area_missed(450, size(img))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_area_missed(451, size(img))" + ] } ], "metadata": { From bafa0b296921f285b7ce4cd10d1a0bf86c6ac51b Mon Sep 17 00:00:00 2001 From: Carlos Paniagua Date: Fri, 4 Oct 2024 17:02:10 -0400 Subject: [PATCH 10/10] fix: img path also update other things --- notebooks/preprocessing-workflow/tiling.ipynb | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/notebooks/preprocessing-workflow/tiling.ipynb b/notebooks/preprocessing-workflow/tiling.ipynb index 7645ce05..c2983a1d 100644 --- a/notebooks/preprocessing-workflow/tiling.ipynb +++ b/notebooks/preprocessing-workflow/tiling.ipynb @@ -49,7 +49,8 @@ "metadata": {}, "outputs": [], "source": [ - "img = load(\"bering_strait/truecolor/20200504.aqua.truecolor.250m.tiff\")" + "imgpath = \"test/test_inputs/NE_Greenland_truecolor.2020162.aqua.250m.tiff\"\n", + "img = load(joinpath(HOME,imgpath))" ] }, { @@ -68,7 +69,7 @@ "outputs": [], "source": [ "\n", - "size(img) .÷ 8" + "prelim_sizes = size(img) .÷ 8" ] }, { @@ -97,7 +98,7 @@ "metadata": {}, "outputs": [], "source": [ - "tiles = get_tiles(img, 450)" + "tiles = get_tiles(img, prelim_sizes[1] + 1) # deliberately using a size that is too large" ] }, { @@ -114,7 +115,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the bottom right tile has been extended to cover the rest of the image as a uniform tiling of side length `450` fails to cover the full image." + "Note that the bottom right tile has been extended to cover the rest of the image as a uniform tiling of side length `prelim_sizes[1] + 1` fails to cover the full image." ] }, { @@ -174,7 +175,7 @@ " newimg\n", "end\n", "\n", - "build_tiling_illustration(img, 450)\n" + "build_tiling_illustration(img, prelim_sizes[1] + 1)\n" ] }, { @@ -203,14 +204,14 @@ "metadata": {}, "outputs": [], "source": [ - "best_side_length = get_optimal_tile_size(450, size(img))" + "best_side_length = get_optimal_tile_size(prelim_sizes[1] + 1, size(img))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "As expected, a tile size of 450 is not optimal for this image. The function `get_optimal_tile_size` suggests a fitter tiling is possible using tiles of 451 pixels in side length for this image." + "As expected, a tile size of 1016 is not optimal for this image. The function `get_optimal_tile_size` suggests a fitter tiling is possible using tiles of 1015 pixels in side length for this image." ] }, { @@ -219,7 +220,7 @@ "metadata": {}, "outputs": [], "source": [ - "build_tiling_illustration(img, 451)" + "build_tiling_illustration(img, best_side_length)" ] }, { @@ -228,15 +229,15 @@ "metadata": {}, "outputs": [], "source": [ - "# Area of corner tile with side length 451\n", - "get_tile_dims(get_tiles(img, 451)[end]) |> prod" + "# Area of corner tile with optimal side length\n", + "get_tile_dims(get_tiles(img, best_side_length)[end]) |> prod" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the area of the corner tile for the 450-tiling is larger." + "Note that the area of the corner tile for the suboptimal tiling is larger." ] }, { @@ -245,14 +246,14 @@ "metadata": {}, "outputs": [], "source": [ - "get_tile_dims(get_tiles(img, 450)[end]) |> prod" + "get_tile_dims(get_tiles(img, prelim_sizes[1] + 1)[end]) |> prod" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The proportion area missed by a uniform tiling can be computed with `get_area_missed`." + "The proportion of pixels missed by a uniform tiling can be computed with `get_area_missed`." ] }, { @@ -262,16 +263,9 @@ "outputs": [], "source": [ "using IceFloeTracker: get_area_missed\n", - "get_area_missed(450, size(img))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "get_area_missed(451, size(img))" + "areamissed_optimal = get_area_missed(best_side_length, size(img))\n", + "@show areamissed_optimal\n", + "@assert get_area_missed(prelim_sizes[1] + 1, size(img)) > get_area_missed(best_side_length, size(img))" ] } ],