OpenCV Advent Calendar 2015 26日目
Random number generator. It encapsulates the state (currently, a 64-bit integer) and has methods to return scalar random values and to fill arrays with random values. Currently it supports uniform and Gaussian (normal) distributions. The generator uses Multiply-With-Carry algorithm, introduced by G. Marsaglia ( <http://en.wikipedia.org/wiki/Multiply-with-carry> ). Gaussian-distribution random numbers are generated using the Ziggurat algorithm ( <http://en.wikipedia.org/wiki/Ziggurat_algorithm> ), introduced by G. Marsaglia and W. W. Tsang.
乱数生成器。内部に状態を保持し(状態は64bit整数)、 乱数スカラ値を返し、もしくは行列を乱数で埋める。 現在サポートされてるのは一様分布とガウシアン(正規)分布。 生成器は内部でMultiply-With-Carryアルゴリズムを使う。 G. Marsaglia ( <http://en.wikipedia.org/wiki/Multiply-with-carry> ) 導出。 ガウシアン分布の乱数はZigguratのアルゴリズム ( <http://en.wikipedia.org/wiki/Ziggurat_algorithm> ) を実装している。
#geshi(C++){{
#include <iostream>
#include <iomanip>
#include <opencv2/core/core.hpp>
const uint64 initState = 0x1234354435;
int main() {
using namespace cv;
using namespace std;
RNG a(initState);
for(int i = 0;i < 10;i++)
{
unsigned int randomNumber = a.next();
cout << "0x" << std::hex << std::setw(8) << std::setfill('0') << randomNumber << endl;
}
return 0;
} }}
0xc4802924 0x6f670ec9 0x4ec21e44 0xe40ce671 0x5fcd40f9 0x3090cb5e 0x5d55db31 0x7145ce59 0xc5efc30e 0x7215b472
#geshi(C++){{ inline RNG::RNG(uint64 _state) { state = _state ? _state : 0xffffffff; } inline unsigned RNG::next() {
state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32); return (unsigned)state;} }}
#geshi(c++){{
int64 start = cv::getTickCount();
for(unsigned int i = 0;i < iteration;i++)
{
a.next();
}
int64 finish = getTickCount();
std::cout << "0x" << std::hex << a.next() << std::endl;
std::cout << (finish - start) * second2ms / getTickFrequency() << "ms for generating " << std::dec << cIteration << " random #" << std::endl;
std::cout << ((finish - start) * second2ms / getTickFrequency() / cIteration) << "ms / 1 random #" << std::endl;
}}0xd497e65c 1.5647ms for generating 1000000 random # 1.5647e-006ms / 1 random #
#geshi(c++){{ const unsigned int cIteration = 8000000; const double second2ms = 1000.0f; const double kSigma = 3.0f;
void checkEachBitVarianceGaussian(uint64 init, unsigned int iteration) {
using namespace cv;
RNG a(init);
double foo = a.gaussian(kSigma);
int64 start = cv::getTickCount();
for(unsigned int i = 0;i < iteration;i++)
{
a.gaussian(kSigma);
}
int64 finish = getTickCount();
foo = a.gaussian(kSigma);
std::cout << (finish - start) * second2ms / getTickFrequency() << "ms for generating " << cIteration << " gaussian distributed random #" << std::endl;
std::cout << ((finish - start) * second2ms / getTickFrequency() / cIteration) << "ms / 1 random #" << std::endl;
std::cout << foo << std::endl;
} }}
24.3736ms for generating 1000000 gaussian distributed random # 2.43736e-005ms / 1 random # -0.965316
#geshi(c++){{
using namespace cv;
RNG a(init);
unsigned int count[60]; //ヒストグラムのカウント
memset(count, 0, sizeof(unsigned int)*60);
// ヒストグラム作成
for(unsigned int i = 0;i < iteration;i++)
{
double foo = a.gaussian(kSigma);
int index = (int)(foo * 3 + 30);
index = index < 0 ? 0 : index;
index = index >= 60 ? 59 : index;
count[index]++;
}
// ヒストグラム出力
for(int i = 0;i < 60;i++)
{
std::cout << std::setw(2) << i << ' ' << ((double)(i-30)/3.0f) << '\t' << std::setw(7) << count[i] << std::endl;
}
}}#geshi(c++){{ Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi) {
Size size0 = size;
if( useRoi )
{
size0.width += std::max(rng.uniform(0, 10) - 5, 0);
size0.height += std::max(rng.uniform(0, 10) - 5, 0);
}Mat m(size0, type);
rng.fill(m, RNG::UNIFORM, minVal, maxVal); // ここで配列mを乱数で埋める
if( size0 == size )
return m;
return m(Rect((size0.width-size.width)/2, (size0.height-size.height)/2, size.width, size.height));
} }}