| 154 | |
| 155 | template<typename InputType, typename RealType = float> |
| 156 | af_array iterDeconv(const af_array in, const af_array ker, const uint iters, |
| 157 | const float rfactor, const af_iterative_deconv_algo algo) { |
| 158 | using T = RealType; |
| 159 | using CT = typename std::conditional<std::is_same<T, double>::value, |
| 160 | cdouble, cfloat>::type; |
| 161 | auto input = castArray<T>(in); |
| 162 | auto psf = castArray<T>(ker); |
| 163 | const dim4& idims = input.dims(); |
| 164 | const dim4& fdims = psf.dims(); |
| 165 | dim_t nElems = 1; |
| 166 | |
| 167 | dim4 inUPad, psfUPad, inLPad, psfLPad, odims(1); |
| 168 | |
| 169 | auto index = calcPadInfo(inLPad, psfLPad, inUPad, psfUPad, odims, nElems, |
| 170 | idims, fdims); |
| 171 | auto paddedIn = |
| 172 | padArrayBorders<T>(input, inLPad, inUPad, AF_PAD_CLAMP_TO_EDGE); |
| 173 | auto paddedPsf = padArrayBorders<T>(psf, psfLPad, psfUPad, AF_PAD_ZERO); |
| 174 | |
| 175 | const std::array<int, 4> shiftDims = {-int(fdims[0] / 2), |
| 176 | -int(fdims[1] / 2), 0, 0}; |
| 177 | auto shiftedPsf = shift(paddedPsf, shiftDims.data()); |
| 178 | |
| 179 | auto P = fft_r2c<CT, T>(shiftedPsf, BASE_DIM); |
| 180 | auto Pc = conj(P); |
| 181 | |
| 182 | Array<T> currentEstimate = paddedIn; |
| 183 | const double normFactor = 1 / static_cast<double>(nElems); |
| 184 | |
| 185 | switch (algo) { |
| 186 | case AF_ITERATIVE_DECONV_RICHARDSONLUCY: |
| 187 | richardsonLucy(currentEstimate, paddedIn, P, Pc, iters, normFactor, |
| 188 | odims); |
| 189 | break; |
| 190 | case AF_ITERATIVE_DECONV_LANDWEBER: |
| 191 | default: |
| 192 | landweber(currentEstimate, paddedIn, P, Pc, iters, rfactor, |
| 193 | normFactor, odims); |
| 194 | } |
| 195 | return getHandle(createSubArray<T>(currentEstimate, index)); |
| 196 | } |
| 197 | |
| 198 | af_err af_iterative_deconv(af_array* out, const af_array in, const af_array ker, |
| 199 | const unsigned iterations, const float relax_factor, |
nothing calls this directly
no test coverage detected