mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
Implementation of bit-exact resize. Internal calls to linear resize updated to use bit-exact version. (#9468)
This commit is contained in:
committed by
Vadim Pisarevsky
parent
84ee4d701a
commit
51cb56ef2c
@@ -0,0 +1,291 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
|
||||
|
||||
#ifndef _CV_FIXEDPOINT_HPP_
|
||||
#define _CV_FIXEDPOINT_HPP_
|
||||
|
||||
#include "opencv2/core/softfloat.hpp"
|
||||
|
||||
#ifndef CV_ALWAYS_INLINE
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define CV_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define CV_ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
#define CV_ALWAYS_INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class fixedpoint64
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 32;
|
||||
|
||||
int64_t val;
|
||||
fixedpoint64(int64_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint64_t fixedround(const uint64_t& _val) { return (_val + ((1LL << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef fixedpoint64 WT;
|
||||
CV_ALWAYS_INLINE fixedpoint64() { val = 0; }
|
||||
CV_ALWAYS_INLINE fixedpoint64(const int8_t& _val) { val = ((int64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint64(const int16_t& _val) { val = ((int64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint64(const int32_t& _val) { val = ((int64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint64(const cv::softdouble& _val) { val = cvRound64(_val * cv::softdouble((int64_t)(1LL << fixedShift))); }
|
||||
CV_ALWAYS_INLINE fixedpoint64& operator = (const int8_t& _val) { val = ((int64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint64& operator = (const int16_t& _val) { val = ((int64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint64& operator = (const int32_t& _val) { val = ((int64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint64& operator = (const cv::softdouble& _val) { val = cvRound64(_val * cv::softdouble((int64_t)(1LL << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint64& operator = (const fixedpoint64& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE fixedpoint64 operator * (const ET& val2) const { return val * val2; } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE fixedpoint64 operator * (const fixedpoint64& val2) const
|
||||
{
|
||||
//Assume -0x00000000C0000000 <= val2 <=0x0000000100000000 INT64_MIN <= val <= INT64_MAX, so shifted multiplication result is inside [INT64_MIN, INT64_MAX] range
|
||||
uint64_t uval = (uint64_t)((val ^ (val >> 63)) - (val >> 63));
|
||||
uint64_t umul = (uint64_t)((val2.val ^ (val2.val >> 63)) - (val2.val >> 63));
|
||||
int64_t ressign = (val >> 63) ^ (val2.val >> 63);
|
||||
|
||||
uint64_t sh0 = fixedround((uval & 0xFFFFFFFF) * (umul & 0xFFFFFFFF));
|
||||
uint64_t sh1_0 = (uval >> 32) * (umul & 0xFFFFFFFF);
|
||||
uint64_t sh1_1 = (uval & 0xFFFFFFFF) * (umul >> 32);
|
||||
uint64_t sh2 = (uval >> 32) * (umul >> 32);
|
||||
uint64_t val0_l = (sh1_0 & 0xFFFFFFFF) + (sh1_1 & 0xFFFFFFFF) + (sh0 >> 32);
|
||||
uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32);
|
||||
val0_l &= 0xFFFFFFFF;
|
||||
|
||||
if (ressign)
|
||||
{
|
||||
val0_l = (~val0_l + 1) & 0xFFFFFFFF;
|
||||
val0_h = val0_l ? ~val0_h : (~val0_h + 1);
|
||||
}
|
||||
return (int64_t)(val0_h << 32 | val0_l);
|
||||
}
|
||||
CV_ALWAYS_INLINE fixedpoint64 operator + (const fixedpoint64& val2) const { return fixedpoint64(val + val2.val); }
|
||||
CV_ALWAYS_INLINE fixedpoint64 operator - (const fixedpoint64& val2) const { return fixedpoint64(val - val2.val); }
|
||||
// CV_ALWAYS_INLINE fixedpoint64 operator + (const fixedpoint64& val2) const
|
||||
// {
|
||||
// int64_t nfrac = (int64_t)frac + val2.frac;
|
||||
// int64_t nval = (int64_t)val + val2.val + nfrac >> 32;
|
||||
// return nval > MAXINT32 ? beConv(MAXINT32, MAXINT32) : beConv((int32_t)(nval), 0);
|
||||
// }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int64_t)fixedround((uint64_t)val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE fixedpoint64 zero() { return fixedpoint64(); }
|
||||
static CV_ALWAYS_INLINE fixedpoint64 one() { return fixedpoint64((int64_t)(1LL << fixedShift)); }
|
||||
friend class fixedpoint32;
|
||||
};
|
||||
|
||||
class ufixedpoint64
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 32;
|
||||
|
||||
uint64_t val;
|
||||
ufixedpoint64(uint64_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint64_t fixedround(const uint64_t& _val) { return (_val + ((1LL << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef ufixedpoint64 WT;
|
||||
CV_ALWAYS_INLINE ufixedpoint64() { val = 0; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64(const uint8_t& _val) { val = ((uint64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64(const uint16_t& _val) { val = ((uint64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64(const uint32_t& _val) { val = ((uint64_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64(const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint64_t)cvRound64(_val * cv::softdouble((int64_t)(1LL << fixedShift))); }
|
||||
CV_ALWAYS_INLINE ufixedpoint64& operator = (const uint8_t& _val) { val = ((uint64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64& operator = (const uint16_t& _val) { val = ((uint64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64& operator = (const uint32_t& _val) { val = ((uint64_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64& operator = (const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint64_t)cvRound64(_val * cv::softdouble((int64_t)(1LL << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint64& operator = (const ufixedpoint64& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE ufixedpoint64 operator * (const ET& val2) const { return val * val2; } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE ufixedpoint64 operator * (const ufixedpoint64& val2) const
|
||||
{
|
||||
//Assume val2 <=0x0000000100000000, so shifted multiplication result is less than val and therefore than UINT64_MAX
|
||||
uint64_t sh0 = fixedround((val & 0xFFFFFFFF) * (val2.val & 0xFFFFFFFF));
|
||||
uint64_t sh1_0 = (val >> 32) * (val2.val & 0xFFFFFFFF);
|
||||
uint64_t sh1_1 = (val & 0xFFFFFFFF) * (val2.val >> 32);
|
||||
uint64_t sh2 = (val >> 32) * (val2.val >> 32);
|
||||
uint64_t val0_l = (sh1_0 & 0xFFFFFFFF) + (sh1_1 & 0xFFFFFFFF) + (sh0 >> 32);
|
||||
uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32);
|
||||
val0_l &= 0xFFFFFFFF;
|
||||
|
||||
return val0_h << 32 | val0_l;
|
||||
}
|
||||
CV_ALWAYS_INLINE ufixedpoint64 operator + (const ufixedpoint64& val2) const { return ufixedpoint64(val + val2.val); }
|
||||
CV_ALWAYS_INLINE ufixedpoint64 operator - (const ufixedpoint64& val2) const { return ufixedpoint64(val - val2.val); }
|
||||
// CV_ALWAYS_INLINE fixedpoint64 operator + (const fixedpoint64& val2) const
|
||||
// {
|
||||
// int64_t nfrac = (int64_t)frac + val2.frac;
|
||||
// int64_t nval = (int64_t)val + val2.val + nfrac >> 32;
|
||||
// return nval > MAXINT32 ? beConv(MAXINT32, MAXINT32) : beConv((int32_t)(nval), 0);
|
||||
// }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE ufixedpoint64 zero() { return ufixedpoint64(); }
|
||||
static CV_ALWAYS_INLINE ufixedpoint64 one() { return ufixedpoint64((uint64_t)(1ULL << fixedShift)); }
|
||||
friend class ufixedpoint32;
|
||||
};
|
||||
|
||||
class fixedpoint32
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 16;
|
||||
|
||||
int32_t val;
|
||||
fixedpoint32(int32_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint32_t fixedround(const uint32_t& _val) { return (_val + ((1 << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef fixedpoint64 WT;
|
||||
CV_ALWAYS_INLINE fixedpoint32() { val = 0; }
|
||||
CV_ALWAYS_INLINE fixedpoint32(const int8_t& _val) { val = ((int32_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint32(const uint8_t& _val) { val = ((int32_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint32(const int16_t& _val) { val = ((int32_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint32(const cv::softdouble& _val) { val = (int32_t)cvRound(_val * cv::softdouble((1 << fixedShift))); }
|
||||
CV_ALWAYS_INLINE fixedpoint32& operator = (const int8_t& _val) { val = ((int32_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint32& operator = (const uint8_t& _val) { val = ((int32_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint32& operator = (const int16_t& _val) { val = ((int32_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint32& operator = (const cv::softdouble& _val) { val = (int32_t)cvRound(_val * cv::softdouble((1 << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint32& operator = (const fixedpoint32& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE fixedpoint32 operator * (const ET& val2) const { return val * val2; } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE fixedpoint64 operator * (const fixedpoint32& val2) const { return (int64_t)val * (int64_t)(val2.val); }
|
||||
CV_ALWAYS_INLINE fixedpoint32 operator + (const fixedpoint32& val2) const { return fixedpoint32(val + val2.val); }
|
||||
CV_ALWAYS_INLINE fixedpoint32 operator - (const fixedpoint32& val2) const { return fixedpoint32(val - val2.val); }
|
||||
// CV_ALWAYS_INLINE fixedpoint32 operator + (const fixedpoint32& val2) const
|
||||
// {
|
||||
// int32_t nfrac = (int32_t)frac + val2.frac;
|
||||
// int32_t nval = (int32_t)val + val2.val + nfrac >> 32;
|
||||
// return nval > MAXINT32 ? beConv(MAXINT32, MAXINT32) : beConv((int32_t)(nval), 0);
|
||||
// }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int32_t)fixedround((uint32_t)val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE fixedpoint32 zero() { return fixedpoint32(); }
|
||||
static CV_ALWAYS_INLINE fixedpoint32 one() { return fixedpoint32((1 << fixedShift)); }
|
||||
friend class fixedpoint16;
|
||||
};
|
||||
|
||||
class ufixedpoint32
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 16;
|
||||
|
||||
uint32_t val;
|
||||
ufixedpoint32(uint32_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint32_t fixedround(const uint32_t& _val) { return (_val + ((1 << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef ufixedpoint64 WT;
|
||||
CV_ALWAYS_INLINE ufixedpoint32() { val = 0; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32(const uint8_t& _val) { val = ((uint32_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32(const uint16_t& _val) { val = ((uint32_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32(const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint32_t)cvRound(_val * cv::softdouble((1 << fixedShift))); }
|
||||
CV_ALWAYS_INLINE ufixedpoint32& operator = (const uint8_t& _val) { val = ((uint32_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32& operator = (const uint16_t& _val) { val = ((uint32_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32& operator = (const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint32_t)cvRound(_val * cv::softdouble((1 << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint32& operator = (const ufixedpoint32& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE ufixedpoint32 operator * (const ET& val2) const { return val * val2; } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE ufixedpoint64 operator * (const ufixedpoint32& val2) const { return (uint64_t)val * (uint64_t)(val2.val); }
|
||||
CV_ALWAYS_INLINE ufixedpoint32 operator + (const ufixedpoint32& val2) const { return ufixedpoint32(val + val2.val); }
|
||||
CV_ALWAYS_INLINE ufixedpoint32 operator - (const ufixedpoint32& val2) const { return ufixedpoint32(val - val2.val); }
|
||||
// CV_ALWAYS_INLINE fixedpoint32 operator + (const fixedpoint32& val2) const
|
||||
// {
|
||||
// int32_t nfrac = (int32_t)frac + val2.frac;
|
||||
// int32_t nval = (int32_t)val + val2.val + nfrac >> 32;
|
||||
// return nval > MAXINT32 ? beConv(MAXINT32, MAXINT32) : beConv((int32_t)(nval), 0);
|
||||
// }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE ufixedpoint32 zero() { return ufixedpoint32(); }
|
||||
static CV_ALWAYS_INLINE ufixedpoint32 one() { return ufixedpoint32((1U << fixedShift)); }
|
||||
friend class ufixedpoint16;
|
||||
};
|
||||
|
||||
class fixedpoint16
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 8;
|
||||
|
||||
int16_t val;
|
||||
fixedpoint16(int16_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint16_t fixedround(const uint16_t& _val) { return (_val + ((1 << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef fixedpoint32 WT;
|
||||
CV_ALWAYS_INLINE fixedpoint16() { val = 0; }
|
||||
CV_ALWAYS_INLINE fixedpoint16(const int8_t& _val) { val = ((int16_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint16(const uint8_t& _val) { val = ((int16_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE fixedpoint16(const cv::softdouble& _val) { val = (int16_t)cvRound(_val * cv::softdouble((1 << fixedShift))); }
|
||||
CV_ALWAYS_INLINE fixedpoint16& operator = (const int8_t& _val) { val = ((int16_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint16& operator = (const cv::softdouble& _val) { val = (int16_t)cvRound(_val * cv::softdouble((1 << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE fixedpoint16& operator = (const fixedpoint16& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE fixedpoint16 operator * (const ET& val2) const { return (int16_t)(val * val2); } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE fixedpoint32 operator * (const fixedpoint16& val2) const { return (int32_t)val * (int32_t)(val2.val); }
|
||||
CV_ALWAYS_INLINE fixedpoint16 operator + (const fixedpoint16& val2) const { return fixedpoint16((int16_t)(val + val2.val)); }
|
||||
CV_ALWAYS_INLINE fixedpoint16 operator - (const fixedpoint16& val2) const { return fixedpoint16((int16_t)(val - val2.val)); }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int16_t)fixedround((uint16_t)val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE fixedpoint16 zero() { return fixedpoint16(); }
|
||||
static CV_ALWAYS_INLINE fixedpoint16 one() { return fixedpoint16((int16_t)(1 << fixedShift)); }
|
||||
};
|
||||
|
||||
class ufixedpoint16
|
||||
{
|
||||
private:
|
||||
static const int fixedShift = 8;
|
||||
|
||||
uint16_t val;
|
||||
ufixedpoint16(uint16_t _val) : val(_val) {}
|
||||
static CV_ALWAYS_INLINE uint16_t fixedround(const uint16_t& _val) { return (_val + ((1 << fixedShift) >> 1)); }
|
||||
public:
|
||||
typedef ufixedpoint32 WT;
|
||||
CV_ALWAYS_INLINE ufixedpoint16() { val = 0; }
|
||||
CV_ALWAYS_INLINE ufixedpoint16(const uint8_t& _val) { val = ((uint16_t)_val) << fixedShift; }
|
||||
CV_ALWAYS_INLINE ufixedpoint16(const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint16_t)cvRound(_val * cv::softdouble((int32_t)(1 << fixedShift))); }
|
||||
CV_ALWAYS_INLINE ufixedpoint16& operator = (const uint8_t& _val) { val = ((uint16_t)_val) << fixedShift; return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint16& operator = (const cv::softdouble& _val) { val = _val.getSign() ? 0 : (uint16_t)cvRound(_val * cv::softdouble((int32_t)(1 << fixedShift))); return *this; }
|
||||
CV_ALWAYS_INLINE ufixedpoint16& operator = (const ufixedpoint16& _val) { val = _val.val; return *this; }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE ufixedpoint16 operator * (const ET& val2) const { return (uint16_t)(val * val2); } // Wrong rounding is possible for floating point types
|
||||
CV_ALWAYS_INLINE ufixedpoint32 operator * (const ufixedpoint16& val2) const { return ((uint32_t)val * (uint32_t)(val2.val)); }
|
||||
CV_ALWAYS_INLINE ufixedpoint16 operator + (const ufixedpoint16& val2) const { return ufixedpoint16((uint16_t)(val + val2.val)); }
|
||||
CV_ALWAYS_INLINE ufixedpoint16 operator - (const ufixedpoint16& val2) const { return ufixedpoint16((uint16_t)(val - val2.val)); }
|
||||
// CV_ALWAYS_INLINE fixedpoint16 operator + (const fixedpoint16& val2) const
|
||||
// {
|
||||
// int16_t nfrac = (int32_t)frac + val2.frac;
|
||||
// int16_t nval = (int32_t)val + val2.val + nfrac >> 16;
|
||||
// return nval > MAXINT32 ? beConv(MAXINT16, MAXINT16) : beConv((int16_t)(nval), 0);
|
||||
// }
|
||||
template <typename ET>
|
||||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); }
|
||||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); }
|
||||
CV_ALWAYS_INLINE bool isZero() { return val == 0; }
|
||||
static CV_ALWAYS_INLINE ufixedpoint16 zero() { return ufixedpoint16(); }
|
||||
static CV_ALWAYS_INLINE ufixedpoint16 one() { return ufixedpoint16((uint16_t)(1 << fixedShift)); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -453,7 +453,7 @@ void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines,
|
||||
Size ksize(1 + 2 * h, 1 + 2 * h); // kernel size
|
||||
GaussianBlur(image, gaussian_img, ksize, sigma);
|
||||
// Scale image to needed size
|
||||
resize(gaussian_img, scaled_image, Size(), SCALE, SCALE);
|
||||
resize(gaussian_img, scaled_image, Size(), SCALE, SCALE, INTER_LINEAR_EXACT);
|
||||
ll_angle(rho, N_BINS);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -50,12 +50,633 @@
|
||||
#include "precomp.hpp"
|
||||
#include "opencl_kernels_imgproc.hpp"
|
||||
#include "hal_replacement.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
#include "opencv2/core/openvx/ovx_defs.hpp"
|
||||
#include "resize.hpp"
|
||||
|
||||
#include "opencv2/core/softfloat.hpp"
|
||||
#include "fixedpoint.inl.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename ET, bool needsign> struct fixedtype { typedef fixedpoint64 type; };
|
||||
template <> struct fixedtype<uint32_t, false> { typedef ufixedpoint64 type; };
|
||||
template <bool needsign> struct fixedtype<int16_t, needsign> { typedef fixedpoint32 type; };
|
||||
template <> struct fixedtype<uint16_t, false> { typedef ufixedpoint32 type; };
|
||||
template <bool needsign> struct fixedtype<int8_t, needsign> { typedef fixedpoint32 type; };
|
||||
template <> struct fixedtype<uint8_t, false> { typedef ufixedpoint16 type; };
|
||||
|
||||
//FT is fixedtype<ET, needsign>::type
|
||||
template <typename ET, typename FT, int n, bool mulall>
|
||||
static void hlineResize(ET* src, int cn, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < dst_min; i++, m += n) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
for (int j = 0; j < cn; j++, dst++)
|
||||
{
|
||||
*dst = src[j];
|
||||
}
|
||||
}
|
||||
for (; i < dst_max; i++, m += n)
|
||||
{
|
||||
ET* src_ofst = src + cn*ofst[i];
|
||||
for (int j = 0; j < cn; j++, dst++)
|
||||
{
|
||||
*dst = (mulall || !m[0].isZero()) ? m[0] * src_ofst[j] : FT::zero();
|
||||
for (int k = 1; k < n; k++)
|
||||
{
|
||||
*dst = *dst + ((mulall || !m[k].isZero()) ? m[k] * src_ofst[j+k*cn] : FT::zero());
|
||||
}
|
||||
}
|
||||
}
|
||||
ET* src_last = src + cn*ofst[dst_width - 1];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
for (int j = 0; j < cn; j++, dst++)
|
||||
{
|
||||
*dst = src_last[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename ET, typename FT, int n, bool mulall, int cncnt> struct hline
|
||||
{
|
||||
static void ResizeCn(ET* src, int cn, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
hlineResize<ET, FT, n, mulall>(src, cn, ofst, m, dst, dst_min, dst_max, dst_width);
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 2, true, 1>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]);
|
||||
for (; i < dst_min; i++, m += 2) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 2)
|
||||
{
|
||||
ET* px = src + ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[1];
|
||||
}
|
||||
src0 = (src + ofst[dst_width - 1])[0];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 2, true, 2>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]);
|
||||
for (; i < dst_min; i++, m += 2) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 2)
|
||||
{
|
||||
ET* px = src + 2*ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[2];
|
||||
*(dst++) = m[0] * px[1] + m[1] * px[3];
|
||||
}
|
||||
src0 = (src + 2*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 2*ofst[dst_width - 1])[1];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 2, true, 3>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]), src2(src[2]);
|
||||
for (; i < dst_min; i++, m += 2) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 2)
|
||||
{
|
||||
ET* px = src + 3*ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[3];
|
||||
*(dst++) = m[0] * px[1] + m[1] * px[4];
|
||||
*(dst++) = m[0] * px[2] + m[1] * px[5];
|
||||
}
|
||||
src0 = (src + 3*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 3*ofst[dst_width - 1])[1];
|
||||
src2 = (src + 3*ofst[dst_width - 1])[2];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 2, true, 4>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]), src2(src[2]), src3(src[3]);
|
||||
for (; i < dst_min; i++, m += 2) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
*(dst++) = src3;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 2)
|
||||
{
|
||||
ET* px = src + 4*ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[4];
|
||||
*(dst++) = m[0] * px[1] + m[1] * px[5];
|
||||
*(dst++) = m[0] * px[2] + m[1] * px[6];
|
||||
*(dst++) = m[0] * px[3] + m[1] * px[7];
|
||||
}
|
||||
src0 = (src + 4*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 4*ofst[dst_width - 1])[1];
|
||||
src2 = (src + 4*ofst[dst_width - 1])[2];
|
||||
src3 = (src + 4*ofst[dst_width - 1])[3];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
*(dst++) = src3;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 4, true, 1>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]);
|
||||
for (; i < dst_min; i++, m += 4) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 4)
|
||||
{
|
||||
ET* px = src + ofst[i];
|
||||
*(dst++) = m[0] * src[0] + m[1] * src[1] + m[2] * src[2] + m[3] * src[3];
|
||||
}
|
||||
src0 = (src + ofst[dst_width - 1])[0];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 4, true, 2>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]);
|
||||
for (; i < dst_min; i++, m += 4) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 4)
|
||||
{
|
||||
ET* px = src + 2*ofst[i];
|
||||
*(dst++) = m[0] * src[0] + m[1] * src[2] + m[2] * src[4] + m[3] * src[6];
|
||||
*(dst++) = m[0] * src[1] + m[1] * src[3] + m[2] * src[5] + m[3] * src[7];
|
||||
}
|
||||
src0 = (src + 2*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 2*ofst[dst_width - 1])[1];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 4, true, 3>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]), src2(src[2]);
|
||||
for (; i < dst_min; i++, m += 4) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 4)
|
||||
{
|
||||
ET* px = src + 3*ofst[i];
|
||||
*(dst++) = m[0] * src[0] + m[1] * src[3] + m[2] * src[6] + m[3] * src[ 9];
|
||||
*(dst++) = m[0] * src[1] + m[1] * src[4] + m[2] * src[7] + m[3] * src[10];
|
||||
*(dst++) = m[0] * src[2] + m[1] * src[5] + m[2] * src[8] + m[3] * src[11];
|
||||
}
|
||||
src0 = (src + 3*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 3*ofst[dst_width - 1])[1];
|
||||
src2 = (src + 3*ofst[dst_width - 1])[2];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT> struct hline<ET, FT, 4, true, 4>
|
||||
{
|
||||
static void ResizeCn(ET* src, int, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
FT src0(src[0]), src1(src[1]), src2(src[2]), src3(src[3]);
|
||||
for (; i < dst_min; i++, m += 4) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
*(dst++) = src3;
|
||||
}
|
||||
for (; i < dst_max; i++, m += 4)
|
||||
{
|
||||
ET* px = src + 4*ofst[i];
|
||||
*(dst++) = m[0] * src[0] + m[1] * src[4] + m[2] * src[ 8] + m[3] * src[12];
|
||||
*(dst++) = m[0] * src[1] + m[1] * src[5] + m[2] * src[ 9] + m[3] * src[13];
|
||||
*(dst++) = m[0] * src[2] + m[1] * src[6] + m[2] * src[10] + m[3] * src[14];
|
||||
*(dst++) = m[0] * src[3] + m[1] * src[7] + m[2] * src[11] + m[3] * src[15];
|
||||
}
|
||||
src0 = (src + 4*ofst[dst_width - 1])[0];
|
||||
src1 = (src + 4*ofst[dst_width - 1])[1];
|
||||
src2 = (src + 4*ofst[dst_width - 1])[2];
|
||||
src3 = (src + 4*ofst[dst_width - 1])[3];
|
||||
for (; i < dst_width; i++) // Points that fall right from src image so became equal to rightmost src point
|
||||
{
|
||||
*(dst++) = src0;
|
||||
*(dst++) = src1;
|
||||
*(dst++) = src2;
|
||||
*(dst++) = src3;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename ET, typename FT, int n, bool mulall, int cncnt>
|
||||
static void hlineResizeCn(ET* src, int cn, int *ofst, FT* m, FT* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
hline<ET, FT, n, mulall, cncnt>::ResizeCn(src, cn, ofst, m, dst, dst_min, dst_max, dst_width);
|
||||
};
|
||||
|
||||
template <>
|
||||
void hlineResizeCn<uint8_t, ufixedpoint16, 2, true, 1>(uint8_t* src, int, int *ofst, ufixedpoint16* m, ufixedpoint16* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
int i = 0;
|
||||
ufixedpoint16 src_0(src[0]);
|
||||
v_uint16x8 v_src_0 = v_setall_u16(*((uint16_t*)&src_0));
|
||||
for (; i < dst_min - 7; i += 8, m += 16, dst += 8) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
v_store((uint16_t*)dst, v_src_0);
|
||||
}
|
||||
for (; i < dst_min; i++, m += 2)
|
||||
{
|
||||
*(dst++) = src_0;
|
||||
}
|
||||
for (; i < dst_max - 7 && ofst[i + 7] + 15 <= ofst[dst_width - 1]; i += 8, m += 16, dst += 8)
|
||||
{
|
||||
v_uint32x4 v_src01 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 1])));
|
||||
v_uint32x4 v_src23 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 2])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 3])));
|
||||
v_uint32x4 v_src45 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 4])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 5])));
|
||||
v_uint32x4 v_src67 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 6])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 7])));
|
||||
|
||||
v_uint32x4 v_zip02, v_zip13, v_zip46, v_zip57;
|
||||
v_zip(v_src01, v_src23, v_zip02, v_zip13);
|
||||
v_zip(v_src45, v_src67, v_zip46, v_zip57);
|
||||
|
||||
v_uint32x4 v_src0, v_src1;
|
||||
v_zip(v_combine_low(v_zip02, v_zip46), v_combine_low(v_zip13, v_zip57), v_src0, v_src1);
|
||||
|
||||
v_int16x8 v_mul0 = v_load((int16_t*)m);
|
||||
v_int16x8 v_mul1 = v_load((int16_t*)m + 8);
|
||||
v_uint32x4 v_res0 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src0), v_mul0));
|
||||
v_uint32x4 v_res1 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src1), v_mul1));
|
||||
v_store((uint16_t*)dst, v_pack(v_res0, v_res1));
|
||||
}
|
||||
for (; i < dst_max; i += 1, m += 2)
|
||||
{
|
||||
uint8_t* px = src + ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[1];
|
||||
}
|
||||
src_0 = (src + ofst[dst_width - 1])[0];
|
||||
v_src_0 = v_setall_u16(*((uint16_t*)&src_0));
|
||||
for (; i < dst_width - 7; i += 8, dst += 8) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
v_store((uint16_t*)dst, v_src_0);
|
||||
}
|
||||
for (; i < dst_width; i++)
|
||||
{
|
||||
*(dst++) = src_0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void hlineResizeCn<uint16_t, ufixedpoint32, 2, true, 1>(uint16_t* src, int, int *ofst, ufixedpoint32* m, ufixedpoint32* dst, int dst_min, int dst_max, int dst_width)
|
||||
{
|
||||
typedef v_uint32x4 v_fixedtype;
|
||||
typedef uint32_t lanetype;
|
||||
int i = 0;
|
||||
ufixedpoint32 src_0(src[0]);
|
||||
v_fixedtype v_src_0 = v_setall_u32(*((lanetype*)&src_0));
|
||||
for (; i < dst_min - 3; i += 4, m += 8, dst += 4) // Points that fall left from src image so became equal to leftmost src point
|
||||
{
|
||||
v_store((lanetype*)dst, v_src_0);
|
||||
}
|
||||
for (; i < dst_min; i++, m += 2)
|
||||
{
|
||||
*(dst++) = src_0;
|
||||
}
|
||||
for (; i < dst_max - 3 && ofst[i + 3] + 8 <= ofst[dst_width - 1]; i += 4, m += 8, dst += 4)
|
||||
{
|
||||
v_fixedtype v_src0 = v_combine_low(v_load_expand(src + ofst[i]), v_load_expand(src + ofst[i + 1]));
|
||||
v_fixedtype v_mul0 = v_load((lanetype*)m);
|
||||
v_fixedtype v_src1 = v_combine_low(v_load_expand(src + ofst[i + 2]), v_load_expand(src + ofst[i + 3]));
|
||||
v_fixedtype v_mul1 = v_load((lanetype*)m + 4);
|
||||
v_fixedtype v_res0 = v_src0 * v_mul0;//a1a2b1b2
|
||||
v_fixedtype v_res1 = v_src1 * v_mul1;//c1c2d1d2
|
||||
v_fixedtype v_tmp0, v_tmp1;
|
||||
v_recombine(v_res0, v_res1, v_tmp0, v_tmp1);//a1a2c1c2 b1b2d1d2
|
||||
v_zip(v_tmp0, v_tmp1, v_res0, v_res1);//a1b1a2b2 c1d1c2d2
|
||||
v_recombine(v_res0, v_res1, v_tmp0, v_tmp1);//a1b1c1d1 a2b2c2d2
|
||||
v_store((lanetype*)dst, v_tmp0 + v_tmp1);//abcd
|
||||
}
|
||||
for (; i < dst_max; i += 1, m += 2)
|
||||
{
|
||||
uint16_t* px = src + ofst[i];
|
||||
*(dst++) = m[0] * px[0] + m[1] * px[1];
|
||||
}
|
||||
src_0 = (src + ofst[dst_width - 1])[0];
|
||||
v_src_0 = v_setall_u32(*((lanetype*)&src_0));
|
||||
for (; i < dst_width - 3; i += 4, dst += 4)
|
||||
{
|
||||
v_store((lanetype*)dst, v_src_0);
|
||||
}
|
||||
for (; i < dst_width; i++)
|
||||
{
|
||||
*(dst++) = src_0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ET, typename FT>
|
||||
void vlineSet(FT* src, ET* dst, int dst_width)
|
||||
{
|
||||
for (int i = 0; i < dst_width; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
template <>
|
||||
void vlineSet<uint8_t, ufixedpoint16>(ufixedpoint16* src, uint8_t* dst, int dst_width)
|
||||
{
|
||||
static const v_uint16x8 v_fixedRound = v_setall_u16((uint16_t)((1U << 8) >> 1));
|
||||
int i = 0;
|
||||
for (; i < dst_width - 15; i += 16, src += 16, dst += 16)
|
||||
{
|
||||
v_uint16x8 v_src0 = v_load((uint16_t*)src);
|
||||
v_uint16x8 v_src1 = v_load((uint16_t*)src + 8);
|
||||
|
||||
v_uint16x8 v_res0 = (v_src0 + v_fixedRound) >> 8;
|
||||
v_uint16x8 v_res1 = (v_src1 + v_fixedRound) >> 8;
|
||||
|
||||
v_store(dst, v_pack(v_res0, v_res1));
|
||||
}
|
||||
for (; i < dst_width; i++)
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
|
||||
template <typename ET, typename FT, int n>
|
||||
void vlineResize(FT* src, size_t src_step, FT* m, ET* dst, int dst_width)
|
||||
{
|
||||
for (int i = 0; i < dst_width; i++)
|
||||
{
|
||||
typename FT::WT res = src[i] * m[0];
|
||||
for (int k = 1; k < n; k++)
|
||||
res = res + src[i + k*src_step] * m[k];
|
||||
dst[i] = res;
|
||||
}
|
||||
}
|
||||
template <>
|
||||
void vlineResize<uint8_t, ufixedpoint16, 2>(ufixedpoint16* src, size_t src_step, ufixedpoint16* m, uint8_t* dst, int dst_width)
|
||||
{
|
||||
static const v_int32x4 v_fixedRound = v_setall_s32((int32_t)((1 << 16) >> 1));
|
||||
static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1<<15));
|
||||
static const v_int8x16 v_128_16 = v_reinterpret_as_s8 (v_setall_u8 ((uint8_t) 1<<7));
|
||||
|
||||
int i = 0;
|
||||
ufixedpoint16* src1 = src + src_step;
|
||||
v_int16x8 v_mul = v_reinterpret_as_s16(v_setall_u32(((uint32_t*)m)[0]));
|
||||
for (; i < dst_width - 15; i += 16, src += 16, src1 += 16, dst += 16)
|
||||
{
|
||||
v_int16x8 v_src00 = v_load((int16_t*)src);
|
||||
v_int16x8 v_src10 = v_load((int16_t*)src1);
|
||||
v_int16x8 v_tmp0, v_tmp1;
|
||||
v_zip(v_add_wrap(v_src00,v_128), v_add_wrap(v_src10,v_128), v_tmp0, v_tmp1);
|
||||
|
||||
v_int32x4 v_res0 = v_dotprod(v_tmp0, v_mul);
|
||||
v_int32x4 v_res1 = v_dotprod(v_tmp1, v_mul);
|
||||
|
||||
v_int16x8 v_src01 = v_load((int16_t*)src + 8);
|
||||
v_int16x8 v_src11 = v_load((int16_t*)src1 + 8);
|
||||
v_zip(v_add_wrap(v_src01,v_128), v_add_wrap(v_src11,v_128), v_tmp0, v_tmp1);
|
||||
v_int32x4 v_res2 = v_dotprod(v_tmp0, v_mul);
|
||||
v_int32x4 v_res3 = v_dotprod(v_tmp1, v_mul);
|
||||
|
||||
v_int8x16 v_res = v_pack(v_pack((v_res0 + v_fixedRound) >> 16,
|
||||
(v_res1 + v_fixedRound) >> 16),
|
||||
v_pack((v_res2 + v_fixedRound) >> 16,
|
||||
(v_res3 + v_fixedRound) >> 16));
|
||||
|
||||
v_store(dst, v_reinterpret_as_u8(v_sub_wrap(v_res, v_128_16)));
|
||||
}
|
||||
for (; i < dst_width; i++)
|
||||
{
|
||||
*(dst++) = (uint8_t)(*(src++) * m[0] + *(src1++) * m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ET> class interpolationLinear
|
||||
{
|
||||
public:
|
||||
static const int len = 2;
|
||||
static const bool needsign = false;
|
||||
interpolationLinear(double inv_scale, int srcsize, int dstsize) : scale(softdouble::one() / softdouble(inv_scale)), maxsize(srcsize), minofst(0), maxofst(dstsize) {}
|
||||
void getCoeffs(int val, int* offset, typename fixedtype<ET, needsign>::type* coeffs)
|
||||
{
|
||||
typedef typename fixedtype<ET, needsign>::type fixedpoint;
|
||||
softdouble fval = scale*(softdouble(val)+softdouble(0.5))-softdouble(0.5);
|
||||
int ival = cvFloor(fval);
|
||||
if (ival >= 0 && maxsize > 1)
|
||||
{
|
||||
if (ival < maxsize - 1)
|
||||
{
|
||||
*offset = ival;
|
||||
coeffs[1] = fval - softdouble(ival);
|
||||
coeffs[0] = fixedpoint::one() - coeffs[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
*offset = maxsize - 1;
|
||||
maxofst = min(maxofst, val);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
minofst = max(minofst, val + 1);
|
||||
}
|
||||
}
|
||||
void getMinMax(int &min, int &max)
|
||||
{
|
||||
min = minofst;
|
||||
max = maxofst;
|
||||
}
|
||||
protected:
|
||||
softdouble scale;
|
||||
int maxsize;
|
||||
int minofst, maxofst;
|
||||
};
|
||||
|
||||
template <typename ET, typename FT, int interp_y_len>
|
||||
class resize_bitExactInvoker :
|
||||
public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
typedef FT fixedpoint;
|
||||
typedef void(*hResizeFunc)(ET* src, int cn, int *ofst, fixedpoint* m, fixedpoint* dst, int dst_min, int dst_max, int dst_width);
|
||||
resize_bitExactInvoker(const uchar* _src, size_t _src_step, int _src_width, int _src_height,
|
||||
uchar* _dst, size_t _dst_step, int _dst_width, int _dst_height,
|
||||
int _cn, int *_xoffsets, int *_yoffsets, fixedpoint *_xcoeffs, fixedpoint *_ycoeffs,
|
||||
int _min_x, int _max_x, int _min_y, int _max_y, hResizeFunc _hResize) : ParallelLoopBody(),
|
||||
src(_src), src_step(_src_step), src_width(_src_width), src_height(_src_height),
|
||||
dst(_dst), dst_step(_dst_step), dst_width(_dst_width), dst_height(_dst_height),
|
||||
cn(_cn), xoffsets(_xoffsets), yoffsets(_yoffsets), xcoeffs(_xcoeffs), ycoeffs(_ycoeffs),
|
||||
min_x(_min_x), max_x(_max_x), min_y(_min_y), max_y(_max_y), hResize(_hResize) {}
|
||||
|
||||
virtual void operator() (const Range& range) const
|
||||
{
|
||||
AutoBuffer<fixedpoint> linebuf(interp_y_len * dst_width * cn);
|
||||
int last_eval = - interp_y_len;
|
||||
int evalbuf_start = 0;
|
||||
int rmin_y = max(min_y, range.start);
|
||||
int rmax_y = min(max_y, range.end);
|
||||
if (range.start < min_y)
|
||||
{
|
||||
last_eval = 1 - interp_y_len;
|
||||
evalbuf_start = 1;
|
||||
hResize((ET*)src, cn, xoffsets, xcoeffs, (fixedpoint*)linebuf, min_x, max_x, dst_width);
|
||||
}
|
||||
int dy = range.start;
|
||||
for (; dy < rmin_y; dy++)
|
||||
vlineSet<ET, FT>((fixedpoint*)linebuf, (ET*)(dst + dst_step * dy), dst_width*cn);
|
||||
for (; dy < rmax_y; dy++)
|
||||
{
|
||||
int &iy = yoffsets[dy];
|
||||
|
||||
int i;
|
||||
for (i = max(iy, last_eval + interp_y_len); i < min(iy + interp_y_len, src_height); i++, evalbuf_start = (evalbuf_start + 1) % interp_y_len)
|
||||
hResize((ET*)(src + i * src_step), cn, xoffsets, xcoeffs, (fixedpoint*)linebuf + evalbuf_start*(dst_width * cn), min_x, max_x, dst_width);
|
||||
evalbuf_start = (evalbuf_start + max(iy, src_height - interp_y_len) - max(last_eval, src_height - interp_y_len)) % interp_y_len;
|
||||
last_eval = iy;
|
||||
|
||||
fixedpoint curcoeffs[interp_y_len];
|
||||
for (i = 0; i < evalbuf_start; i++)
|
||||
curcoeffs[i] = ycoeffs[ dy*interp_y_len - evalbuf_start + interp_y_len + i];
|
||||
for (; i < interp_y_len; i++)
|
||||
curcoeffs[i] = ycoeffs[ dy*interp_y_len - evalbuf_start + i];
|
||||
|
||||
vlineResize<ET, FT, interp_y_len>((fixedpoint*)linebuf, dst_width*cn, curcoeffs, (ET*)(dst + dst_step * dy), dst_width*cn);
|
||||
}
|
||||
fixedpoint *endline = (fixedpoint*)linebuf;
|
||||
if (last_eval + interp_y_len > src_height)
|
||||
endline += dst_width*cn*((evalbuf_start + src_height - 1 - last_eval) % interp_y_len);
|
||||
else
|
||||
hResize((ET*)(src + (src_height - 1) * src_step), cn, xoffsets, xcoeffs, endline, min_x, max_x, dst_width);
|
||||
for (; dy < range.end; dy++)
|
||||
vlineSet<ET, FT>(endline, (ET*)(dst + dst_step * dy), dst_width*cn);
|
||||
}
|
||||
|
||||
private:
|
||||
const uchar* src;
|
||||
size_t src_step;
|
||||
int src_width, src_height;
|
||||
uchar* dst;
|
||||
size_t dst_step;
|
||||
int dst_width, dst_height, cn;
|
||||
int *xoffsets, *yoffsets;
|
||||
fixedpoint *xcoeffs, *ycoeffs;
|
||||
int min_x, max_x, min_y, max_y;
|
||||
hResizeFunc hResize;
|
||||
|
||||
resize_bitExactInvoker(const resize_bitExactInvoker&);
|
||||
resize_bitExactInvoker& operator=(const resize_bitExactInvoker&);
|
||||
};
|
||||
|
||||
template <typename ET, typename interpolation>
|
||||
void resize_bitExact(const uchar* src, size_t src_step, int src_width, int src_height,
|
||||
uchar* dst, size_t dst_step, int dst_width, int dst_height,
|
||||
int cn, double inv_scale_x, double inv_scale_y)
|
||||
{
|
||||
typedef typename fixedtype<ET, interpolation::needsign>::type fixedpoint;
|
||||
void(*hResize)(ET* src, int cn, int *ofst, fixedpoint* m, fixedpoint* dst, int dst_min, int dst_max, int dst_width);
|
||||
switch (cn)
|
||||
{
|
||||
case 1: hResize = src_width > interpolation::len ? hlineResizeCn<ET, fixedpoint, interpolation::len, true, 1> : hlineResizeCn<ET, fixedpoint, interpolation::len, false, 1>; break;
|
||||
case 2: hResize = src_width > interpolation::len ? hlineResizeCn<ET, fixedpoint, interpolation::len, true, 2> : hlineResizeCn<ET, fixedpoint, interpolation::len, false, 2>; break;
|
||||
case 3: hResize = src_width > interpolation::len ? hlineResizeCn<ET, fixedpoint, interpolation::len, true, 3> : hlineResizeCn<ET, fixedpoint, interpolation::len, false, 3>; break;
|
||||
case 4: hResize = src_width > interpolation::len ? hlineResizeCn<ET, fixedpoint, interpolation::len, true, 4> : hlineResizeCn<ET, fixedpoint, interpolation::len, false, 4>; break;
|
||||
default: hResize = src_width > interpolation::len ? hlineResize<ET, fixedpoint, interpolation::len, true> : hlineResize<ET, fixedpoint, interpolation::len, false> ; break;
|
||||
}
|
||||
|
||||
interpolation interp_x(inv_scale_x, src_width, dst_width);
|
||||
interpolation interp_y(inv_scale_y, src_height, dst_height);
|
||||
|
||||
AutoBuffer<uchar> buf( dst_width * sizeof(int) +
|
||||
dst_height * sizeof(int) +
|
||||
dst_width * interp_x.len*sizeof(fixedpoint) +
|
||||
dst_height * interp_y.len * sizeof(fixedpoint) );
|
||||
int* xoffsets = (int*)((uchar*)buf);
|
||||
int* yoffsets = xoffsets + dst_width;
|
||||
fixedpoint* xcoeffs = (fixedpoint*)(yoffsets + dst_height);
|
||||
fixedpoint* ycoeffs = xcoeffs + dst_width * interp_x.len;
|
||||
|
||||
int min_x, max_x, min_y, max_y;
|
||||
for (int dx = 0; dx < dst_width; dx++)
|
||||
interp_x.getCoeffs(dx, xoffsets+dx, xcoeffs+dx*interp_x.len);
|
||||
interp_x.getMinMax(min_x, max_x);
|
||||
for (int dy = 0; dy < dst_height; dy++)
|
||||
interp_y.getCoeffs(dy, yoffsets+dy, ycoeffs+dy*interp_y.len);
|
||||
interp_y.getMinMax(min_y, max_y);
|
||||
|
||||
resize_bitExactInvoker<ET, fixedpoint, interpolation::len> invoker(src, src_step, src_width, src_height, dst, dst_step, dst_width, dst_height, cn,
|
||||
xoffsets, yoffsets, xcoeffs, ycoeffs, min_x, max_x, min_y, max_y, hResize);
|
||||
Range range(0, dst_height);
|
||||
parallel_for_(range, invoker, dst_width * dst_height / (double)(1 << 16));
|
||||
}
|
||||
|
||||
typedef void(*be_resize_func)(const uchar* src, size_t src_step, int src_width, int src_height,
|
||||
uchar* dst, size_t dst_step, int dst_width, int dst_height,
|
||||
int cn, double inv_scale_x, double inv_scale_y);
|
||||
|
||||
}
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
@@ -89,7 +710,7 @@ static inline void interpolateLanczos4( float x, float* coeffs )
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
double y0=-(x+3)*CV_PI*0.25, s0 = sin(y0), c0=cos(y0);
|
||||
double y0=-(x+3)*CV_PI*0.25, s0 = std::sin(y0), c0= std::cos(y0);
|
||||
for(int i = 0; i < 8; i++ )
|
||||
{
|
||||
double y = -(x+3-i)*CV_PI*0.25;
|
||||
@@ -3066,6 +3687,18 @@ void resize(int src_type,
|
||||
resizeArea_<double, double>, 0
|
||||
};
|
||||
|
||||
static be_resize_func linear_exact_tab[] =
|
||||
{
|
||||
resize_bitExact<uchar, interpolationLinear<uchar> >,
|
||||
resize_bitExact<schar, interpolationLinear<schar> >,
|
||||
resize_bitExact<ushort, interpolationLinear<ushort> >,
|
||||
resize_bitExact<short, interpolationLinear<short> >,
|
||||
resize_bitExact<int, interpolationLinear<int> >,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
double scale_x = 1./inv_scale_x, scale_y = 1./inv_scale_y;
|
||||
|
||||
int iscale_x = saturate_cast<int>(scale_x);
|
||||
@@ -3077,6 +3710,23 @@ void resize(int src_type,
|
||||
Mat src(Size(src_width, src_height), src_type, const_cast<uchar*>(src_data), src_step);
|
||||
Mat dst(dsize, src_type, dst_data, dst_step);
|
||||
|
||||
if (interpolation == INTER_LINEAR_EXACT)
|
||||
{
|
||||
// in case of inv_scale_x && inv_scale_y is equal to 0.5
|
||||
// INTER_AREA (fast) is equal to bit exact INTER_LINEAR
|
||||
if (is_area_fast && iscale_x == 2 && iscale_y == 2)
|
||||
interpolation = INTER_AREA;
|
||||
else
|
||||
{
|
||||
be_resize_func func = linear_exact_tab[depth];
|
||||
CV_Assert(func != 0);
|
||||
func(src_data, src_step, src_width, src_height,
|
||||
dst_data, dst_step, dst_width, dst_height,
|
||||
cn, inv_scale_x, inv_scale_y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( interpolation == INTER_NEAREST )
|
||||
{
|
||||
resizeNN( src, dst, inv_scale_x, inv_scale_y );
|
||||
|
||||
Reference in New Issue
Block a user