-------------
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.
: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.
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);
(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();
{
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;
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 )
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
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);
}
}
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);
}
}
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(); }
+