mergechannels 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mergechannels might be problematic. Click here for more details.
- {mergechannels-0.1.2 → mergechannels-0.2.0}/Cargo.lock +8 -1
- {mergechannels-0.1.2 → mergechannels-0.2.0}/Cargo.toml +2 -1
- {mergechannels-0.1.2 → mergechannels-0.2.0}/PKG-INFO +52 -22
- {mergechannels-0.1.2 → mergechannels-0.2.0}/README.md +48 -21
- {mergechannels-0.1.2 → mergechannels-0.2.0}/pyproject.toml +7 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/pytests/test_colorize.py +50 -10
- {mergechannels-0.1.2 → mergechannels-0.2.0}/python/mergechannels/__init__.py +5 -5
- mergechannels-0.2.0/python/mergechannels/__init__.pyi +30 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/python/mergechannels/_internal.py +25 -7
- {mergechannels-0.1.2 → mergechannels-0.2.0}/src/blend.rs +43 -8
- mergechannels-0.2.0/src/colorize.rs +397 -0
- mergechannels-0.2.0/src/interface.rs +239 -0
- mergechannels-0.2.0/src/lib.rs +15 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/uv.lock +217 -2
- mergechannels-0.1.2/python/mergechannels/__init__.pyi +0 -27
- mergechannels-0.1.2/src/colorize.rs +0 -64
- mergechannels-0.1.2/src/interface.rs +0 -36
- mergechannels-0.1.2/src/lib.rs +0 -15
- {mergechannels-0.1.2 → mergechannels-0.2.0}/.gitattributes +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/.github/workflows/CI.yml +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/.gitignore +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/.pre-commit-config.yaml +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/LICENSE +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/16_colors.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/5_ramps.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/6_shades.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Cyan Hot.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Green Fire Blue.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/HiLo.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/ICA.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/ICA2.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/ICA3.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Magenta Hot.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Orange Hot.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Rainbow RGB.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Red Hot.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Thermal.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/Yellow Hot.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/blue_orange_icb.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/brgbcmyw.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/cool.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/edges.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/gem.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/glasbey.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/glasbey_inverted.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/glasbey_on_dark.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/glow.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/mpl-inferno.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/mpl-magma.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/mpl-plasma.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/mpl-viridis.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/phase.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/physics.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/royal.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/sepia.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/smart.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/thal.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/thallium.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/builtin_luts/unionjack.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/3color-BMR.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/3color-CGY.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/3color-RMB.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/3color-YGC.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/BOP blue.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/BOP orange.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/BOP purple.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Blue.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Bordeaux.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Cyan.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Forest.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Green.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Magenta.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Purple.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Red.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/I Yellow.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/NOTICE +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/OPF fresh.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/OPF orange.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/OPF purple.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/christ_luts/Turbo.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/16_colors.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/3-3-2 RGB.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/3color-BMR.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/3color-CGY.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/3color-RMB.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/3color-YGC.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/5_ramps.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/6_shades.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/BOP blue.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/BOP orange.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/BOP purple.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Blue.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Cyan Hot.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Cyan.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Fire.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Grays.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Green Fire Blue.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Green.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/HiLo.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Blue.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Bordeaux.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Cyan.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Forest.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Green.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Magenta.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Purple.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Red.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/I Yellow.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/ICA.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/ICA2.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/ICA3.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Ice.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Magenta Hot.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Magenta.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OIMB1.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OIMB2.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OIMB3.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OPF fresh.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OPF orange.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/OPF purple.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Orange Hot.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Rainbow RGB.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Red Hot.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Red%Green.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Red.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Spectrum.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Thermal.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Turbo.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Yellow Hot.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/Yellow.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterBlue.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterCyan.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterGreen.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterOrange.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterRed.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/betterYellow.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/blue_orange_icb.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/brgbcmyw.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/cool.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/edges.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/gem.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/glasbey.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/glasbey_inverted.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/glasbey_on_dark.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/glow.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/mpl-inferno.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/mpl-magma.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/mpl-plasma.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/mpl-viridis.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/phase.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/physics.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/royal.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/sepia.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/smart.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/thal.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/thallium.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/converted/unionjack.txt +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/OIMB1.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/OIMB2.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/OIMB3.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterBlue.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterCyan.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterGreen.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterOrange.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterRed.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/assets/zac_luts/betterYellow.lut +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/python/mergechannels/_blending.py +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/python/mergechannels/_luts.py +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/python/mergechannels/py.typed +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/ruff.toml +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/scripts/convert_luts_to_txt.ijm +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/scripts/populate_luts.py +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/src/cmaps.rs +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/src/normalize.rs +0 -0
- {mergechannels-0.1.2 → mergechannels-0.2.0}/tox.ini +0 -0
|
@@ -59,12 +59,13 @@ dependencies = [
|
|
|
59
59
|
|
|
60
60
|
[[package]]
|
|
61
61
|
name = "mergechannels"
|
|
62
|
-
version = "0.
|
|
62
|
+
version = "0.2.0"
|
|
63
63
|
dependencies = [
|
|
64
64
|
"lazy_static",
|
|
65
65
|
"ndarray",
|
|
66
66
|
"numpy",
|
|
67
67
|
"pyo3",
|
|
68
|
+
"smallvec",
|
|
68
69
|
]
|
|
69
70
|
|
|
70
71
|
[[package]]
|
|
@@ -239,6 +240,12 @@ version = "2.1.1"
|
|
|
239
240
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
240
241
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|
241
242
|
|
|
243
|
+
[[package]]
|
|
244
|
+
name = "smallvec"
|
|
245
|
+
version = "1.15.0"
|
|
246
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
247
|
+
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
|
248
|
+
|
|
242
249
|
[[package]]
|
|
243
250
|
name = "syn"
|
|
244
251
|
version = "2.0.98"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "mergechannels"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
@@ -13,3 +13,4 @@ lazy_static = "1.5.0"
|
|
|
13
13
|
ndarray = "0.16.1"
|
|
14
14
|
numpy = "0.24.0"
|
|
15
15
|
pyo3 = "0.24.1"
|
|
16
|
+
smallvec = "1.15.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mergechannels
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -12,7 +12,10 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Requires-Dist: numpy>1.25.0
|
|
15
|
+
Provides-Extra: nvim
|
|
15
16
|
License-File: LICENSE
|
|
17
|
+
Summary: Apply and merge colormaps
|
|
18
|
+
Author-email: Zac Swider <zac.swider@gmail.com>
|
|
16
19
|
License: MIT
|
|
17
20
|
Requires-Python: >=3.9, <=3.13
|
|
18
21
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
@@ -60,8 +63,7 @@ plt.show()
|
|
|
60
63
|
print(colorized.shape, colorized.dtype)
|
|
61
64
|
>> (512, 512, 3) uint8
|
|
62
65
|
```
|
|
63
|
-

|
|
66
|
+

|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
### apply a different colormap to each channel
|
|
@@ -71,38 +73,66 @@ import matplotlib.pyplot as plt
|
|
|
71
73
|
import mergechannels as mc
|
|
72
74
|
|
|
73
75
|
cells, nuclei = data.cells3d().max(axis=0)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
assert cells.dtype == 'uint16' and nuclei.dtype == 'uint16'
|
|
77
|
+
fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
|
|
78
|
+
for ax in axes.ravel(): ax.axis('off')
|
|
79
|
+
(a, b) = axes.ravel()
|
|
80
|
+
a.imshow(mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot']))
|
|
81
|
+
b.imshow(mc.merge([cells, nuclei],['I Blue', 'I Forest'], blending='min'))
|
|
82
|
+
fig.tight_layout()
|
|
83
|
+
plt.show()
|
|
84
|
+
```
|
|
85
|
+

|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
### apply a colormap to a whole stack
|
|
88
|
+
```python
|
|
89
|
+
from skimage import data
|
|
90
|
+
from matplotlib import pyplot as plt
|
|
91
|
+
import mergechannels as mc
|
|
92
|
+
|
|
93
|
+
volume = data.cells3d()
|
|
94
|
+
cells = volume[:, 0]
|
|
95
|
+
nuclei = volume[:, 1]
|
|
96
|
+
merged = mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot'])
|
|
97
|
+
plt.imshow(merged[24]); plt.show()
|
|
98
|
+
```
|
|
99
|
+

|
|
100
|
+
|
|
101
|
+
### adjust the saturation limits when applying colormaps
|
|
102
|
+
``` python
|
|
103
|
+
from skimage import data
|
|
104
|
+
import matplotlib.pyplot as plt
|
|
105
|
+
import mergechannels as mc
|
|
106
|
+
|
|
107
|
+
cells, nuclei = data.cells3d().max(axis=0)
|
|
108
|
+
channels = [cells, nuclei]
|
|
109
|
+
colormaps = ['I Blue', 'I Forest']
|
|
110
|
+
fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
|
|
78
111
|
for ax in axes.ravel(): ax.axis('off')
|
|
79
|
-
(a, b
|
|
80
|
-
a.imshow(
|
|
81
|
-
b.imshow(
|
|
82
|
-
c.imshow(
|
|
83
|
-
mc.merge(
|
|
84
|
-
[cells, nuclei],
|
|
85
|
-
['Orange Hot', 'Cyan Hot'], # maximum blending is the default
|
|
86
|
-
),
|
|
87
|
-
)
|
|
88
|
-
d.imshow(
|
|
112
|
+
(a, b) = axes.ravel()
|
|
113
|
+
a.imshow(mc.merge(channels, colormaps, blending='min'))
|
|
114
|
+
b.imshow(
|
|
89
115
|
mc.merge(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
blending='min',
|
|
116
|
+
channels,
|
|
117
|
+
colormaps,
|
|
118
|
+
blending='min',
|
|
119
|
+
saturation_limits=(
|
|
120
|
+
0.01, # bottom 1% of pixels set to black point
|
|
121
|
+
0.97, # top 3% of pixels set to white point
|
|
122
|
+
),
|
|
93
123
|
),
|
|
94
124
|
)
|
|
95
125
|
fig.tight_layout()
|
|
96
126
|
plt.show()
|
|
97
127
|
```
|
|
98
|
-

|
|
99
129
|
|
|
100
130
|
|
|
101
131
|
## Roadmap
|
|
102
|
-
mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D 8-bit images and that's it.
|
|
132
|
+
mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D and 3D 8-bit or 16-bit images and that's it.
|
|
103
133
|
- Add support for any numerical dtype
|
|
104
|
-
- Add support for 3D images
|
|
105
134
|
- Add option to return any colormap as a matplotlib colormap
|
|
135
|
+
- Add option to pass external colormaps to mergechannels
|
|
106
136
|
- Add support for directly passing matplotlib colormaps instead of colormap names
|
|
107
137
|
- Parallelize colormap application on large images (if it's helpful)
|
|
108
138
|
- Add option to overlay binary or instance masks onto colorized images
|
|
@@ -41,8 +41,7 @@ plt.show()
|
|
|
41
41
|
print(colorized.shape, colorized.dtype)
|
|
42
42
|
>> (512, 512, 3) uint8
|
|
43
43
|
```
|
|
44
|
-

|
|
44
|
+

|
|
46
45
|
|
|
47
46
|
|
|
48
47
|
### apply a different colormap to each channel
|
|
@@ -52,38 +51,66 @@ import matplotlib.pyplot as plt
|
|
|
52
51
|
import mergechannels as mc
|
|
53
52
|
|
|
54
53
|
cells, nuclei = data.cells3d().max(axis=0)
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
assert cells.dtype == 'uint16' and nuclei.dtype == 'uint16'
|
|
55
|
+
fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
|
|
56
|
+
for ax in axes.ravel(): ax.axis('off')
|
|
57
|
+
(a, b) = axes.ravel()
|
|
58
|
+
a.imshow(mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot']))
|
|
59
|
+
b.imshow(mc.merge([cells, nuclei],['I Blue', 'I Forest'], blending='min'))
|
|
60
|
+
fig.tight_layout()
|
|
61
|
+
plt.show()
|
|
62
|
+
```
|
|
63
|
+

|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
### apply a colormap to a whole stack
|
|
66
|
+
```python
|
|
67
|
+
from skimage import data
|
|
68
|
+
from matplotlib import pyplot as plt
|
|
69
|
+
import mergechannels as mc
|
|
70
|
+
|
|
71
|
+
volume = data.cells3d()
|
|
72
|
+
cells = volume[:, 0]
|
|
73
|
+
nuclei = volume[:, 1]
|
|
74
|
+
merged = mc.merge([cells, nuclei],['Orange Hot', 'Cyan Hot'])
|
|
75
|
+
plt.imshow(merged[24]); plt.show()
|
|
76
|
+
```
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
### adjust the saturation limits when applying colormaps
|
|
80
|
+
``` python
|
|
81
|
+
from skimage import data
|
|
82
|
+
import matplotlib.pyplot as plt
|
|
83
|
+
import mergechannels as mc
|
|
84
|
+
|
|
85
|
+
cells, nuclei = data.cells3d().max(axis=0)
|
|
86
|
+
channels = [cells, nuclei]
|
|
87
|
+
colormaps = ['I Blue', 'I Forest']
|
|
88
|
+
fig, axes = plt.subplots(1, 2, figsize=(3, 6), dpi=300)
|
|
59
89
|
for ax in axes.ravel(): ax.axis('off')
|
|
60
|
-
(a, b
|
|
61
|
-
a.imshow(
|
|
62
|
-
b.imshow(
|
|
63
|
-
c.imshow(
|
|
64
|
-
mc.merge(
|
|
65
|
-
[cells, nuclei],
|
|
66
|
-
['Orange Hot', 'Cyan Hot'], # maximum blending is the default
|
|
67
|
-
),
|
|
68
|
-
)
|
|
69
|
-
d.imshow(
|
|
90
|
+
(a, b) = axes.ravel()
|
|
91
|
+
a.imshow(mc.merge(channels, colormaps, blending='min'))
|
|
92
|
+
b.imshow(
|
|
70
93
|
mc.merge(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
blending='min',
|
|
94
|
+
channels,
|
|
95
|
+
colormaps,
|
|
96
|
+
blending='min',
|
|
97
|
+
saturation_limits=(
|
|
98
|
+
0.01, # bottom 1% of pixels set to black point
|
|
99
|
+
0.97, # top 3% of pixels set to white point
|
|
100
|
+
),
|
|
74
101
|
),
|
|
75
102
|
)
|
|
76
103
|
fig.tight_layout()
|
|
77
104
|
plt.show()
|
|
78
105
|
```
|
|
79
|
-

|
|
80
107
|
|
|
81
108
|
|
|
82
109
|
## Roadmap
|
|
83
|
-
mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D 8-bit images and that's it.
|
|
110
|
+
mergechannels is currently incredibly simple. It can apply one or more colormaps to one or more 2D and 3D 8-bit or 16-bit images and that's it.
|
|
84
111
|
- Add support for any numerical dtype
|
|
85
|
-
- Add support for 3D images
|
|
86
112
|
- Add option to return any colormap as a matplotlib colormap
|
|
113
|
+
- Add option to pass external colormaps to mergechannels
|
|
87
114
|
- Add support for directly passing matplotlib colormaps instead of colormap names
|
|
88
115
|
- Parallelize colormap application on large images (if it's helpful)
|
|
89
116
|
- Add option to overlay binary or instance masks onto colorized images
|
|
@@ -4,6 +4,9 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mergechannels"
|
|
7
|
+
description = "Apply and merge colormaps"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
authors = [{ name = "Zac Swider", email = "zac.swider@gmail.com" }]
|
|
7
10
|
license = { text = "MIT" }
|
|
8
11
|
requires-python = ">=3.9, <=3.13"
|
|
9
12
|
classifiers = [
|
|
@@ -20,6 +23,9 @@ classifiers = [
|
|
|
20
23
|
]
|
|
21
24
|
dynamic = ["version"]
|
|
22
25
|
dependencies = ["numpy>1.25.0"]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
nvim = []
|
|
23
29
|
[tool.maturin]
|
|
24
30
|
features = ["pyo3/extension-module"]
|
|
25
31
|
python-source = "python"
|
|
@@ -28,6 +34,7 @@ python-source = "python"
|
|
|
28
34
|
dev = [
|
|
29
35
|
"matplotlib>=3.7.5",
|
|
30
36
|
"pre-commit>=3.5.0",
|
|
37
|
+
"pynvim>=0.5.2",
|
|
31
38
|
"pytest-benchmark>=4.0.0",
|
|
32
39
|
"pytest>=8.3.5",
|
|
33
40
|
]
|
|
@@ -7,7 +7,7 @@ def test_apply_color_map():
|
|
|
7
7
|
Test that the color map is applied correctly
|
|
8
8
|
'''
|
|
9
9
|
x = np.ones((1, 1), dtype=np.uint8)
|
|
10
|
-
rgb = mc.
|
|
10
|
+
rgb = mc.dispatch_single_channel(x, 'betterBlue', (0, 255))
|
|
11
11
|
assert rgb.shape == (1,1,3)
|
|
12
12
|
assert rgb.dtype == np.uint8
|
|
13
13
|
assert np.allclose(
|
|
@@ -17,7 +17,7 @@ def test_apply_color_map():
|
|
|
17
17
|
)
|
|
18
18
|
)
|
|
19
19
|
x = np.ones((1, 1), dtype=np.uint8) * 255
|
|
20
|
-
rgb = mc.
|
|
20
|
+
rgb = mc.dispatch_single_channel(x, 'betterBlue', (0, 255))
|
|
21
21
|
assert np.allclose(
|
|
22
22
|
rgb,
|
|
23
23
|
np.array(
|
|
@@ -31,7 +31,12 @@ def test_apply_colors_and_merge_low_sum():
|
|
|
31
31
|
'''
|
|
32
32
|
x = np.ones((1, 1), dtype=np.uint8)
|
|
33
33
|
y = np.ones((1, 1), dtype=np.uint8)
|
|
34
|
-
rgb_sum = mc.
|
|
34
|
+
rgb_sum = mc.dispatch_multi_channel(
|
|
35
|
+
[x, y],
|
|
36
|
+
['betterBlue', 'betterOrange'],
|
|
37
|
+
'sum',
|
|
38
|
+
[(0, 255), (0, 255)],
|
|
39
|
+
)
|
|
35
40
|
# blue = [0, 1, 2,]
|
|
36
41
|
# orange = [1, 1, 0]
|
|
37
42
|
assert np.allclose(
|
|
@@ -47,7 +52,12 @@ def test_apply_colors_and_merge_high_sum():
|
|
|
47
52
|
'''
|
|
48
53
|
x = np.ones((1, 1), dtype=np.uint8) * 255
|
|
49
54
|
y = np.ones((1, 1), dtype=np.uint8) * 255
|
|
50
|
-
rgb_sum = mc.
|
|
55
|
+
rgb_sum = mc.dispatch_multi_channel(
|
|
56
|
+
[x, y],
|
|
57
|
+
['betterBlue', 'betterOrange'],
|
|
58
|
+
'sum',
|
|
59
|
+
[(0, 255), (0, 255)],
|
|
60
|
+
)
|
|
51
61
|
# blue = [0, 188, 254]
|
|
52
62
|
# orange = [255, 149, 0]
|
|
53
63
|
assert np.allclose(
|
|
@@ -63,7 +73,12 @@ def test_apply_colors_and_merge_low_max():
|
|
|
63
73
|
'''
|
|
64
74
|
x = np.ones((1, 1), dtype=np.uint8)
|
|
65
75
|
y = np.ones((1, 1), dtype=np.uint8)
|
|
66
|
-
rgb_max = mc.
|
|
76
|
+
rgb_max = mc.dispatch_multi_channel(
|
|
77
|
+
[x, y],
|
|
78
|
+
['betterBlue', 'betterOrange'],
|
|
79
|
+
'max',
|
|
80
|
+
[(0, 255), (0, 255)],
|
|
81
|
+
)
|
|
67
82
|
# blue = [0, 1, 2,]
|
|
68
83
|
# orange = [1, 1, 0]
|
|
69
84
|
assert np.allclose(
|
|
@@ -79,7 +94,12 @@ def test_apply_colors_and_merge_high_max():
|
|
|
79
94
|
'''
|
|
80
95
|
x = np.ones((1, 1), dtype=np.uint8) * 255
|
|
81
96
|
y = np.ones((1, 1), dtype=np.uint8) * 255
|
|
82
|
-
rgb_max = mc.
|
|
97
|
+
rgb_max = mc.dispatch_multi_channel(
|
|
98
|
+
[x, y],
|
|
99
|
+
['betterBlue', 'betterOrange'],
|
|
100
|
+
'max',
|
|
101
|
+
[(0, 255), (0, 255)],
|
|
102
|
+
)
|
|
83
103
|
# blue = [0, 188, 254]
|
|
84
104
|
# orange = [255, 149, 0]
|
|
85
105
|
assert np.allclose(
|
|
@@ -95,7 +115,12 @@ def test_apply_colors_and_merge_low_min():
|
|
|
95
115
|
'''
|
|
96
116
|
x = np.ones((1, 1), dtype=np.uint8)
|
|
97
117
|
y = np.ones((1, 1), dtype=np.uint8)
|
|
98
|
-
rgb_min = mc.
|
|
118
|
+
rgb_min = mc.dispatch_multi_channel(
|
|
119
|
+
[x, y],
|
|
120
|
+
['betterBlue', 'betterOrange'],
|
|
121
|
+
'min',
|
|
122
|
+
[(0, 255), (0, 255)],
|
|
123
|
+
)
|
|
99
124
|
# blue = [0, 1, 2,]
|
|
100
125
|
# orange = [1, 1, 0]
|
|
101
126
|
assert np.allclose(
|
|
@@ -111,7 +136,12 @@ def test_apply_colors_and_merge_high_min():
|
|
|
111
136
|
'''
|
|
112
137
|
x = np.ones((1, 1), dtype=np.uint8) * 255
|
|
113
138
|
y = np.ones((1, 1), dtype=np.uint8) * 255
|
|
114
|
-
rgb_min = mc.
|
|
139
|
+
rgb_min = mc.dispatch_multi_channel(
|
|
140
|
+
[x, y],
|
|
141
|
+
['betterBlue', 'betterOrange'],
|
|
142
|
+
'min',
|
|
143
|
+
[(0, 255), (0, 255)],
|
|
144
|
+
)
|
|
115
145
|
# blue = [0, 188, 254]
|
|
116
146
|
# orange = [255, 149, 0]
|
|
117
147
|
assert np.allclose(
|
|
@@ -127,7 +157,12 @@ def test_apply_colors_and_merge_low_mean():
|
|
|
127
157
|
'''
|
|
128
158
|
x = np.ones((1, 1), dtype=np.uint8)
|
|
129
159
|
y = np.ones((1, 1), dtype=np.uint8)
|
|
130
|
-
rgb_mean = mc.
|
|
160
|
+
rgb_mean = mc.dispatch_multi_channel(
|
|
161
|
+
[x, y],
|
|
162
|
+
['betterBlue', 'betterOrange'],
|
|
163
|
+
'mean',
|
|
164
|
+
[(0, 255), (0, 255)],
|
|
165
|
+
)
|
|
131
166
|
# blue = [0, 1, 2,]
|
|
132
167
|
# orange = [1, 1, 0]
|
|
133
168
|
assert np.allclose(
|
|
@@ -145,7 +180,12 @@ def test_apply_colors_and_merge_high_mean():
|
|
|
145
180
|
'''
|
|
146
181
|
x = np.ones((1, 1), dtype=np.uint8) * 255
|
|
147
182
|
y = np.ones((1, 1), dtype=np.uint8) * 255
|
|
148
|
-
rgb_mean = mc.
|
|
183
|
+
rgb_mean = mc.dispatch_multi_channel(
|
|
184
|
+
[x, y],
|
|
185
|
+
['betterBlue', 'betterOrange'],
|
|
186
|
+
'mean',
|
|
187
|
+
[(0, 255), (0, 255)]
|
|
188
|
+
)
|
|
149
189
|
# blue = [0, 188, 254]
|
|
150
190
|
# orange = [255, 149, 0]
|
|
151
191
|
assert np.allclose(
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Import Rust functions
|
|
2
2
|
from .mergechannels import ( # type: ignore
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
dispatch_single_channel,
|
|
4
|
+
dispatch_multi_channel,
|
|
5
5
|
)
|
|
6
|
-
|
|
7
6
|
from ._internal import merge
|
|
8
7
|
|
|
8
|
+
|
|
9
9
|
__all__ = [
|
|
10
|
-
'
|
|
11
|
-
'
|
|
10
|
+
'dispatch_single_channel',
|
|
11
|
+
'dispatch_multi_channel',
|
|
12
12
|
'merge',
|
|
13
13
|
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Literal, Sequence
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from python.mergechannels._blending import BLENDING_OPTIONS
|
|
6
|
+
from python.mergechannels._luts import COLORMAPS
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def merge(
|
|
10
|
+
arrs: np.ndarray | Sequence[np.ndarray],
|
|
11
|
+
colors: Sequence[COLORMAPS] = (),
|
|
12
|
+
blending: Literal[BLENDING_OPTIONS] = 'max',
|
|
13
|
+
saturation_limits: tuple[float, float] = (0.2, 99.8),
|
|
14
|
+
) -> np.ndarray:
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
def dispatch_single_channel(
|
|
18
|
+
array_reference: np.ndarray,
|
|
19
|
+
cmap_name: str,
|
|
20
|
+
limits: tuple[float, float],
|
|
21
|
+
) -> np.ndarray:
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
def dispatch_multi_channel(
|
|
25
|
+
array_references: Sequence[np.ndarray],
|
|
26
|
+
cmap_names: Sequence[str],
|
|
27
|
+
blending: Literal[BLENDING_OPTIONS],
|
|
28
|
+
limits: Sequence[tuple[float, float]],
|
|
29
|
+
) -> np.ndarray:
|
|
30
|
+
...
|
|
@@ -3,8 +3,8 @@ from typing import Sequence
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
5
|
from mergechannels import (
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
dispatch_single_channel,
|
|
7
|
+
dispatch_multi_channel,
|
|
8
8
|
)
|
|
9
9
|
from ._luts import COLORMAPS
|
|
10
10
|
from ._blending import BLENDING_OPTIONS
|
|
@@ -13,6 +13,7 @@ def merge(
|
|
|
13
13
|
arrs: Sequence[np.ndarray],
|
|
14
14
|
colors: Sequence[COLORMAPS],
|
|
15
15
|
blending: BLENDING_OPTIONS = 'max',
|
|
16
|
+
saturation_limits: tuple[float, float] = (0.011, 0.999),
|
|
16
17
|
) -> np.ndarray:
|
|
17
18
|
'''
|
|
18
19
|
apply cmaps to arrays and blend the colors
|
|
@@ -30,9 +31,9 @@ def merge(
|
|
|
30
31
|
raise ValueError(
|
|
31
32
|
f'Expected every array to have the same shape, got {arr_shapes}'
|
|
32
33
|
)
|
|
33
|
-
if
|
|
34
|
+
if len(arr_shapes[0]) not in (2, 3):
|
|
34
35
|
raise ValueError(
|
|
35
|
-
f'Expected every array to be 2D, got {arr_shapes[0]}'
|
|
36
|
+
f'Expected every array to be 2D or 3D, got {arr_shapes[0]}'
|
|
36
37
|
)
|
|
37
38
|
arr_dtypes = [arr.dtype for arr in arrs]
|
|
38
39
|
if not len(set(arr_dtypes)) == 1:
|
|
@@ -40,8 +41,25 @@ def merge(
|
|
|
40
41
|
f'Expected every array to have the same dtype, got {arr_dtypes}'
|
|
41
42
|
)
|
|
42
43
|
# endregion
|
|
43
|
-
|
|
44
44
|
if n_arrs == 1:
|
|
45
|
-
|
|
45
|
+
if arrs[0].dtype == 'uint8':
|
|
46
|
+
limits = (0, 255)
|
|
47
|
+
else:
|
|
48
|
+
low, high = np.percentile(arrs[0], np.array(saturation_limits) * 100)
|
|
49
|
+
limits = (low, high)
|
|
50
|
+
return dispatch_single_channel(
|
|
51
|
+
array_reference=arrs[0],
|
|
52
|
+
cmap_name=colors[0],
|
|
53
|
+
limits=limits,
|
|
54
|
+
)
|
|
46
55
|
else:
|
|
47
|
-
|
|
56
|
+
if all(arr.dtype == 'uint8' for arr in arrs):
|
|
57
|
+
limits = (0, 255)
|
|
58
|
+
else:
|
|
59
|
+
limits = tuple(np.percentile(arr, np.array(saturation_limits) * 100) for arr in arrs)
|
|
60
|
+
return dispatch_multi_channel(
|
|
61
|
+
array_references=arrs,
|
|
62
|
+
cmap_names=colors,
|
|
63
|
+
blending=blending,
|
|
64
|
+
limits=limits, # type: ignore
|
|
65
|
+
)
|
|
@@ -1,4 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
use smallvec::SmallVec;
|
|
2
|
+
use std::error::Error;
|
|
3
|
+
use std::fmt;
|
|
4
|
+
|
|
5
|
+
pub const MAX_N_CH: usize = 5;
|
|
6
|
+
|
|
7
|
+
pub type BlendFn = fn(&SmallVec<[[u8; 3]; 5]>) -> [u8; 3];
|
|
8
|
+
|
|
9
|
+
#[derive(Debug)]
|
|
10
|
+
pub enum MergeError {
|
|
11
|
+
InvalidBlendingMode(String),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl fmt::Display for MergeError {
|
|
15
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
16
|
+
match self {
|
|
17
|
+
MergeError::InvalidBlendingMode(mode) => {
|
|
18
|
+
write!(
|
|
19
|
+
f,
|
|
20
|
+
"Invalid blending mode: `{}`. Valid modes are 'max', 'sum', 'min', and 'mean'.",
|
|
21
|
+
mode
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
impl Error for MergeError {}
|
|
29
|
+
|
|
30
|
+
pub fn max_blending(px_vals: &SmallVec<[[u8; 3]; 5]>) -> [u8; 3] {
|
|
2
31
|
let mut r: u8 = 0;
|
|
3
32
|
let mut g: u8 = 0;
|
|
4
33
|
let mut b: u8 = 0;
|
|
@@ -16,7 +45,7 @@ pub fn max_blending(px_vals: &Vec<[u8; 3]>) -> [u8; 3] {
|
|
|
16
45
|
[r, g, b]
|
|
17
46
|
}
|
|
18
47
|
|
|
19
|
-
pub fn sum_blending(px_vals: &
|
|
48
|
+
pub fn sum_blending(px_vals: &SmallVec<[[u8; 3]; 5]>) -> [u8; 3] {
|
|
20
49
|
let mut r: u8 = 0;
|
|
21
50
|
let mut g: u8 = 0;
|
|
22
51
|
let mut b: u8 = 0;
|
|
@@ -28,7 +57,7 @@ pub fn sum_blending(px_vals: &Vec<[u8; 3]>) -> [u8; 3] {
|
|
|
28
57
|
[r, g, b]
|
|
29
58
|
}
|
|
30
59
|
|
|
31
|
-
pub fn min_blending(px_vals: &
|
|
60
|
+
pub fn min_blending(px_vals: &SmallVec<[[u8; 3]; 5]>) -> [u8; 3] {
|
|
32
61
|
let mut r: u8 = 255;
|
|
33
62
|
let mut g: u8 = 255;
|
|
34
63
|
let mut b: u8 = 255;
|
|
@@ -46,7 +75,7 @@ pub fn min_blending(px_vals: &Vec<[u8; 3]>) -> [u8; 3] {
|
|
|
46
75
|
[r, g, b]
|
|
47
76
|
}
|
|
48
77
|
|
|
49
|
-
pub fn mean_blending(px_vals: &
|
|
78
|
+
pub fn mean_blending(px_vals: &SmallVec<[[u8; 3]; 5]>) -> [u8; 3] {
|
|
50
79
|
let mut r: u16 = 0;
|
|
51
80
|
let mut g: u16 = 0;
|
|
52
81
|
let mut b: u16 = 0;
|
|
@@ -65,31 +94,37 @@ pub fn mean_blending(px_vals: &Vec<[u8; 3]>) -> [u8; 3] {
|
|
|
65
94
|
#[cfg(test)]
|
|
66
95
|
mod tests {
|
|
67
96
|
use super::*;
|
|
97
|
+
fn create_test_data() -> SmallVec<[[u8; 3]; MAX_N_CH]> {
|
|
98
|
+
let mut px_vals: SmallVec<[[u8; 3]; MAX_N_CH]> = SmallVec::new();
|
|
99
|
+
px_vals.push([100, 100, 100]);
|
|
100
|
+
px_vals.push([200, 200, 200]);
|
|
101
|
+
px_vals
|
|
102
|
+
}
|
|
68
103
|
|
|
69
104
|
#[test]
|
|
70
105
|
fn test_max_blending() {
|
|
71
|
-
let px_vals =
|
|
106
|
+
let px_vals = create_test_data();
|
|
72
107
|
let result = max_blending(&px_vals);
|
|
73
108
|
assert_eq!(result, [200, 200, 200]);
|
|
74
109
|
}
|
|
75
110
|
|
|
76
111
|
#[test]
|
|
77
112
|
fn test_sum_blending() {
|
|
78
|
-
let px_vals =
|
|
113
|
+
let px_vals = create_test_data();
|
|
79
114
|
let result = sum_blending(&px_vals);
|
|
80
115
|
assert_eq!(result, [255, 255, 255]);
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
#[test]
|
|
84
119
|
fn test_min_blending() {
|
|
85
|
-
let px_vals =
|
|
120
|
+
let px_vals = create_test_data();
|
|
86
121
|
let result = min_blending(&px_vals);
|
|
87
122
|
assert_eq!(result, [100, 100, 100]);
|
|
88
123
|
}
|
|
89
124
|
|
|
90
125
|
#[test]
|
|
91
126
|
fn test_mean_blending() {
|
|
92
|
-
let px_vals =
|
|
127
|
+
let px_vals = create_test_data();
|
|
93
128
|
let result = mean_blending(&px_vals);
|
|
94
129
|
assert_eq!(result, [150, 150, 150]);
|
|
95
130
|
}
|