#
# This file is part of fluid3d - a software for image registration
#
# Copyright (c) Madrid 2013
#
# fluid3d is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fluid3d; if not, see <http://www.gnu.org/licenses/>.
#
#
import numpy as np
import pyopencl as cl
import pyopencl.array as cl_array
from OpenCLHelpers import read_cl_program
from GaussKernel import create_gausskernel
class C3DDownscaler:
"""This class encapsulates a 3D image downscaler. The output size is
defined based on the input sizes divided by the given scales.
The output sizes can be padded to a length of multiples of four in order to
make sure the processing parallized well.
"""
def __init__(self, ctx, queue, inv_scales, img_format):
self.inv_scales = inv_scales
self.ctx = ctx
self.queue = queue
self.prog = read_cl_program(ctx, "downscale3d.cl").build()
self.img_format = img_format
khs = [int(round(iscale/2)) for iscale in inv_scales]
khs.append(0)
self.kernel_half_sizes = np.array(tuple(khs), dtype=cl_array.vec.int4)
k0 = create_gausskernel(khs[0])
k1 = create_gausskernel(khs[1])
k2 = create_gausskernel(khs[2])
k0 = k0.reshape((k0.size, 1, 1))
k1 = k1.reshape((1, k1.size, 1))
k2 = k2.reshape((1, 1, k2.size))
kernel = k0 * k1 * k2;
kernel = kernel.reshape(1,1, kernel.size)[0][0]
self.kernel_dev = cl_array.to_device(queue, kernel)
inv_scales.append(0)
self.scales_dev = np.array(tuple(inv_scales), dtype=cl_array.vec.float4)
def run(self, in_image_dev):
"""Downscale the input image stored on the computing device by the parameters
the filter was initialized with. The functions returned the downscaled image
stored on the computing device"""
out_shape = tuple([int(round(ai / bi))
for ai, bi in zip(in_image_dev.shape, self.inv_scales)])
out_image_dev = cl.Image(self.ctx, cl.mem_flags.WRITE_ONLY, self.img_format, out_shape)
self.prog.downscale3d(self.queue, out_shape, None , out_image_dev, in_image_dev,
self.kernel_dev.data, self.kernel_half_sizes, self.scales_dev)
return out_image_dev
def run_padded(self, in_image_dev):
"""Downscale the input image stored on the computing device by the parameters
the filter was initialized with. Pad the output so that all axis directions have length
of multiples of four, thereby assuring the processing on this images can be parallized well.
The padding is achieved by adding zeros on the high index positions of the index domain.
The functions returned the downscaled image stored on the computing device"""
out_shape = tuple([int(round(ai / bi))
for ai, bi in zip(in_image_dev.shape, self.inv_scales)])
real_out_shape = tuple([((i + 3) & 0xFFFFFFFC) for i in out_shape])
out_image_dev = cl.Image(self.ctx, cl.mem_flags.WRITE_ONLY, self.img_format, real_out_shape)
self.prog.downscale3d(self.queue, out_shape, None , out_image_dev, in_image_dev,
self.kernel_dev.data, self.kernel_half_sizes, self.scales_dev)
return (out_image_dev, out_shape)