Skip to content

Commit 268d88f

Browse files
committed
add rank_downscale
1 parent 50f6413 commit 268d88f

File tree

4 files changed

+240
-1
lines changed

4 files changed

+240
-1
lines changed

gputools/convolve/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
#from .minmax_filter import max_filter, min_filter
1313
from .generic_separable_filters import max_filter, min_filter, uniform_filter
1414
from .median_filter import median_filter
15+
from .rank_downscale import rank_downscale
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// https://github.com/rudrasohan/algorithms/blob/master/quickselect.c
2+
3+
inline void swap(${DTYPE}* a, ${DTYPE}* b)
4+
{
5+
${DTYPE} t = *a;
6+
*a = *b;
7+
*b = t;
8+
}
9+
10+
inline int partition(${DTYPE}* arr, const int l, const int r)
11+
{
12+
${DTYPE} x = arr[r];
13+
int i = l;
14+
for (int j = l; j <= r - 1; j++) {
15+
if (arr[j] <= x) {
16+
swap(&arr[i], &arr[j]);
17+
i++;
18+
}
19+
}
20+
swap(&arr[i], &arr[r]);
21+
return i;
22+
}
23+
24+
inline ${DTYPE} kthSmallest(${DTYPE} arr[], int l, int r, int k)
25+
{
26+
// If k is smaller than number of
27+
// elements in array
28+
if (k > 0 && k <= r - l + 1) {
29+
30+
// Partition the array around last
31+
// element and get position of pivot
32+
// element in sorted array
33+
int index = partition(arr, l, r);
34+
35+
// If position is same as k
36+
if (index - l == k - 1)
37+
return arr[index];
38+
39+
// If position is more, recur
40+
// for left subarray
41+
if (index - l > k - 1)
42+
return kthSmallest(arr, l, index - 1, k);
43+
44+
// Else recur for right subarray
45+
return kthSmallest(arr, index + 1, r,
46+
k - index + l - 1);
47+
}
48+
else
49+
return (${DTYPE})0;
50+
51+
}
52+
53+
54+
55+
__kernel void rank_2(__global ${DTYPE} * input,
56+
__global ${DTYPE} * output,
57+
const int Nx0, const int Ny0,
58+
const int rank){
59+
60+
int x = get_global_id(0);
61+
int y = get_global_id(1);
62+
63+
int Nx = get_global_size(0);
64+
int Ny = get_global_size(1);
65+
66+
67+
68+
${DTYPE} a[${FSIZE_Y}*${FSIZE_X}];
69+
70+
for (int m = 0; m < ${FSIZE_Y}; ++m) {
71+
for (int n = 0; n < ${FSIZE_X}; ++n) {
72+
73+
int x2 = x*${FSIZE_X}+n;
74+
int y2 = y*${FSIZE_Y}+m;
75+
76+
bool inside = ((x2>=0)&&(x2<Nx0)&&(y2>=0)&&(y2<Ny0));
77+
78+
a[n+${FSIZE_X}*m] = inside?input[x2+y2*Nx0]:(${DTYPE})(${CVAL});
79+
}
80+
}
81+
82+
83+
output[x+y*Nx] = kthSmallest(a, 0, ${FSIZE_X}*${FSIZE_Y}-1, rank+1);
84+
85+
}
86+
87+
88+
89+
__kernel void rank_3(__global ${DTYPE} * input,
90+
__global ${DTYPE} * output,
91+
const int Nx0, const int Ny0, const int Nz0,
92+
const int rank){
93+
94+
int x = get_global_id(0);
95+
int y = get_global_id(1);
96+
int z = get_global_id(2);
97+
98+
int Nx = get_global_size(0);
99+
int Ny = get_global_size(1);
100+
int Nz = get_global_size(2);
101+
102+
103+
104+
${DTYPE} a[${FSIZE_Z}*${FSIZE_Y}*${FSIZE_X}];
105+
106+
for (int p = 0; p < ${FSIZE_Z}; ++p) {
107+
for (int m = 0; m < ${FSIZE_Y}; ++m) {
108+
for (int n = 0; n < ${FSIZE_X}; ++n) {
109+
110+
int x2 = x*${FSIZE_X}+n;
111+
int y2 = y*${FSIZE_Y}+m;
112+
int z2 = z*${FSIZE_Z}+p;
113+
114+
bool inside = ((x2>=0)&&(x2<Nx0)&&(y2>=0)&&(y2<Ny0)&&(z2>=0)&&(z2<Nz0));
115+
116+
a[n+${FSIZE_X}*m+${FSIZE_X}*${FSIZE_Y}*p] = inside?input[x2+y2*Nx0+z2*Nx0*Ny0]:(${DTYPE})(${CVAL});
117+
}
118+
}
119+
}
120+
121+
122+
output[x+y*Nx+z*Nx*Ny] = kthSmallest(a, 0, ${FSIZE_X}*${FSIZE_Y}*${FSIZE_Z}-1, rank+1);
123+
124+
}

gputools/convolve/rank_downscale.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from __future__ import print_function, unicode_literals, absolute_import, division
2+
import logging
3+
from typing import Union, Tuple
4+
5+
logger = logging.getLogger(__name__)
6+
7+
import numpy as np
8+
from mako.template import Template
9+
from numbers import Number
10+
from gputools import OCLArray, OCLProgram
11+
from gputools.core.ocltypes import cl_buffer_datatype_dict
12+
from ._abspath import abspath
13+
14+
15+
def _rank_downscale_2d(data_g, size=(3, 3), rank=None, cval = 0, res_g=None):
16+
if not data_g.dtype.type in cl_buffer_datatype_dict:
17+
raise ValueError("dtype %s not supported" % data_g.dtype.type)
18+
19+
DTYPE = cl_buffer_datatype_dict[data_g.dtype.type]
20+
21+
size = tuple(map(int, size))
22+
23+
if rank is None:
24+
rank = np.prod(size) // 2
25+
26+
with open(abspath("kernels/rank_downscale.cl"), "r") as f:
27+
tpl = Template(f.read())
28+
29+
rendered = tpl.render(DTYPE = DTYPE,FSIZE_Z=0, FSIZE_X=size[1], FSIZE_Y=size[0],CVAL = cval)
30+
31+
prog = OCLProgram(src_str=rendered)
32+
33+
if res_g is None:
34+
res_g = OCLArray.empty(tuple(s0//s for s, s0 in zip(size,data_g.shape)), data_g.dtype)
35+
36+
prog.run_kernel("rank_2", res_g.shape[::-1], None, data_g.data, res_g.data,
37+
np.int32(data_g.shape[1]), np.int32(data_g.shape[0]),
38+
np.int32(rank))
39+
return res_g
40+
41+
def _rank_downscale_3d(data_g, size=(3, 3, 3), rank=None, cval = 0, res_g=None):
42+
if not data_g.dtype.type in cl_buffer_datatype_dict:
43+
raise ValueError("dtype %s not supported" % data_g.dtype.type)
44+
45+
DTYPE = cl_buffer_datatype_dict[data_g.dtype.type]
46+
47+
size = tuple(map(int, size))
48+
49+
if rank is None:
50+
rank = np.prod(size) // 2
51+
52+
with open(abspath("kernels/rank_downscale.cl"), "r") as f:
53+
tpl = Template(f.read())
54+
55+
rendered = tpl.render(DTYPE = DTYPE,FSIZE_X=size[2], FSIZE_Y=size[1], FSIZE_Z=size[0],CVAL = cval)
56+
57+
prog = OCLProgram(src_str=rendered)
58+
59+
if res_g is None:
60+
res_g = OCLArray.empty(tuple(s0//s for s, s0 in zip(size,data_g.shape)), data_g.dtype)
61+
62+
prog.run_kernel("rank_3", res_g.shape[::-1], None, data_g.data, res_g.data,
63+
np.int32(data_g.shape[2]), np.int32(data_g.shape[1]), np.int32(data_g.shape[0]),
64+
np.int32(rank))
65+
return res_g
66+
67+
68+
def rank_downscale(data:np.ndarray, size:Union[int, Tuple[int]]=3, rank=None):
69+
"""
70+
downscales an image by the given factor and returns the rank-th element in each block
71+
72+
Parameters
73+
----------
74+
data: numpy.ndarray
75+
input data (2d or 3d)
76+
size: int or tuple
77+
downsampling factors
78+
rank: int
79+
rank of element to retain
80+
rank = 0 -> minimum
81+
rank = -1 -> maximum
82+
rank = None -> median
83+
84+
Returns
85+
-------
86+
downscaled image
87+
"""
88+
89+
if not (isinstance(data, np.ndarray) and data.ndim in (2,3)):
90+
raise ValueError("input data has to be a 2d or 3d numpy array!")
91+
92+
if isinstance(size, Number):
93+
size = (int(size),)*data.ndim
94+
95+
if len(size) != data.ndim:
96+
raise ValueError("size has to be a tuple of 3 ints")
97+
98+
if rank is None:
99+
rank = np.prod(size) // 2
100+
else:
101+
rank = rank % np.prod(size)
102+
103+
data_g = OCLArray.from_array(data)
104+
105+
if data.ndim==2:
106+
res_g = _rank_downscale_2d(data_g, size=size, rank=rank)
107+
elif data.ndim==3:
108+
res_g = _rank_downscale_3d(data_g, size=size, rank=rank)
109+
else:
110+
raise ValueError("data has to be 2d or 3d")
111+
112+
return res_g.get()
113+
114+

gputools/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
77
"""
88

9-
__version__ = "0.2.15"
9+
__version__ = "0.2.16"

0 commit comments

Comments
 (0)