/******************************************************* * Copyright (c) 2017, ArrayFire * All rights reserved. * * This file is distributed under 3-clause BSD license. * The complete license agreement can be obtained at: * http://arrayfire.com/licenses/BSD-3-Clause ********************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include using af::dim4; using detail::arithOp; using detail::Array; using detail::cast; using detail::createEmptyArray; using detail::gradient; using detail::reduce_all; template af_array diffusion(const Array& in, const float dt, const float K, const unsigned iterations, const af_flux_function fftype, const af::diffusionEq eq) { auto out = copyArray(in); auto dims = out.dims(); auto g0 = createEmptyArray(dims); auto g1 = createEmptyArray(dims); float cnst = -2.0f * K * K / dims.elements(); // NOLINT(readability-magic-numbers) for (unsigned i = 0; i < iterations; ++i) { gradient(g0, g1, out); auto g0Sqr = arithOp(g0, g0, dims); auto g1Sqr = arithOp(g1, g1, dims); auto sumd = arithOp(g0Sqr, g1Sqr, dims); float avg = reduce_all(sumd, true, 0); anisotropicDiffusion(out, dt, 1.0f / (cnst * avg), fftype, eq); } return getHandle(cast(out)); } af_err af_anisotropic_diffusion(af_array* out, const af_array in, const float dt, const float K, const unsigned iterations, const af_flux_function fftype, const af_diffusion_eq eq) { try { const ArrayInfo& info = getInfo(in); const af::dim4& inputDimensions = info.dims(); const af_dtype inputType = info.getType(); const unsigned inputNumDims = inputDimensions.ndims(); DIM_ASSERT(1, (inputNumDims >= 2)); ARG_ASSERT(3, (K > 0 || K < 0)); ARG_ASSERT(4, (iterations > 0)); const af_flux_function F = (fftype == AF_FLUX_DEFAULT ? AF_FLUX_EXPONENTIAL : fftype); auto input = castArray(in); af_array output = nullptr; switch (inputType) { case f64: output = diffusion(input, dt, K, iterations, F, eq); break; case f32: case s32: case u32: case s16: case u16: case u8: output = diffusion(input, dt, K, iterations, F, eq); break; default: TYPE_ERROR(1, inputType); } std::swap(*out, output); } CATCHALL; return AF_SUCCESS; }