diff --git a/demo/smoothing.ipynb b/demo/smoothing.ipynb index 65205634..fb2f0dc7 100644 --- a/demo/smoothing.ipynb +++ b/demo/smoothing.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 29, + "execution_count": 1, "id": "eb73de20-5c0d-4cae-836c-ee3e240cad68", "metadata": {}, "outputs": [], @@ -13,7 +13,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ff3849b7", "metadata": {}, @@ -23,13 +22,13 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 2, "id": "abc572bf", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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\n", "text/plain": [ "
" ] @@ -39,7 +38,7 @@ } ], "source": [ - "array = np.zeros((100, 100), dtype=np.uint8)\n", + "array = np.zeros((100, 85), dtype=np.uint8)\n", "array[15:85, 15:85] = 1\n", "array[35:65, 35:65] = 0\n", "cle.imshow(array)" @@ -47,7 +46,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 3, "id": "560a1217", "metadata": {}, "outputs": [ @@ -60,7 +59,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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\n", "text/plain": [ "
" ] @@ -77,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 4, "id": "480d0014", "metadata": {}, "outputs": [ @@ -90,7 +89,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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\n", "text/plain": [ "
" ] @@ -106,7 +105,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "48e384da", "metadata": {}, @@ -116,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 5, "id": "d418a958", "metadata": {}, "outputs": [ @@ -165,7 +163,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 6, "id": "3d2b5f2f", "metadata": {}, "outputs": [ @@ -214,7 +212,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 7, "id": "9c25d0db", "metadata": {}, "outputs": [ @@ -263,7 +261,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 8, "id": "9d4e616a", "metadata": {}, "outputs": [ @@ -300,7 +298,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 9, "id": "90c85d91", "metadata": {}, "outputs": [ @@ -311,9 +309,9 @@ "Pyclesperanto\n", "\n", "[[[0 0 0 0 0]\n", + " [0 0 0 0 0]\n", " [0 0 1 0 0]\n", - " [0 1 1 1 0]\n", - " [0 0 1 0 0]\n", + " [0 0 0 0 0]\n", " [0 0 0 0 0]]\n", "\n", " [[0 0 0 0 0]\n", @@ -323,9 +321,9 @@ " [0 0 0 0 0]]\n", "\n", " [[0 0 0 0 0]\n", + " [0 0 0 0 0]\n", " [0 0 1 0 0]\n", - " [0 1 1 1 0]\n", - " [0 0 1 0 0]\n", + " [0 0 0 0 0]\n", " [0 0 0 0 0]]]\n" ] } @@ -337,7 +335,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 10, "id": "226f18fe", "metadata": {}, "outputs": [ @@ -383,7 +381,7 @@ ], "metadata": { "kernelspec": { - "display_name": "cle_39", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -397,7 +395,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.9.15" }, "vscode": { "interpreter": { diff --git a/pyclesperanto_prototype/_tier1/_inferior_superior.py b/pyclesperanto_prototype/_tier1/_inferior_superior.py index 0b339ccf..bb9c9418 100644 --- a/pyclesperanto_prototype/_tier1/_inferior_superior.py +++ b/pyclesperanto_prototype/_tier1/_inferior_superior.py @@ -26,6 +26,10 @@ def inferior_superior(source : Image, destination : Image = None) -> Image: Implemented in inf_sup function in scikit morphological snakes: .. [1] https://github.com/scikit-image/scikit-image/blob/00177e14097237ef20ed3141ed454bc81b308f82/skimage/segmentation/morphsnakes.py """ + import numpy as np + if source.dtype != np.uint8: + # the read function in the kernel below is custom and only supports images of type uint8 + source = source.astype(np.uint8) parameters = { "src":source, diff --git a/pyclesperanto_prototype/_tier1/_superior_inferior.py b/pyclesperanto_prototype/_tier1/_superior_inferior.py index e8d10ba5..7adba43c 100644 --- a/pyclesperanto_prototype/_tier1/_superior_inferior.py +++ b/pyclesperanto_prototype/_tier1/_superior_inferior.py @@ -26,6 +26,10 @@ def superior_inferior(source : Image, destination : Image = None) -> Image: Implemented in sup_inf function in scikit morphological snakes: .. [1] https://github.com/scikit-image/scikit-image/blob/00177e14097237ef20ed3141ed454bc81b308f82/skimage/segmentation/morphsnakes.py """ + import numpy as np + if source.dtype != np.uint8: + # the read function in the kernel below is custom and only supports images of type uint8 + source = source.astype(np.uint8) parameters = { "src":source, diff --git a/pyclesperanto_prototype/_tier1/inferior_superior_2d_x.cl b/pyclesperanto_prototype/_tier1/inferior_superior_2d_x.cl index 819b0930..8db97f94 100644 --- a/pyclesperanto_prototype/_tier1/inferior_superior_2d_x.cl +++ b/pyclesperanto_prototype/_tier1/inferior_superior_2d_x.cl @@ -1,5 +1,17 @@ __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; +#define READ_IMAGE_ZERO_OUTSIDE(a,b,c) read_buffer2duc_zero_outside(GET_IMAGE_WIDTH(a),GET_IMAGE_HEIGHT(a),GET_IMAGE_DEPTH(a),a,b,c) + +inline uchar2 read_buffer2duc_zero_outside(int read_buffer_width, int read_buffer_height, int read_buffer_depth, __global uchar * buffer_var, sampler_t sampler, int2 position ) +{ + int2 pos = (int2){position.x, position.y}; + int pos_in_buffer = pos.x + pos.y * read_buffer_width; + if (pos.x < 0 || pos.x >= read_buffer_width || pos.y < 0 || pos.y >= read_buffer_height) { + return (uchar2){0, 0}; + } + return (uchar2){buffer_var[pos_in_buffer],0}; +} + __kernel void inferior_superior_2d ( IMAGE_src_TYPE src, IMAGE_dst_TYPE dst @@ -10,7 +22,7 @@ __kernel void inferior_superior_2d ( const int2 pos = (int2){x,y}; - float value = READ_src_IMAGE(src, sampler, pos).x; + float value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, pos).x; // if value is already 1, dilate will return 1 if (value == 1) { @@ -21,9 +33,9 @@ __kernel void inferior_superior_2d ( /* Dilate with kernel [[1, 0, 0], [0, 1, 0], [0, 0, 1]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, 1})).x; if (value == 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, -1})).x; if (value == 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(0)); return; @@ -33,9 +45,9 @@ __kernel void inferior_superior_2d ( /* Dilate with kernel [[0, 1, 0], [0, 1, 0], [0, 1, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){0, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){0, 1})).x; if (value == 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){0, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){0, -1})).x; if (value == 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(0)); return; @@ -45,9 +57,9 @@ __kernel void inferior_superior_2d ( /* Dilate with kernel [[0, 0, 1], [0, 1, 0], [1, 0, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, 1})).x; if (value == 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, -1})).x; if (value == 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(0)); return; @@ -57,9 +69,9 @@ __kernel void inferior_superior_2d ( /* Dilate with kernel [[0, 0, 0], [1, 1, 1], [0, 0, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, 0})).x; if (value == 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, 0})).x; if (value == 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(0)); return; diff --git a/pyclesperanto_prototype/_tier1/inferior_superior_3d_x.cl b/pyclesperanto_prototype/_tier1/inferior_superior_3d_x.cl index 77e198ab..367df83d 100644 --- a/pyclesperanto_prototype/_tier1/inferior_superior_3d_x.cl +++ b/pyclesperanto_prototype/_tier1/inferior_superior_3d_x.cl @@ -1,5 +1,18 @@ __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + +#define READ_IMAGE_ZERO_OUTSIDE(a,b,c) read_buffer3duc_zero_outside(GET_IMAGE_WIDTH(a),GET_IMAGE_HEIGHT(a),GET_IMAGE_DEPTH(a),a,b,c) + +inline uchar2 read_buffer3duc_zero_outside(int read_buffer_width, int read_buffer_height, int read_buffer_depth, __global uchar * buffer_var, sampler_t sampler, int4 position ) +{ + int4 pos = (int4){position.x, position.y, position.z, 0}; + int pos_in_buffer = pos.x + pos.y * read_buffer_width + pos.z * read_buffer_width * read_buffer_height; + if (pos.x < 0 || pos.x >= read_buffer_width || pos.y < 0 || pos.y >= read_buffer_height || pos.z < 0 || pos.z >= read_buffer_depth) { + return (uchar2){0, 0}; + } + return (uchar2){buffer_var[pos_in_buffer],0}; +} + __kernel void inferior_superior_3d ( IMAGE_src_TYPE src, IMAGE_dst_TYPE dst @@ -11,7 +24,7 @@ __kernel void inferior_superior_3d ( const int4 pos = (int4){x, y, z, 0}; - float value = READ_src_IMAGE(src, sampler, pos).x; + float value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, pos).x; // if value is already 0, erode will return 0 if (value != 0) { @@ -25,7 +38,7 @@ __kernel void inferior_superior_3d ( // P0 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, 0, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, 0, 0})).x; // printf("value %i\n", value); if (value != 0) { break; @@ -43,7 +56,7 @@ __kernel void inferior_superior_3d ( // P1 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, 0, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, 0, j, 0})).x; if (value != 0) { break; } @@ -60,7 +73,7 @@ __kernel void inferior_superior_3d ( // P2 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){0, i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){0, i, j, 0})).x; if (value != 0) { break; } @@ -77,7 +90,7 @@ __kernel void inferior_superior_3d ( // P3 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, j, 0})).x; if (value != 0) { break; } @@ -94,7 +107,7 @@ __kernel void inferior_superior_3d ( // P4 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){j, i, -i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){j, i, -i, 0})).x; if (value != 0) { break; } @@ -111,7 +124,7 @@ __kernel void inferior_superior_3d ( // P5 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, i, 0})).x; if (value != 0) { break; } @@ -128,7 +141,7 @@ __kernel void inferior_superior_3d ( // P6 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, -i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, -i, 0})).x; if (value != 0) { break; } @@ -145,7 +158,7 @@ __kernel void inferior_superior_3d ( // P7 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, i, j, 0})).x; if (value != 0) { break; } @@ -162,7 +175,7 @@ __kernel void inferior_superior_3d ( // P8 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, -i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, -i, j, 0})).x; if (value != 0) { break; } diff --git a/pyclesperanto_prototype/_tier1/superior_inferior_2d_x.cl b/pyclesperanto_prototype/_tier1/superior_inferior_2d_x.cl index cc051b92..aae7c711 100644 --- a/pyclesperanto_prototype/_tier1/superior_inferior_2d_x.cl +++ b/pyclesperanto_prototype/_tier1/superior_inferior_2d_x.cl @@ -1,5 +1,19 @@ __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + +#define READ_IMAGE_ZERO_OUTSIDE(a,b,c) read_buffer2duc_zero_outside(GET_IMAGE_WIDTH(a),GET_IMAGE_HEIGHT(a),GET_IMAGE_DEPTH(a),a,b,c) + +inline uchar2 read_buffer2duc_zero_outside(int read_buffer_width, int read_buffer_height, int read_buffer_depth, __global uchar * buffer_var, sampler_t sampler, int2 position ) +{ + int2 pos = (int2){position.x, position.y}; + int pos_in_buffer = pos.x + pos.y * read_buffer_width; + if (pos.x < 0 || pos.x >= read_buffer_width || pos.y < 0 || pos.y >= read_buffer_height) { + return (uchar2){0, 0}; + } + return (uchar2){buffer_var[pos_in_buffer],0}; +} + + __kernel void superior_inferior_2d ( IMAGE_src_TYPE src, IMAGE_dst_TYPE dst @@ -10,7 +24,7 @@ __kernel void superior_inferior_2d ( const int2 pos = (int2){x,y}; - float value = READ_src_IMAGE(src, sampler, pos).x; + float value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, pos).x; // if value is already 0, erode will return 0 if (value == 0) { @@ -21,9 +35,9 @@ __kernel void superior_inferior_2d ( /* Erode with kernel [[1, 0, 0], [0, 1, 0], [0, 0, 1]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, 1})).x; if (value != 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, -1})).x; if (value != 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(1)); return; @@ -33,9 +47,9 @@ __kernel void superior_inferior_2d ( /* Erode with kernel [[0, 1, 0], [0, 1, 0], [0, 1, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){0, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){0, 1})).x; if (value != 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){0, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){0, -1})).x; if (value != 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(1)); return; @@ -45,9 +59,9 @@ __kernel void superior_inferior_2d ( /* Erode with kernel [[0, 0, 1], [0, 1, 0], [1, 0, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, 1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, 1})).x; if (value != 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, -1})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, -1})).x; if (value != 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(1)); return; @@ -57,9 +71,9 @@ __kernel void superior_inferior_2d ( /* Erode with kernel [[0, 0, 0], [1, 1, 1], [0, 0, 0]] */ - value = READ_src_IMAGE(src, sampler, (pos + (int2){1, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){1, 0})).x; if (value != 0) { - value = READ_src_IMAGE(src, sampler, (pos + (int2){-1, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int2){-1, 0})).x; if (value != 0) { WRITE_dst_IMAGE(dst, pos, CONVERT_dst_PIXEL_TYPE(1)); return; diff --git a/pyclesperanto_prototype/_tier1/superior_inferior_3d_x.cl b/pyclesperanto_prototype/_tier1/superior_inferior_3d_x.cl index 9b8cf260..d997a227 100644 --- a/pyclesperanto_prototype/_tier1/superior_inferior_3d_x.cl +++ b/pyclesperanto_prototype/_tier1/superior_inferior_3d_x.cl @@ -1,5 +1,17 @@ __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; +#define READ_IMAGE_ZERO_OUTSIDE(a,b,c) read_buffer3duc_zero_outside(GET_IMAGE_WIDTH(a),GET_IMAGE_HEIGHT(a),GET_IMAGE_DEPTH(a),a,b,c) + +inline uchar2 read_buffer3duc_zero_outside(int read_buffer_width, int read_buffer_height, int read_buffer_depth, __global uchar * buffer_var, sampler_t sampler, int4 position ) +{ + int4 pos = (int4){position.x, position.y, position.z, 0}; + int pos_in_buffer = pos.x + pos.y * read_buffer_width + pos.z * read_buffer_width * read_buffer_height; + if (pos.x < 0 || pos.x >= read_buffer_width || pos.y < 0 || pos.y >= read_buffer_height || pos.z < 0 || pos.z >= read_buffer_depth) { + return (uchar2){0, 0}; + } + return (uchar2){buffer_var[pos_in_buffer],0}; +} + __kernel void superior_inferior_3d ( IMAGE_src_TYPE src, IMAGE_dst_TYPE dst @@ -25,7 +37,7 @@ __kernel void superior_inferior_3d ( // P0 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, 0, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, 0, 0})).x; // printf("value %i\n", value); if (value == 0) { break; @@ -43,7 +55,7 @@ __kernel void superior_inferior_3d ( // P1 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, 0, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, 0, j, 0})).x; if (value == 0) { break; } @@ -60,7 +72,7 @@ __kernel void superior_inferior_3d ( // P2 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){0, i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){0, i, j, 0})).x; if (value == 0) { break; } @@ -77,7 +89,7 @@ __kernel void superior_inferior_3d ( // P3 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, j, 0})).x; if (value == 0) { break; } @@ -94,7 +106,7 @@ __kernel void superior_inferior_3d ( // P4 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){j, i, -i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){j, i, -i, 0})).x; if (value == 0) { break; } @@ -111,7 +123,7 @@ __kernel void superior_inferior_3d ( // P5 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, i, 0})).x; if (value == 0) { break; } @@ -128,7 +140,7 @@ __kernel void superior_inferior_3d ( // P6 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, j, -i, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, j, -i, 0})).x; if (value == 0) { break; } @@ -145,7 +157,7 @@ __kernel void superior_inferior_3d ( // P7 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, i, j, 0})).x; if (value == 0) { break; } @@ -162,7 +174,7 @@ __kernel void superior_inferior_3d ( // P8 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - value = READ_src_IMAGE(src, sampler, (pos + (int4){i, -i, j, 0})).x; + value = READ_IMAGE_ZERO_OUTSIDE(src, sampler, (pos + (int4){i, -i, j, 0})).x; if (value == 0) { break; } diff --git a/tests/test_superior_inferior.py b/tests/test_superior_inferior.py index f3ce0443..28e69721 100644 --- a/tests/test_superior_inferior.py +++ b/tests/test_superior_inferior.py @@ -1,6 +1,6 @@ import pyclesperanto_prototype as cle import numpy as np - +from skimage.segmentation.morphsnakes import sup_inf, inf_sup def test_superior_inferior_2d(): test = cle.push(np.asarray([ @@ -37,11 +37,49 @@ def test_superior_inferior_2d(): a = cle.pull(result) b = cle.pull(reference) assert (np.array_equal(a, b)) - - + + reference2 = sup_inf(test) + assert cle.array_equal(result, reference2) + +def test_superior_inferior_2d_compare_with_skimage_x(): + + array = np.zeros((100, 85), dtype=np.uint8) + array[15:85, 15:85] = 1 + array[35:65, 35:65] = 0 + + result = cle.superior_inferior(cle.inferior_superior(array)) + reference = sup_inf(inf_sup(array)) + + print("result", result) + print("reference", reference) + + assert cle.array_equal(result, reference) + + +def test_superior_inferior_2d_compare_with_skimage_y(): + + array = np.zeros((85, 100), dtype=np.uint8) + array[15:85, 15:85] = 1 + array[35:65, 35:65] = 0 + + result = cle.superior_inferior(cle.inferior_superior(array)) + reference = sup_inf(inf_sup(array)) + + print("result", result) + print("reference", reference) + + assert cle.array_equal(result, reference) + + def test_superior_inferior_3d(): test = cle.push(np.asarray([ + [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]], + + [[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], @@ -57,34 +95,64 @@ def test_superior_inferior_3d(): [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], - [0, 0, 0, 0, 0] - ])) - - reference = cle.push(np.asarray([ - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 1, 0, 1, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0]], - - [[0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0] + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]], ])) + + reference = inf_sup(test) - result = cle.create(test) - cle.inferior_superior(test, result) + result = cle.inferior_superior(test) - print(result) + print("result", result) + print("reference", reference) a = cle.pull(result) b = cle.pull(reference) - assert (np.array_equal(a, b)) \ No newline at end of file + assert (np.array_equal(a, b)) + +def test_superior_inferior_3d_compare_with_skimage_x(): + + array = np.zeros((5, 5, 4)) + array[1:4, 1:4, 1:4] = 1 + array[2, 2, 2] = 0 + + result = cle.superior_inferior(cle.inferior_superior(array)) + reference = sup_inf(inf_sup(array)) + + print("result", result) + print("reference", reference) + + assert cle.array_equal(result, reference) + +def test_superior_inferior_3d_compare_with_skimage_y(): + + array = np.zeros((5, 4, 5)) + array[1:4, 1:4, 1:4] = 1 + array[2, 2, 2] = 0 + + result = cle.superior_inferior(cle.inferior_superior(array)) + reference = sup_inf(inf_sup(array)) + + print("result", result) + print("reference", reference) + + assert cle.array_equal(result, reference) + +def test_superior_inferior_3d_compare_with_skimage_z(): + + array = np.zeros((4, 5, 5)) + array[1:4, 1:4, 1:4] = 1 + array[2, 2, 2] = 0 + + result = cle.superior_inferior(cle.inferior_superior(array)) + reference = sup_inf(inf_sup(array)) + + print("result", result) + print("reference", reference) + + assert cle.array_equal(result, reference)