/** * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * * License Agreement * For Open Source Computer Vision Library * (3-clause BSD License) * * Copyright (C) 2000-2020, Intel Corporation, all rights reserved. * Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. * Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. * Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. * Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. * Copyright (C) 2015-2016, Itseez Inc., all rights reserved. * Copyright (C) 2019-2020, Xperience AI, all rights reserved. * Third party copyrights are property of their respective owners. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the names of the copyright holders nor the names of the contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * This software is provided by the copyright holders and contributors "as is" and * any express or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose are disclaimed. * In no event shall copyright holders or contributors be liable for any direct, * indirect, incidental, special, exemplary, or consequential damages * (including, but not limited to, procurement of substitute goods or services; * loss of use, data, or profits; or business interruption) however caused * and on any theory of liability, whether in contract, strict liability, * or tort (including negligence or otherwise) arising in any way out of * the use of this software, even if advised of the possibility of such damage. * * --------------------------------------------------------------------------- * \file dnn/src/common/cv/interp_helper.cpp * * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * This file has been modified by Megvii ("Megvii Modifications"). * All Megvii Modifications are Copyright (C) 2014-2021 Megvii Inc. All rights reserved. * * --------------------------------------------------------------------------- */ #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" // TableHolderBase has no problem; ignore the warning for old clang versions #include "./interp_helper.h" using namespace megdnn; using namespace megdnn::megcv; static constexpr double MEGCV_PI_4 = 0.78539816339744830962; /* pi/4 */ #define DEF_FUN(_ret) \ template \ _ret InterpolationTable:: #define DEF_TABLE_HOLDER(_name, _ksize) \ template \ typename InterpolationTable< \ INTER_BITS_, INTER_MAX_, \ INTER_REMAP_COEF_BITS_>::template TableHolder<_ksize> \ InterpolationTable::_name DEF_TABLE_HOLDER(sm_tab_linear, 2); DEF_TABLE_HOLDER(sm_tab_cubic, 4); DEF_TABLE_HOLDER(sm_tab_lanczos4, 8); DEF_FUN(void) interpolate_linear(float x, float* coeffs) { coeffs[0] = 1.f - x; coeffs[1] = x; } DEF_FUN(void) interpolate_cubic(float x, float* coeffs) { const float A = -0.75f; coeffs[0] = ((A * (x + 1) - 5 * A) * (x + 1) + 8 * A) * (x + 1) - 4 * A; coeffs[1] = ((A + 2) * x - (A + 3)) * x * x + 1; coeffs[2] = ((A + 2) * (1 - x) - (A + 3)) * (1 - x) * (1 - x) + 1; coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2]; } DEF_FUN(void) interpolate_lanczos4(float x, float* coeffs) { static const double s45 = 0.70710678118654752440084436210485; static const double cs[][2] = {{1, 0}, {-s45, -s45}, {0, 1}, {s45, -s45}, {-1, 0}, {s45, s45}, {0, -1}, {-s45, s45}}; if (x < FLT_EPSILON) { for (int i = 0; i < 8; i++) coeffs[i] = 0; coeffs[3] = 1; return; } float sum = 0; double y0 = -(x + 3) * MEGCV_PI_4, s0 = sin(y0), c0 = cos(y0); for (int i = 0; i < 8; i++) { double y = -(x + 3 - i) * MEGCV_PI_4; coeffs[i] = (float)((cs[i][0] * s0 + cs[i][1] * c0) / (y * y)); sum += coeffs[i]; } sum = 1.f / sum; for (int i = 0; i < 8; i++) coeffs[i] *= sum; } DEF_FUN(void) init_inter_tab_1d(InterpolationMode imode, float* tab, int tabsz) { float scale = 1.f / tabsz; switch (imode) { case IMode::INTER_LINEAR: for (int i = 0; i < tabsz; ++i, tab += 2) interpolate_linear(i * scale, tab); break; case IMode::INTER_CUBIC: for (int i = 0; i < tabsz; ++i, tab += 4) interpolate_cubic(i * scale, tab); break; case IMode::INTER_LANCZOS4: for (int i = 0; i < tabsz; ++i, tab += 8) interpolate_lanczos4(i * scale, tab); break; default: megdnn_throw("unsupported interpolation mode"); } } #if MEGDNN_X86 DEF_FUN(const int16_t*) get_linear_ic4_table() { auto table_holder = &sm_tab_linear; MEGDNN_LOCK_GUARD(table_holder->mtx); float* tab = nullptr; short* itab = nullptr; MEGDNN_MARK_USED_VAR(tab); MEGDNN_MARK_USED_VAR(itab); megdnn_assert(table_holder->get(&tab, &itab), "invoke get_table before get_linear_ic4_table"); return table_holder->table->bilineartab_ic4_buf; } #endif DEF_FUN(const void*) get_table(InterpolationMode imode, bool fixpt) { TableHolderBase* table_holder = nullptr; int ksize = 0; switch (imode) { case IMode::INTER_LINEAR: table_holder = &sm_tab_linear; ksize = 2; break; case IMode::INTER_CUBIC: table_holder = &sm_tab_cubic; ksize = 4; break; case IMode::INTER_LANCZOS4: table_holder = &sm_tab_lanczos4; ksize = 8; break; default: megdnn_throw(("unsupported interpolation mode")); } MEGDNN_LOCK_GUARD(table_holder->mtx); float* tab = nullptr; short* itab = nullptr; if (!table_holder->get(&tab, &itab)) { float _tab[8 * INTER_TAB_SIZE]; int i, j, k1, k2; init_inter_tab_1d(imode, _tab, INTER_TAB_SIZE); for (i = 0; i < INTER_TAB_SIZE; ++i) { for (j = 0; j < INTER_TAB_SIZE; ++j, tab += ksize * ksize, itab += ksize * ksize) { int isum = 0; for (k1 = 0; k1 < ksize; ++k1) { float vy = _tab[i * ksize + k1]; for (k2 = 0; k2 < ksize; ++k2) { float v = vy * _tab[j * ksize + k2]; tab[k1 * ksize + k2] = v; isum += itab[k1 * ksize + k2] = saturate_cast( v * INTER_REMAP_COEF_SCALE); } } if (isum != INTER_REMAP_COEF_SCALE) { int diff = isum - INTER_REMAP_COEF_SCALE; int ksize2 = ksize / 2, Mk1 = ksize2, Mk2 = ksize2; int mk1 = ksize2, mk2 = ksize2; for (k1 = ksize2; k1 < ksize2 + 2; ++k1) for (k2 = ksize2; k2 < ksize2 + 2; ++k2) { if (itab[k1 * ksize + k2] < itab[mk1 * ksize + mk2]) { mk1 = k1; mk2 = k2; } else if (itab[k1 * ksize + k2] > itab[Mk1 * ksize + Mk2]) { Mk1 = k1; Mk2 = k2; } } if (diff < 0) itab[Mk1 * ksize + Mk2] = (short)(itab[Mk1 * ksize + Mk2] - diff); else itab[mk1 * ksize + mk2] = (short)(itab[mk1 * ksize + mk2] - diff); } } } tab -= INTER_TAB_SIZE2 * ksize * ksize; itab -= INTER_TAB_SIZE2 * ksize * ksize; #if MEGDNN_X86 if (imode == IMode::INTER_LINEAR) { int16_t* bilineartab_ic4_buf = sm_tab_linear.table->bilineartab_ic4_buf; for (i = 0; i < INTER_TAB_SIZE2; i++) for (j = 0; j < 4; j++) { bilineartab_ic4_buf[i * 2 * 8 + 0 * 8 + j * 2] = itab[i * ksize * ksize + 0 * ksize + 0]; bilineartab_ic4_buf[i * 2 * 8 + 0 * 8 + j * 2 + 1] = itab[i * ksize * ksize + 0 * ksize + 1]; bilineartab_ic4_buf[i * 2 * 8 + 1 * 8 + j * 2] = itab[i * ksize * ksize + 1 * ksize + 0]; bilineartab_ic4_buf[i * 2 * 8 + 1 * 8 + j * 2 + 1] = itab[i * ksize * ksize + 1 * ksize + 1]; } } #endif } return fixpt ? static_cast(itab) : static_cast(tab); } namespace megdnn { namespace megcv { // explicit inst template class InterpolationTable<5, 7, 15>; } // namespace megcv } // namespace megdnn // vim: syntax=cpp.doxygen