在这篇教程可以学会:
- 使用随机数发生器RNG类以及如何获取服从均匀分布的随机数
- 使用putText在OpenCV窗口上显示文本
目录
1 关于RNG类
core.hpp中关于RNG类声明:
/*!
Random Number Generator
The class implements RNG using Multiply-with-Carry algorithm
*/
class CV_EXPORTS RNG
{
public:
enum { UNIFORM=0, NORMAL=1 };
RNG();
RNG(uint64 state);
//! updates the state and returns the next 32-bit unsigned integer random number
unsigned next();
operator uchar();
operator schar();
operator ushort();
operator short();
operator unsigned();
//! returns a random integer sampled uniformly from [0, N).
unsigned operator ()(unsigned N);
unsigned operator ()();
operator int();
operator float();
operator double();
//! returns uniformly distributed integer random number from [a,b) range
int uniform(int a, int b);
//! returns uniformly distributed floating-point random number from [a,b) range
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, bool saturateRange=false );
//! returns Gaussian random variate with mean zero.
double gaussian(double sigma);
uint64 state;
};
下面结合文档opencv2refman.pdf中RNG的说明简单讲一下自己的理解。
(1)构造函数
可以看到RNG有两个构造函数,第一个构造参数设置的state是默认值0xffffffff,第二个构造参数的格式设置state为特定值,如果state为0,使用默认值(0xffffffff)避免单一的随机数序列都为0。
// Multiply-with-Carry RNG
inline RNG::RNG() { state = 0xffffffff; }
inline RNG::RNG(uint64 _state) { state = _state ? _state : 0xffffffff; }
(2)uinform函数
uinform函数返回[a,b)范围内的随机数,类型可以是int、float、double。需要注意的是编译器并不关心你uniform函数返回值变量的类型,它仅仅考虑的是上下限a,b的类型。因此如果你想要一个float类型的随机数,要么在整数后面放点(rng.uniform(0., 1.)),如果是常量要么使用显式的类型转换符,就像a1的初始化那样(rng.uniform((double)0, (double)1))。
其他函数暂时不做研究,本篇教程使用的主要是RNG的构造函数还有uniform函数。
2 putText函数
函数声明:
//! renders text string in the image
CV_EXPORTS_W void putText( Mat& img, const string& text, Point org,
int fontFace, double fontScale, Scalar color,
int thickness=1, int lineType=8,
bool bottomLeftOrigin=false );
函数说明:
参数说明:
img-图像
text-文本
org-图像中显示文本字符串的左下角位置
fontFace-文本的字体类型
fontScale-文本的尺度因子
color-文本颜色
thickness-文本线的粗细,默认值为1
lineType-文本线的类型,默认值为8
bottomLeftOrigin-如果为真,图像数据原点就在左下角,否则在左上角。默认值为false。
相关函数getTextSize()
函数声明:
//! returns bounding box of the text string
CV_EXPORTS_W Size getTextSize(const string& text, int fontFace,
double fontScale, int thickness,
CV_OUT int* baseLine);
返回文本字符串的包围矩形size.
text-输入文本字符串
fontFace-文本的字体类型
fontScale-文本的尺度因子
thickness-文本线的粗细
baseLine-输出参数,y坐标的基准线,相对于文本最底部点
3 我的练习
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int Width = 400; //图像宽
int Height = 400; //图像高
int xMin = 0; //横坐标下限
int xMax = Width; //横坐标上限
int yMin = 0; //纵坐标下限
int yMax = Height; //纵坐标上限
int Num = 25; //数量
static cv::Scalar RandomColor(cv::RNG &rng);
int main()
{
//创建空白图像
cv::Mat src = cv::Mat::zeros(Width, Height, CV_8UC3);
//创建RNG对象
cv::RNG rng;
for (int i = 0; i < Num; i++)
{
//产生均匀分布的两个点
cv::Point P1;
P1.x = rng.uniform(xMin, xMax);
P1.y = rng.uniform(yMin, yMax);
cv::Point P2;
P2.x = rng.uniform(xMin, xMax);
P2.y = rng.uniform(yMin, yMax);
//画随机线
const Scalar color = RandomColor(rng);
int thickness = rng.uniform(1, 10);
int lineType = 8;
int shift = 0;
cv::line(src, P1, P2, color, thickness, 8, 0);
}
//输出文本
const std::string str = "hungry";
cv::Point P3;
P3.x = rng.uniform(xMin, xMax);
P3.y = rng.uniform(yMin, yMax);
int fontFace = rng.uniform(0, 8);
double fontScale = rng.uniform((double)1, (double)1.5);
Scalar color = RandomColor(rng);
int thickness = rng.uniform(1, 5);
int lineType = 8;
bool bottomLeftOrigin = false;
putText(src, str, P3, fontFace, fontScale, color, thickness, 8, false);
int baseline = 0;
cv::Size textsize = getTextSize(str, fontFace, fontScale, thickness, &baseline);
cv::Point P4;
P4.x = (Width - textsize.width) / 2;
P4.y = (Height - textsize.height) / 2;
putText(src, str, P4, fontFace, fontScale, color, thickness, 8, false);
return 0;
}
//返回随机颜色
static cv::Scalar RandomColor(cv::RNG &rng)
{
int value = (unsigned)rng;
return cv::Scalar(value & 255, (value >> 8) & 255, (value >> 16) & 255);
}
RandomColor函数说明:
使用了operator unsigned();查看函数定义
inline RNG::operator unsigned() { return next(); }
实际调用了next()函数
inline unsigned RNG::next()
{
state = (uint64)(unsigned)state*CV_RNG_COEFF + (unsigned)(state >> 32);
return (unsigned)state;
}
next函数说明:
利用MWC算法更新state值的并且返回32位随机数。
MWC算法https://en.wikipedia.org/wiki/Multiply-with-carry
有时间可以研究一下。
cv::Scalar(value & 255, (value >> 8) & 255, (value >> 16) & 255)这句话是通过移位运算符分别获取B、G、R值,并且注意不要超出范围[0,255]。
以后涉及随机颜色可以采用教程中的这个函数,很简短方便。
注意这个函数前加了static,这样有什么作用呢?与普通函数有什么区别呢?