mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
added basic support for CV_16F (the new datatype etc.) (#12463)
* added basic support for CV_16F (the new datatype etc.). CV_USRTYPE1 is now equal to CV_16F, which may break some [rarely used] functionality. We'll see * fixed just introduced bug in norm; reverted errorneous changes in Torch importer (need to find a better solution) * addressed some issues found during the PR review * restored the patch to fix some perf test failures
This commit is contained in:
+50
-167
@@ -48,18 +48,6 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#if defined _WIN32 || defined WINCE
|
||||
#include <windows.h>
|
||||
#undef small
|
||||
#undef min
|
||||
#undef max
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP)
|
||||
#include "emmintrin.h"
|
||||
#endif
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
@@ -74,12 +62,6 @@ namespace cv
|
||||
|
||||
#define RNG_NEXT(x) ((uint64)(unsigned)(x)*CV_RNG_COEFF + ((x) >> 32))
|
||||
|
||||
#ifdef __PPC64__
|
||||
#define PPC_MUL_ADD(ret, tmp, p0, p1) \
|
||||
asm volatile("fmuls %0,%1,%2\n\t fadds %0,%0,%3" : "=&f" (ret) \
|
||||
: "f" (tmp), "f" (p0), "f" (p1))
|
||||
#endif
|
||||
|
||||
/***************************************************************************************\
|
||||
* Pseudo-Random Number Generators (PRNGs) *
|
||||
\***************************************************************************************/
|
||||
@@ -154,59 +136,26 @@ template<typename T> static void
|
||||
randi_( T* arr, int len, uint64* state, const DivStruct* p )
|
||||
{
|
||||
uint64 temp = *state;
|
||||
int i = 0;
|
||||
unsigned t0, t1, v0, v1;
|
||||
|
||||
for( i = 0; i <= len - 4; i += 4 )
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
temp = RNG_NEXT(temp);
|
||||
t0 = (unsigned)temp;
|
||||
temp = RNG_NEXT(temp);
|
||||
t1 = (unsigned)temp;
|
||||
v0 = (unsigned)(((uint64)t0 * p[i].M) >> 32);
|
||||
v1 = (unsigned)(((uint64)t1 * p[i+1].M) >> 32);
|
||||
v0 = (v0 + ((t0 - v0) >> p[i].sh1)) >> p[i].sh2;
|
||||
v1 = (v1 + ((t1 - v1) >> p[i+1].sh1)) >> p[i+1].sh2;
|
||||
v0 = t0 - v0*p[i].d + p[i].delta;
|
||||
v1 = t1 - v1*p[i+1].d + p[i+1].delta;
|
||||
arr[i] = saturate_cast<T>((int)v0);
|
||||
arr[i+1] = saturate_cast<T>((int)v1);
|
||||
|
||||
temp = RNG_NEXT(temp);
|
||||
t0 = (unsigned)temp;
|
||||
temp = RNG_NEXT(temp);
|
||||
t1 = (unsigned)temp;
|
||||
v0 = (unsigned)(((uint64)t0 * p[i+2].M) >> 32);
|
||||
v1 = (unsigned)(((uint64)t1 * p[i+3].M) >> 32);
|
||||
v0 = (v0 + ((t0 - v0) >> p[i+2].sh1)) >> p[i+2].sh2;
|
||||
v1 = (v1 + ((t1 - v1) >> p[i+3].sh1)) >> p[i+3].sh2;
|
||||
v0 = t0 - v0*p[i+2].d + p[i+2].delta;
|
||||
v1 = t1 - v1*p[i+3].d + p[i+3].delta;
|
||||
arr[i+2] = saturate_cast<T>((int)v0);
|
||||
arr[i+3] = saturate_cast<T>((int)v1);
|
||||
unsigned t = (unsigned)temp;
|
||||
unsigned v = (unsigned)(((uint64)t * p[i].M) >> 32);
|
||||
v = (v + ((t - v) >> p[i].sh1)) >> p[i].sh2;
|
||||
v = t - v*p[i].d + p[i].delta;
|
||||
arr[i] = saturate_cast<T>((int)v);
|
||||
}
|
||||
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
temp = RNG_NEXT(temp);
|
||||
t0 = (unsigned)temp;
|
||||
v0 = (unsigned)(((uint64)t0 * p[i].M) >> 32);
|
||||
v0 = (v0 + ((t0 - v0) >> p[i].sh1)) >> p[i].sh2;
|
||||
v0 = t0 - v0*p[i].d + p[i].delta;
|
||||
arr[i] = saturate_cast<T>((int)v0);
|
||||
}
|
||||
|
||||
*state = temp;
|
||||
}
|
||||
|
||||
|
||||
#define DEF_RANDI_FUNC(suffix, type) \
|
||||
static void randBits_##suffix(type* arr, int len, uint64* state, \
|
||||
const Vec2i* p, bool small_flag) \
|
||||
const Vec2i* p, void*, bool small_flag) \
|
||||
{ randBits_(arr, len, state, p, small_flag); } \
|
||||
\
|
||||
static void randi_##suffix(type* arr, int len, uint64* state, \
|
||||
const DivStruct* p, bool ) \
|
||||
const DivStruct* p, void*, bool ) \
|
||||
{ randi_(arr, len, state, p); }
|
||||
|
||||
DEF_RANDI_FUNC(8u, uchar)
|
||||
@@ -215,131 +164,62 @@ DEF_RANDI_FUNC(16u, ushort)
|
||||
DEF_RANDI_FUNC(16s, short)
|
||||
DEF_RANDI_FUNC(32s, int)
|
||||
|
||||
static void randf_32f( float* arr, int len, uint64* state, const Vec2f* p, bool )
|
||||
static void randf_32f( float* arr, int len, uint64* state, const Vec2f* p, void*, bool )
|
||||
{
|
||||
uint64 temp = *state;
|
||||
int i = 0;
|
||||
|
||||
for( ; i <= len - 4; i += 4 )
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
float f[4];
|
||||
f[0] = (float)(int)(temp = RNG_NEXT(temp));
|
||||
f[1] = (float)(int)(temp = RNG_NEXT(temp));
|
||||
f[2] = (float)(int)(temp = RNG_NEXT(temp));
|
||||
f[3] = (float)(int)(temp = RNG_NEXT(temp));
|
||||
|
||||
// handwritten SSE is required not for performance but for numerical stability!
|
||||
// both 32-bit gcc and MSVC compilers trend to generate double precision SSE
|
||||
// while 64-bit compilers generate single precision SIMD instructions
|
||||
// so manual vectorisation forces all compilers to the single precision
|
||||
#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP)
|
||||
__m128 q0 = _mm_loadu_ps((const float*)(p + i));
|
||||
__m128 q1 = _mm_loadu_ps((const float*)(p + i + 2));
|
||||
|
||||
__m128 q01l = _mm_unpacklo_ps(q0, q1);
|
||||
__m128 q01h = _mm_unpackhi_ps(q0, q1);
|
||||
|
||||
__m128 p0 = _mm_unpacklo_ps(q01l, q01h);
|
||||
__m128 p1 = _mm_unpackhi_ps(q01l, q01h);
|
||||
|
||||
_mm_storeu_ps(arr + i, _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(f), p0), p1));
|
||||
#elif defined __ARM_NEON && defined __aarch64__
|
||||
// handwritten NEON is required not for performance but for numerical stability!
|
||||
// 64bit gcc tends to use fmadd instead of separate multiply and add
|
||||
// use volatile to ensure to separate the multiply and add
|
||||
float32x4x2_t q = vld2q_f32((const float*)(p + i));
|
||||
|
||||
float32x4_t p0 = q.val[0];
|
||||
float32x4_t p1 = q.val[1];
|
||||
|
||||
volatile float32x4_t v0 = vmulq_f32(vld1q_f32(f), p0);
|
||||
vst1q_f32(arr+i, vaddq_f32(v0, p1));
|
||||
#elif defined __PPC64__
|
||||
// inline asm is required for numerical stability!
|
||||
// compilers tends to use floating multiply-add single(fmadds)
|
||||
// instead of separate multiply and add
|
||||
PPC_MUL_ADD(arr[i+0], f[0], p[i+0][0], p[i+0][1]);
|
||||
PPC_MUL_ADD(arr[i+1], f[1], p[i+1][0], p[i+1][1]);
|
||||
PPC_MUL_ADD(arr[i+2], f[2], p[i+2][0], p[i+2][1]);
|
||||
PPC_MUL_ADD(arr[i+3], f[3], p[i+3][0], p[i+3][1]);
|
||||
#else
|
||||
arr[i+0] = f[0]*p[i+0][0] + p[i+0][1];
|
||||
arr[i+1] = f[1]*p[i+1][0] + p[i+1][1];
|
||||
arr[i+2] = f[2]*p[i+2][0] + p[i+2][1];
|
||||
arr[i+3] = f[3]*p[i+3][0] + p[i+3][1];
|
||||
#endif
|
||||
int t = (int)(temp = RNG_NEXT(temp));
|
||||
arr[i] = (float)(t*p[i][0]);
|
||||
}
|
||||
|
||||
for( ; i < len; i++ )
|
||||
{
|
||||
temp = RNG_NEXT(temp);
|
||||
#if defined __SSE2__ || (defined _M_IX86_FP && 2 == _M_IX86_FP)
|
||||
_mm_store_ss(arr + i, _mm_add_ss(
|
||||
_mm_mul_ss(_mm_set_ss((float)(int)temp), _mm_set_ss(p[i][0])),
|
||||
_mm_set_ss(p[i][1]))
|
||||
);
|
||||
#elif defined __ARM_NEON && defined __aarch64__
|
||||
float32x2_t t = vadd_f32(vmul_f32(
|
||||
vdup_n_f32((float)(int)temp), vdup_n_f32(p[i][0])),
|
||||
vdup_n_f32(p[i][1]));
|
||||
arr[i] = vget_lane_f32(t, 0);
|
||||
#elif defined __PPC64__
|
||||
PPC_MUL_ADD(arr[i], (float)(int)temp, p[i][0], p[i][1]);
|
||||
#else
|
||||
arr[i] = (int)temp*p[i][0] + p[i][1];
|
||||
#endif
|
||||
}
|
||||
|
||||
*state = temp;
|
||||
}
|
||||
|
||||
// add bias separately to make the generated random numbers
|
||||
// more deterministic, independent of
|
||||
// architecture details (FMA instruction use etc.)
|
||||
hal::addRNGBias32f(arr, &p[0][0], len);
|
||||
}
|
||||
|
||||
static void
|
||||
randf_64f( double* arr, int len, uint64* state, const Vec2d* p, bool )
|
||||
randf_64f( double* arr, int len, uint64* state, const Vec2d* p, void*, bool )
|
||||
{
|
||||
uint64 temp = *state;
|
||||
int64 v = 0;
|
||||
int i;
|
||||
|
||||
for( i = 0; i <= len - 4; i += 4 )
|
||||
{
|
||||
double f0, f1;
|
||||
|
||||
temp = RNG_NEXT(temp);
|
||||
v = (temp >> 32)|(temp << 32);
|
||||
f0 = v*p[i][0] + p[i][1];
|
||||
temp = RNG_NEXT(temp);
|
||||
v = (temp >> 32)|(temp << 32);
|
||||
f1 = v*p[i+1][0] + p[i+1][1];
|
||||
arr[i] = f0; arr[i+1] = f1;
|
||||
|
||||
temp = RNG_NEXT(temp);
|
||||
v = (temp >> 32)|(temp << 32);
|
||||
f0 = v*p[i+2][0] + p[i+2][1];
|
||||
temp = RNG_NEXT(temp);
|
||||
v = (temp >> 32)|(temp << 32);
|
||||
f1 = v*p[i+3][0] + p[i+3][1];
|
||||
arr[i+2] = f0; arr[i+3] = f1;
|
||||
}
|
||||
|
||||
for( ; i < len; i++ )
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
temp = RNG_NEXT(temp);
|
||||
v = (temp >> 32)|(temp << 32);
|
||||
arr[i] = v*p[i][0] + p[i][1];
|
||||
int64 v = (temp >> 32)|(temp << 32);
|
||||
arr[i] = v*p[i][0];
|
||||
}
|
||||
|
||||
*state = temp;
|
||||
|
||||
hal::addRNGBias64f(arr, &p[0][0], len);
|
||||
}
|
||||
|
||||
typedef void (*RandFunc)(uchar* arr, int len, uint64* state, const void* p, bool small_flag);
|
||||
static void randf_16f( float16_t* arr, int len, uint64* state, const Vec2f* p, float* fbuf, bool )
|
||||
{
|
||||
uint64 temp = *state;
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
float f = (float)(int)(temp = RNG_NEXT(temp));
|
||||
fbuf[i] = f*p[i][0];
|
||||
}
|
||||
*state = temp;
|
||||
|
||||
// add bias separately to make the generated random numbers
|
||||
// more deterministic, independent of
|
||||
// architecture details (FMA instruction use etc.)
|
||||
hal::addRNGBias32f(fbuf, &p[0][0], len);
|
||||
hal::cvt32f16f(fbuf, arr, len);
|
||||
}
|
||||
|
||||
typedef void (*RandFunc)(uchar* arr, int len, uint64* state, const void* p, void* tempbuf, bool small_flag);
|
||||
|
||||
|
||||
static RandFunc randTab[][8] =
|
||||
{
|
||||
{
|
||||
(RandFunc)randi_8u, (RandFunc)randi_8s, (RandFunc)randi_16u, (RandFunc)randi_16s,
|
||||
(RandFunc)randi_32s, (RandFunc)randf_32f, (RandFunc)randf_64f, 0
|
||||
(RandFunc)randi_32s, (RandFunc)randf_32f, (RandFunc)randf_64f, (RandFunc)randf_16f
|
||||
},
|
||||
{
|
||||
(RandFunc)randBits_8u, (RandFunc)randBits_8s, (RandFunc)randBits_16u, (RandFunc)randBits_16s,
|
||||
@@ -350,7 +230,7 @@ static RandFunc randTab[][8] =
|
||||
/*
|
||||
The code below implements the algorithm described in
|
||||
"The Ziggurat Method for Generating Random Variables"
|
||||
by Marsaglia and Tsang, Journal of Statistical Software.
|
||||
by George Marsaglia and Wai Wan Tsang, Journal of Statistical Software, 2007.
|
||||
*/
|
||||
static void
|
||||
randn_0_1_32f( float* arr, int len, uint64* state )
|
||||
@@ -631,8 +511,8 @@ void RNG::fill( InputOutputArray _mat, int disttype,
|
||||
// for each channel i compute such dparam[0][i] & dparam[1][i],
|
||||
// so that a signed 32/64-bit integer X is transformed to
|
||||
// the range [param1.val[i], param2.val[i]) using
|
||||
// dparam[1][i]*X + dparam[0][i]
|
||||
if( depth == CV_32F )
|
||||
// dparam[0][i]*X + dparam[1][i]
|
||||
if( depth != CV_64F )
|
||||
{
|
||||
fp = (Vec2f*)(parambuf + cn*2);
|
||||
for( j = 0; j < cn; j++ )
|
||||
@@ -704,6 +584,7 @@ void RNG::fill( InputOutputArray _mat, int disttype,
|
||||
AutoBuffer<double> buf;
|
||||
uchar* param = 0;
|
||||
float* nbuf = 0;
|
||||
float* tmpbuf = 0;
|
||||
|
||||
if( disttype == UNIFORM )
|
||||
{
|
||||
@@ -727,12 +608,14 @@ void RNG::fill( InputOutputArray _mat, int disttype,
|
||||
p[j + k] = ip[k];
|
||||
}
|
||||
}
|
||||
else if( depth == CV_32F )
|
||||
else if( depth != CV_64F )
|
||||
{
|
||||
Vec2f* p = (Vec2f*)param;
|
||||
for( j = 0; j < blockSize*cn; j += cn )
|
||||
for( k = 0; k < cn; k++ )
|
||||
p[j + k] = fp[k];
|
||||
if( depth == CV_16F )
|
||||
tmpbuf = (float*)p + blockSize*cn*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -755,7 +638,7 @@ void RNG::fill( InputOutputArray _mat, int disttype,
|
||||
int len = std::min(total - j, blockSize);
|
||||
|
||||
if( disttype == CV_RAND_UNI )
|
||||
func( ptr, len*cn, &state, param, smallFlag );
|
||||
func( ptr, len*cn, &state, param, tmpbuf, smallFlag );
|
||||
else
|
||||
{
|
||||
randn_0_1_32f(nbuf, len*cn, &state);
|
||||
|
||||
Reference in New Issue
Block a user