From 0f6b2a696b0998d42a5fc6ca0841d78f9086f75e Mon Sep 17 00:00:00 2001 From: Leonid Kostrykin Date: Thu, 7 Mar 2024 23:53:22 +0100 Subject: [PATCH 1/4] Add `morphological_operations` tool Squashed commit of the following: commit 0edf531d72692625c0750295beba7b6349a22765 Author: Leonid Kostrykin Date: Thu Mar 7 23:48:36 2024 +0100 Update test data commit cf17824d89ed21bafc6939fb2ce2dc45b7eb122a Author: Leonid Kostrykin Date: Thu Mar 7 22:44:12 2024 +0000 Fix UI commit 9992a546ed46ca3968bec792efffdcc7475cf9db Author: Leonid Kostrykin Date: Thu Mar 7 22:29:58 2024 +0000 Fix bug commit 5bb0d2cb61426ddf0e62959b4c346694d6f0c8fc Author: Leonid Kostrykin Date: Thu Mar 7 23:26:35 2024 +0100 Update test output data commit d72012481dac613d7b76e41141eac0e16e343fc6 Merge: 1408aab c57e084 Author: Leonid Kostrykin Date: Thu Mar 7 22:22:47 2024 +0000 Merge branch 'add-morphology-tools' of https://github.com/kostrykin/galaxy-image-analysis into add-morphology-tools commit 1408aab0dfaac225161b4dd4dd5e2455cfeb9ec1 Author: Leonid Kostrykin Date: Thu Mar 7 22:22:14 2024 +0000 Fix output type commit c57e084f4fc793850ef99e2ffe0b651da05711a9 Author: Leonid Kostrykin Date: Thu Mar 7 23:16:53 2024 +0100 Add test results commit addf5c17cd78721f93c528edb87b86a92f00842a Author: Leonid Kostrykin Date: Thu Mar 7 22:16:35 2024 +0000 Add more tests commit edf0dd5b13b75d4533098fdb7787d85acf74ed0e Author: Leonid Kostrykin Date: Thu Mar 7 22:07:40 2024 +0000 Fix bug commit 9094e30f9c1058fff6df61a3691bdb12bfb352c7 Author: Leonid Kostrykin Date: Thu Mar 7 21:44:13 2024 +0000 Fix tool commit 77bd875eca598739775c371d0ea67e0348890123 Author: Leonid Kostrykin Date: Thu Mar 7 21:40:00 2024 +0000 Fix tool commit 08840954aec7ac601c5183cca3e98eba3f665d73 Author: Leonid Kostrykin Date: Thu Mar 7 21:37:59 2024 +0000 Fix profile commit 3220ddb2d8f7afb3263504cde3b7343ec9830726 Author: Leonid Kostrykin Date: Thu Mar 7 21:37:05 2024 +0000 Add help commit 657018cc110fadda068b73ab526bfab5830da8bb Author: Leonid Kostrykin Date: Thu Mar 7 21:32:07 2024 +0000 Add citation commit 5df1d74ff2e020534f843119c00e635c3ceeb2ff Author: Leonid Kostrykin Date: Thu Mar 7 21:29:01 2024 +0000 Add tests for `morphological_operations` tool commit 59aa195c4231328e6540f14a205527a4ffca090c Author: Leonid Kostrykin Date: Thu Mar 7 21:15:58 2024 +0000 Fix `morphological_operations` tool commit e048176410e493a1124ce18c91b76bace2080eb9 Author: Leonid Kostrykin Date: Thu Mar 7 21:07:08 2024 +0000 Finish implementation of `morphological_operations` tool commit 106075c62fb09907f63ac20120ebe3df8aa1ef12 Author: Leonid Kostrykin Date: Thu Mar 7 18:56:08 2024 +0000 Continue implementation of `morphological_operations` tool commit 8057408a6a20f51b8f5d47c14f46637308c0ef1b Author: Leonid Kostrykin Date: Thu Mar 7 13:31:47 2024 +0000 Continue implementation of `morphological_operations` tool commit 442a45989966732158c6c2b34e2bd73602879457 Author: Leonid Kostrykin Date: Thu Mar 7 13:04:26 2024 +0000 Add `morphological_operations` tool commit 0ab2a2df4f63ee8edfb99d8845a065f95bb505ba Author: Leonid Kostrykin Date: Thu Mar 7 12:58:35 2024 +0000 Add devcontainer.json with useful extensions --- .devcontainer/devcontainer.json | 11 ++ tools/morphological_operations/.shed.yml | 8 ++ .../morphological_operations.py | 93 ++++++++++++ .../morphological_operations.xml | 133 ++++++++++++++++++ .../test-data/input1.tiff | Bin 0 -> 320272 bytes .../test-data/input2.png | Bin 0 -> 652 bytes .../test-data/input3.png | Bin 0 -> 317 bytes .../test-data/output1_closing.tiff | Bin 0 -> 320272 bytes .../test-data/output1_dilation.tiff | Bin 0 -> 320272 bytes .../test-data/output1_erosion.tiff | Bin 0 -> 320272 bytes .../test-data/output1_opening.tiff | Bin 0 -> 320272 bytes .../test-data/output2_fill_holes.tiff | Bin 0 -> 120272 bytes .../test-data/output3_closing.tiff | Bin 0 -> 40256 bytes .../test-data/output3_dilation.tiff | Bin 0 -> 40256 bytes .../test-data/output3_erosion.tiff | Bin 0 -> 40256 bytes .../test-data/output3_opening.tiff | Bin 0 -> 40256 bytes 16 files changed, 245 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 tools/morphological_operations/.shed.yml create mode 100644 tools/morphological_operations/morphological_operations.py create mode 100644 tools/morphological_operations/morphological_operations.xml create mode 100644 tools/morphological_operations/test-data/input1.tiff create mode 100644 tools/morphological_operations/test-data/input2.png create mode 100644 tools/morphological_operations/test-data/input3.png create mode 100644 tools/morphological_operations/test-data/output1_closing.tiff create mode 100644 tools/morphological_operations/test-data/output1_dilation.tiff create mode 100644 tools/morphological_operations/test-data/output1_erosion.tiff create mode 100644 tools/morphological_operations/test-data/output1_opening.tiff create mode 100644 tools/morphological_operations/test-data/output2_fill_holes.tiff create mode 100644 tools/morphological_operations/test-data/output3_closing.tiff create mode 100644 tools/morphological_operations/test-data/output3_dilation.tiff create mode 100644 tools/morphological_operations/test-data/output3_erosion.tiff create mode 100644 tools/morphological_operations/test-data/output3_opening.tiff diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..9da184d2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,11 @@ +{ + "image":"mcr.microsoft.com/devcontainers/universal:2", + "customizations": { + "vscode": { + "extensions": [ + "davelopez.galaxy-tools", + "ms-python.flake8" + ] + } + } +} \ No newline at end of file diff --git a/tools/morphological_operations/.shed.yml b/tools/morphological_operations/.shed.yml new file mode 100644 index 00000000..b38a3517 --- /dev/null +++ b/tools/morphological_operations/.shed.yml @@ -0,0 +1,8 @@ +categories: + - Imaging +description: Apply morphological operations to images +long_description: Apply morphological operations to images. +name: morphological_operations +owner: imgteam +homepage_url: https://github.com/bmcv +remote_repository_url: https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/morphological_operations \ No newline at end of file diff --git a/tools/morphological_operations/morphological_operations.py b/tools/morphological_operations/morphological_operations.py new file mode 100644 index 00000000..9d41245b --- /dev/null +++ b/tools/morphological_operations/morphological_operations.py @@ -0,0 +1,93 @@ +import argparse + +import numpy as np +import scipy.ndimage as ndi +import skimage.io +import skimage.morphology as morph + + +def create_selem(args): + """ + Creates structuring element based on commandline arguments. + """ + assert args.selem_shape in ( + 'square', + 'disk', + ) + + if args.selem_shape == 'square': + return np.ones((args.selem_size, args.selem_size)) + + elif args.selem_shape == 'disk': + return morph.disk(args.selem_size) + + +def apply_operation(args, im): + """ + Applies morphological operation to a 2-D single-channel image. + """ + assert im.ndim == 2 + selem = create_selem(args) + values_count = len(np.unique(im)) + if values_count <= 2: + im_proxy = np.zeros(im.shape, bool) + im_proxy[im == im.max()] = True + result_proxy = apply_binary_operation(args, im_proxy, selem) + result = np.full(im.shape, im.min(), im.dtype) + result[result_proxy] = im.max() + return result + else: + return apply_intensity_based_operation(args, im, selem) + + +def apply_intensity_based_operation(args, im, selem): + operations = { + 'erosion': ndi.grey_erosion, + 'dilation': ndi.grey_dilation, + 'opening': ndi.grey_opening, + 'closing': ndi.grey_closing, + } + if args.operation in operations: + operation = operations[args.operation] + return operation(input=im, structure=selem) + else: + raise ValueError(f'Operation "{args.operation}" not supported for this image type ({im.dtype}).') + + +def apply_binary_operation(args, im, selem): + operations = { + 'erosion': ndi.binary_erosion, + 'dilation': ndi.binary_dilation, + 'opening': ndi.binary_opening, + 'closing': ndi.binary_closing, + 'fill_holes': ndi.binary_fill_holes, + } + operation = operations[args.operation] + return operation(input=im, structure=selem) + + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + parser.add_argument('--operation', type=str) + parser.add_argument('--selem-shape', type=str) + parser.add_argument('--selem-size', type=int) + parser.add_argument('input', type=str) + parser.add_argument('output', type=str) + args = parser.parse_args() + + im = skimage.io.imread(args.input) + assert im.ndim in (2, 3), 'Input image must be two-dimensional and either single-channel or multi-channel.' + + if im.ndim == 2: + im_result = apply_operation(args, im) + + else: + ch_result_list = [] + for ch_idx in range(im.shape[2]): + ch = im[:, :, ch_idx] + ch_result = apply_operation(args, ch) + ch_result_list.append(ch_result) + im_result = np.dstack(ch_result_list) + + skimage.io.imsave(args.output, im_result) diff --git a/tools/morphological_operations/morphological_operations.xml b/tools/morphological_operations/morphological_operations.xml new file mode 100644 index 00000000..331e107c --- /dev/null +++ b/tools/morphological_operations/morphological_operations.xml @@ -0,0 +1,133 @@ + + with SciPy + + 1.12.0 + 0 + + + operation_3443 + + + scipy + + + scipy + scikit-image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Applies a morphological operation to a 2-D image. + For multi-channel images, the operation is applied to each channel separately. + + The following operations are supported: + + - **Erosion:** Shrink bright areas. + - **Dilation:** Grow bright areas. + - **Opening:** Erosion followed by Dilation. Erases tiny bright spots. + - **Closing:** Dilation followed by Erosion. Erases tiny dark holes. + - **Fill holes:** Fills the holes (dark areas) in binary images. + + + 10.1038/s41592-019-0686-2 + + \ No newline at end of file diff --git a/tools/morphological_operations/test-data/input1.tiff b/tools/morphological_operations/test-data/input1.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ad863d68f94bad45043ce8ee83c896f9e272befd GIT binary patch literal 320272 zcmeIzKWi0T5WwNx+$a{}pTY>*gj6CT(b7iS)Rtmlk&6L~fHoq25dAn-eh#aov$XWw zxC7hU%rK7-&n0gnv(KLQHzy~LryJ8W-JYg-f11aqpW|y@ecqclSKog%zQ0*M?|$z3 z>hrC6Z#o#?`!T-mF28$c{LsDC&m64&&HKye>DT`BV7_+s?_Z4HeYkx7Jw88L{qD2z z@82BX`!l{?FW=vc&$~Zgjy}GBcYb>G;_%J$47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D# zUbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb- z(9}*dX1_1yv)Al3do4Q9sm&FhHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDo zcrQ+!)@hy2-hm2D?KETd`(i$O&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y| zd(B>p4s>dBg=dZT;?!xK*6HjWsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpU zLQ^}9jMUMPBUh|FXpq? z>@|BWI?$=j6`nQTi&Lj{TBoyjph8nS&6xeZn9p9b*X*_EK&LiWc-D9?PMy|iozC8Y z3Qg@aWA^)EK6}kxv)7^no!VUCS>wGpby}x&I(r8yG_})=+3$<_>@|DMUW*QNYIB8W zjrZczX`R;T>>a4k)J`*Izc1#q*X%WWEjrMt%@v+C-iuSGby}yhcc4O3JI$E=zL?Km zv)Amk=s>47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D#UbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb-(9}*dX1_1yv)Al3do4Q9sm&Fh zHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDocrQ+!)@hy2-hm2D?KETd`(i$O z&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y|d(B>p4s>dBg=dZT;?!xK*6HjW zsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpULQ^})KPSil literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/input2.png b/tools/morphological_operations/test-data/input2.png new file mode 100644 index 0000000000000000000000000000000000000000..41a80ade6e6a710546cb9ab673c903771803431c GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k2}mkgS)OEIU<&qhaSW-L^Y-pR&O;6Y4uMlc zo@h>u3O==o$u+`$_p$Hq8ZB#{ndGdS{=3!RHjV#-b>3$72Xk6nog!3-CALlM@6Y!= zIO$tsey)ztAtgmB5YFq*mbl%s{Ar%O?`LxIL;*3*M52j^FVAYv%nE<-e(u{-_m5G< zIn?nK)Rc{9FUKI=-L}Dlqq~Jj;>aTN_s8EbN~Dk&95};HqAK^;e4omrBnHt( Z7W)fqbDE?ce+H&922WQ%mvv4FO#q%<%wGTi literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/input3.png b/tools/morphological_operations/test-data/input3.png new file mode 100644 index 0000000000000000000000000000000000000000..1aabead6778f9c7e11105e74f020a0efedf99e2f GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^CqS43NHBC5e{^DCU}W)haSW-L^Y;2i&Lai_433Fs z!e1rrS98yE_+T-i-q84=>hh;by^IV6rw#X=F3&k_ZsX$7J3&g()G4dw3dc&pAmt@) z)D-wuZ~tI=vC(gzwDmhXFzuQ3XMXKB`}vh;U8!U{BSXYmdK II;Vst08Bq}!vFvP literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output1_closing.tiff b/tools/morphological_operations/test-data/output1_closing.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ad863d68f94bad45043ce8ee83c896f9e272befd GIT binary patch literal 320272 zcmeIzKWi0T5WwNx+$a{}pTY>*gj6CT(b7iS)Rtmlk&6L~fHoq25dAn-eh#aov$XWw zxC7hU%rK7-&n0gnv(KLQHzy~LryJ8W-JYg-f11aqpW|y@ecqclSKog%zQ0*M?|$z3 z>hrC6Z#o#?`!T-mF28$c{LsDC&m64&&HKye>DT`BV7_+s?_Z4HeYkx7Jw88L{qD2z z@82BX`!l{?FW=vc&$~Zgjy}GBcYb>G;_%J$47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D# zUbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb- z(9}*dX1_1yv)Al3do4Q9sm&FhHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDo zcrQ+!)@hy2-hm2D?KETd`(i$O&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y| zd(B>p4s>dBg=dZT;?!xK*6HjWsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpU zLQ^}9jMUMPBUh|FXpq? z>@|BWI?$=j6`nQTi&Lj{TBoyjph8nS&6xeZn9p9b*X*_EK&LiWc-D9?PMy|iozC8Y z3Qg@aWA^)EK6}kxv)7^no!VUCS>wGpby}x&I(r8yG_})=+3$<_>@|DMUW*QNYIB8W zjrZczX`R;T>>a4k)J`*Izc1#q*X%WWEjrMt%@v+C-iuSGby}yhcc4O3JI$E=zL?Km zv)Amk=s>47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D#UbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb-(9}*dX1_1yv)Al3do4Q9sm&Fh zHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDocrQ+!)@hy2-hm2D?KETd`(i$O z&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y|d(B>p4s>dBg=dZT;?!xK*6HjW zsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpULQ^})KPSil literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output1_dilation.tiff b/tools/morphological_operations/test-data/output1_dilation.tiff new file mode 100644 index 0000000000000000000000000000000000000000..81c4f12a5a69438f0b3da009a488d61fac135fe8 GIT binary patch literal 320272 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 I1ZoKU1DImZ+yDRo literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output1_opening.tiff b/tools/morphological_operations/test-data/output1_opening.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ad863d68f94bad45043ce8ee83c896f9e272befd GIT binary patch literal 320272 zcmeIzKWi0T5WwNx+$a{}pTY>*gj6CT(b7iS)Rtmlk&6L~fHoq25dAn-eh#aov$XWw zxC7hU%rK7-&n0gnv(KLQHzy~LryJ8W-JYg-f11aqpW|y@ecqclSKog%zQ0*M?|$z3 z>hrC6Z#o#?`!T-mF28$c{LsDC&m64&&HKye>DT`BV7_+s?_Z4HeYkx7Jw88L{qD2z z@82BX`!l{?FW=vc&$~Zgjy}GBcYb>G;_%J$47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D# zUbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb- z(9}*dX1_1yv)Al3do4Q9sm&FhHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDo zcrQ+!)@hy2-hm2D?KETd`(i$O&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y| zd(B>p4s>dBg=dZT;?!xK*6HjWsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpU zLQ^}9jMUMPBUh|FXpq? z>@|BWI?$=j6`nQTi&Lj{TBoyjph8nS&6xeZn9p9b*X*_EK&LiWc-D9?PMy|iozC8Y z3Qg@aWA^)EK6}kxv)7^no!VUCS>wGpby}x&I(r8yG_})=+3$<_>@|DMUW*QNYIB8W zjrZczX`R;T>>a4k)J`*Izc1#q*X%WWEjrMt%@v+C-iuSGby}yhcc4O3JI$E=zL?Km zv)Amk=s>47S9sQVFHW7-X`RmAfeKCSG-LMrVm^D#UbEMt1D)Dj;aTIoICWa5bvkjXN~vb)M=g8>Fgb-(9}*dX1_1yv)Al3do4Q9sm&Fh zHQtL;r*&GVvv;6EQ#;L={l1vbUbENiwdg>nHdlDocrQ+!)@hy2-hm2D?KETd`(i$O z&0e$Dq63}UT;W;cy*PDRr*%4e2P!nR(~Q~gi}~y|d(B>p4s>dBg=dZT;?!xK*6HjW zsL<3-GiJXp=CjxAHG3^O(5cN8o;BW!Q>S%Wr?YpULQ^})KPSil literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output2_fill_holes.tiff b/tools/morphological_operations/test-data/output2_fill_holes.tiff new file mode 100644 index 0000000000000000000000000000000000000000..8954b3c51812564942b9b0a3deadd98632d6d6e0 GIT binary patch literal 120272 zcmeI*O^RGq9LC|>iAo0I$3Vr8LC8o%B(^hmkTr+{2MGoo1auhRW6_ZCgyJb3WMc4ynRcem~2jqPMVI_&q8OUJiPZg02u zzx#8)-`Q$M2ln+CJVN&t~7hn0;>#eQ=REoB#0AbAEJj{KsD>+b1V) zK7GEw_spjk$N%idpI!P{pIG5LY*J+T^NZbG~xEdd~aB`O5j~7$5w& z;)<&qGSIJXJ^7sL#W7yfm*F{`uWraHS3bA*vrtcR#Z}kRlU#Atwe%!cTy-ry$rV>! zOHXpeRoBv!TyfR4^dwhYbuB%~6<1wLPjbao*V2<*an-f-Bv)K@Ej`HZ5G z(vw_q)wT2_S6p>1J;@bUT}w}L#Z}kRlU#Atwe%!cTy-ry$rV>!OHXpeRoBv!TyfR4 z^dwhYbuB%~6<1wLPjbao*V2<*an-f-Bv)K@Ej`HZ5G(vw_q)wT2_S6p>1 zJ;@bUT}w}L#Z}kRlU#Atwe%!cTy-ry$rV>!OHXpeRoBv!TyfR4^dwhYbuB%~6<1wL zPjbao*V2<*z1FS{htuQS4#)d?8Fyl}KhD+tagKv(w|c}cuD0#jR+v{`&6j7dXRfYC zsq@uU;aqWbjI$h9Tyb^&q3wDkT<>m}u7j?F*DLD$*|_40tE&cF2VDpM`wheSuNsao zWKEsV?bq{Z&2{jqaIUyoJ0p#!xZ-LoWNnozuGZv?r?}#3EM#q!E3Ve$jHkHbYAj@J zl`F2+(*ebTu z|L+EVz9)G3enYS3>Cv3bJ~LNb&6+8BuDB{rW;0xIHEX8ix#Frgnayy;)vTG4=ZdT1 zWH!SUSF>hHo-3}3li3VcT+Ny(d9JuBPG&P)aW!kEhHo-3}3 zli3VcT+Ny(d9JuBPG&P)aW!kED z=bdS5?9R3C^L2ldT|y65&+M*xKHQvNe;eb`bo-+J&pG>ebN)4-pRBSk=KlBQ+VA;V zUSIYXM6M8+pm9bt=^YUxxPM~o}8SVemH)9_IdRbM+iUw0uX=z z1R(Hl0!K&7f25oL;(PpG4)KAH1OfIcLDlbx51(BkiH`(Tzb8I?c8MfD5>)-3`0&{! zlK4na^?TyOXO~FgBSF>gi4UJ$B8iU#Rlg@be0GT>J`z;@p7`+DC6f3^Q1yG_!)KRB z;v+%T?}-neT_TB(1XaH$K74kGBt8;U{hs*n*(H+rNKo~A;=^Z`Na7)-3`0&{!lK4na^?TyOXO~FgBSF>gi4UJ$B6%Gj=a;+^pYbX^`5t3jqT~E3>=Mu5 z10U>_Ccy85--q4~{|OI>ez@#U-<-UAeRlTZq<*~r{_m^N=kh7X=a-AwYyw`o~mKJ^JBSFBqN>JsU`rzym zNqr=!@=kqlc8R1u5>$DoJ~+EXQXdJbyi*^XT_UNE1XbRt56&);)JK9U@6-opmq_X( zL6vvvgR@H{^^u^;JN3cYC6f9`Q01Na;Or7feI%&zPJM88iKIRfRC%X9IJ-nr9|@|w zQy-jNBB_rARoNA z>=H?RB&hOEeQKdZv@km2)*c9sC>T%DLjx zGo5s?mD(}<>XO~FoBSDpS>VvaOB=wP?$~*PJ*(H+tNKoaS`rzymNqr=!@=kqlc8R1u z5>$DoJ~+EXQXdJbyi*^XT_UNE1XbRt56&);)JK9U@6-opmq_X(L6vvvgR@H{^^u^; zJN3cYC6f9`Q01Na;Or7feI%&zPJM88iKIRfRC%X9IJ-nr9|@|wQy-jNBH8t27>1Il b-fCypl`@q5-^W&=`C}50fCMD4B?5l|>4rd! literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output3_erosion.tiff b/tools/morphological_operations/test-data/output3_erosion.tiff new file mode 100644 index 0000000000000000000000000000000000000000..fbc462938e421d438419ac2f96a9b981f70d0654 GIT binary patch literal 40256 zcmeH`F=`c27)I|)R4gQ5VFYbLDiM)rX=R%=h=qha3|IuT5pgH3!!@`FOG`J9&Ux__ z1K~k9$pMLHV1~=g{XS;S`RDNP>9{+_*coGSYb>VKkLg^@)?171^ZTn^+w1je-<{cd zXR$SQr+eS0^Zq)!3O$(Z*`0MhT(4h$8{^U9_Idx$Df@W6{xz+i%(5@0{(IBC-_yA| zzU+T||L*j7|JB}`mj?&W_NL3*uYVuSuB*44pPx>a%jL<3K9?2KeS463{{ADo?$%!fghcjkk$ zGm`l*sPfKyaCS!WDn8CG9L5`7uCwnL)n)?yAN?Pjr-MIfu9_=8 zJ)4uwRdcm@I{1_3>gLQ9pMvX8US+PX|800<-@(}#$$S`8d1pR2J0qD7gDUUL2WMv_ z^I=fso%!JGjAT9xs=PBFoSl)(he4Hh=7X~{lKC*G^3Hs4c1AKE236jf56;d==EI=M zJM+QW8OeMYRC#AUI6EVm4}&W2%m-&@B=ccV<(>K9?2KeS463{{ADo?$%!fghcjkk$ zGm`l*sPfKyaCSyA9|l$4nGep+Nan+!$~*JH*%`@v7*y+wKm;NXfe1t(0xE$&n4^;# literal 0 HcmV?d00001 diff --git a/tools/morphological_operations/test-data/output3_opening.tiff b/tools/morphological_operations/test-data/output3_opening.tiff new file mode 100644 index 0000000000000000000000000000000000000000..c27b7a6707f1816f2725d700255f980d0aa8b626 GIT binary patch literal 40256 zcmeH}v1$}i7=`a7Di#v3FoHHAm54~Rw6e`Jh=q_W1}p;Fi1;QxhtJ?cSX%l7shnN6 zm?DRS6AmZEw=m1)pL_m)=KJo#9v?p+_s1A}V@!9(G_QWm*R)vgOuL)&jAV$c4f=i}}A?T;~@Om{c^f6v*c+x4G${cMqaHTQoo*Z$7e z`t$AZ^T!Y8r-yG2-n~9LdT}s+z5o9I*5Z5pl*{YO*=n^q`*iy9{Oe*DO9(&!0uX=z z1R!uVfs@UDq^tMc_8q*(?J|T9d?W~Pt`b!Jp7`+DC6f3^Q1yG_!)KRB;v+%T?}-ne zT_TB(1XaH$K74kGBt8;U{hs*n*(H+rNKo~A;=^Z`Na7)-3`0&{! zlK4na^?TyOXO~FgBSF>gi4UJ$B8iU#Rlg@be0GT>J`z;@p7`+DC6f3^Q1yG_!)KRB z;v+%T?}-neT_TB(1XaH$K74kGBt8;U{hs*n*(H)U@o{mB)PHafyzL>#$4g z!3RD#SDFC74}Kr|boh5TSDY*V^ynn#igTq;hku82#kulNk4|!~G@HhqoA_uvubRnw zC^DToK04ghRD38hojN``+|^WkC^DToK04ghRD38hojN``+|^WkC^DToK04ghRD38h zojN``+|^WkC^DToK04ghRD38hojN``+|^WkC^DToK04ghRD38hojN``+|^WkC^DTo zK04ghRD38hojN``+|^WkC^DToK04ghRD38hojN``+|^WkC^DToK04ghRD38hojN`` b+|^WkC^DToK04f)3IPZ}00IzzK!?CTG>2@z literal 0 HcmV?d00001 From 2448178d6cb35fc3a9d1ef4c051f11572a6540e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 8 Mar 2024 10:56:45 +0100 Subject: [PATCH 2/4] Delete .devcontainer/devcontainer.json --- .devcontainer/devcontainer.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 9da184d2..00000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "image":"mcr.microsoft.com/devcontainers/universal:2", - "customizations": { - "vscode": { - "extensions": [ - "davelopez.galaxy-tools", - "ms-python.flake8" - ] - } - } -} \ No newline at end of file From 32a082f7c655299cfb20c22618b70bd5ba210c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 8 Mar 2024 10:57:20 +0100 Subject: [PATCH 3/4] Update .gitignore with .devcontainer/ --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fad9b7c3..d81c5521 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ template_shed.yml /create_csvs.py .DS_Store ._* +.devcontainer From 78b39c349741a4e2c2070a23fa37e9cb4f1377da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 8 Mar 2024 11:11:04 +0100 Subject: [PATCH 4/4] Create styler.R --- .github/styler.R | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/styler.R diff --git a/.github/styler.R b/.github/styler.R new file mode 100644 index 00000000..c5c0cb5d --- /dev/null +++ b/.github/styler.R @@ -0,0 +1,36 @@ +#!/usr/bin/env Rscript + +library("argparse") +library("styler") + +parser <- ArgumentParser(description = "Call styler") +parser$add_argument("dir", + metavar = "DIR", type = "character", + help = "File to parse" +) +parser$add_argument("--dry", + choices = c("off", "on"), default = "on" +) +args <- parser$parse_args() + +file_info <- file.info(args$dir) +is_directory <- file_info$isdir + +if (is_directory) { + captured_output <- capture.output({ + result <- style_dir(args$dir, indent_by = 4, dry = args$dry, recursive = TRUE) + }) +} else { + captured_output <- capture.output({ + result <- style_file(args$dir, indent_by = 4, dry = args$dry) + }) +} + +n <- nrow(subset(result, changed == TRUE)) +if (n > 0) { + if (args$dry == "off") { + print(paste("Changed", n, "files")) + } else { + stop(paste("Linting failed for", n, "files")) + } +}