提交 586ff429 编写于 作者: V Vadim Pisarevsky

fixed bug #1318. extended RNG::fill with the optional saturateRange parameter

上级 ee8c4aeb
......@@ -2564,7 +2564,7 @@ RNG::fill
-------------
Fills arrays with random numbers.
.. ocv:function:: void RNG::fill( InputOutputArray mat, int distType, InputArray a, InputArray b )
.. ocv:function:: void RNG::fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )
:param mat: 2D or N-dimensional matrix. Currently matrices with more than 4 channels are not supported by the methods. Use :ocv:func:`Mat::reshape` as a possible workaround.
......@@ -2573,6 +2573,8 @@ Fills arrays with random numbers.
:param a: First distribution parameter. In case of the uniform distribution, this is an inclusive lower boundary. In case of the normal distribution, this is a mean value.
:param b: Second distribution parameter. In case of the uniform distribution, this is a non-inclusive upper boundary. In case of the normal distribution, this is a standard deviation (diagonal of the standard deviation matrix or the full standard deviation matrix).
:param saturateRange: Pre-saturation flag; for uniform distribution only. If it is true, the method will first convert a and b to the acceptable value range (according to the mat datatype) and then will generate uniformly distributed random numbers within the range ``[saturate(a), saturate(b))``. If ``saturateRange=false``, the method will generate uniformly distributed random numbers in the original range ``[a, b)`` and then will saturate them. It means, for example, that ``theRNG().fill(mat_8u, RNG::UNIFORM, -DBL_MAX, DBL_MAX)`` will likely produce array mostly filled with 0's and 255's, since the range ``(0, 255)`` is significantly smaller than ``[-DBL_MAX, DBL_MAX)``.
Each of the methods fills the matrix with the random values from the specified distribution. As the new numbers are generated, the RNG state is updated accordingly. In case of multiple-channel images, every channel is filled independently, which means that RNG cannot generate samples from the multi-dimensional Gaussian distribution with non-diagonal covariance matrix directly. To do that, the method generates samples from multi-dimensional standard Gaussian distribution with zero mean and identity covariation matrix, and then transforms them using :ocv:func:`transform` to get samples from the specified Gaussian distribution.
......
......@@ -1979,7 +1979,7 @@ public:
float uniform(float a, float b);
//! returns uniformly distributed double-precision floating-point random number from [a,b) range
double uniform(double a, double b);
void fill( InputOutputArray mat, int distType, InputArray a, InputArray b );
void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false );
//! returns Gaussian random variate with mean zero.
double gaussian(double sigma);
......
......@@ -443,7 +443,8 @@ static RandnScaleFunc randnScaleTab[] =
(RandnScaleFunc)randnScale_64f, 0
};
void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, InputArray _param2arg )
void RNG::fill( InputOutputArray _mat, int disttype,
InputArray _param1arg, InputArray _param2arg, bool saturateRange )
{
Mat mat = _mat.getMat(), _param1 = _param1arg.getMat(), _param2 = _param2arg.getMat();
int depth = mat.depth(), cn = mat.channels();
......@@ -505,6 +506,13 @@ void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, Inpu
{
double a = min(p1[j], p2[j]);
double b = max(p1[j], p2[j]);
if( saturateRange )
{
a = max(a, depth == CV_8U || depth == CV_16U ? 0. :
depth == CV_8S ? -128. : depth == CV_16S ? -32768. : (double)INT_MIN);
b = min(b, depth == CV_8U ? 256. : depth == CV_16U ? 65536. :
depth == CV_8S ? 128. : depth == CV_16S ? 32768. : (double)INT_MAX);
}
ip[j][1] = cvCeil(a);
int idiff = ip[j][0] = cvFloor(b) - ip[j][1] - 1;
double diff = b - a;
......@@ -512,6 +520,13 @@ void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, Inpu
fast_int_mode &= diff <= 4294967296. && (idiff & (idiff+1)) == 0;
if( fast_int_mode )
smallFlag &= idiff <= 255;
else
{
if( diff > INT_MAX )
ip[j][0] = INT_MAX;
if( a < INT_MIN/2 )
ip[j][1] = INT_MIN/2;
}
}
if( !fast_int_mode )
......@@ -537,6 +552,7 @@ void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, Inpu
double scale = depth == CV_64F ?
5.4210108624275221700372640043497e-20 : // 2**-64
2.3283064365386962890625e-10; // 2**-32
double maxdiff = saturateRange ? (double)FLT_MAX : DBL_MAX;
// for each channel i compute such dparam[0][i] & dparam[1][i],
// so that a signed 32/64-bit integer X is transformed to
......@@ -547,7 +563,7 @@ void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, Inpu
fp = (Vec2f*)(parambuf + cn*2);
for( j = 0; j < cn; j++ )
{
fp[j][0] = (float)((p2[j] - p1[j])*scale);
fp[j][0] = (float)(std::min(maxdiff, p2[j] - p1[j])*scale);
fp[j][1] = (float)((p2[j] + p1[j])*0.5);
}
}
......@@ -556,7 +572,7 @@ void RNG::fill( InputOutputArray _mat, int disttype, InputArray _param1arg, Inpu
dp = (Vec2d*)(parambuf + cn*2);
for( j = 0; j < cn; j++ )
{
dp[j][0] = ((p2[j] - p1[j])*scale);
dp[j][0] = std::min(DBL_MAX, p2[j] - p1[j])*scale;
dp[j][1] = ((p2[j] + p1[j])*0.5);
}
}
......
......@@ -301,3 +301,37 @@ void Core_RandTest::run( int )
TEST(Core_Rand, quality) { Core_RandTest test; test.safe_run(); }
class Core_RandRangeTest : public cvtest::BaseTest
{
public:
Core_RandRangeTest() {}
~Core_RandRangeTest() {}
protected:
void run(int)
{
Mat a(Size(1280, 720), CV_8U, Scalar(20));
Mat af(Size(1280, 720), CV_32F, Scalar(20));
theRNG().fill(a, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
theRNG().fill(af, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
int n0 = 0, n255 = 0, nx = 0;
int nfmin = 0, nfmax = 0, nfx = 0;
for( int i = 0; i < a.rows; i++ )
for( int j = 0; j < a.cols; j++ )
{
int v = a.at<uchar>(i,j);
double vf = af.at<float>(i,j);
if( v == 0 ) n0++;
else if( v == 255 ) n255++;
else nx++;
if( vf < FLT_MAX*-0.999f ) nfmin++;
else if( vf > FLT_MAX*0.999f ) nfmax++;
else nfx++;
}
CV_Assert( n0 > nx*2 && n255 > nx*2 );
CV_Assert( nfmin > nfx*2 && nfmax > nfx*2 );
}
};
TEST(Core_Rand, range) { Core_RandRangeTest test; test.safe_run(); }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册