11、OpenCV生成随机数、写文字

本文档详细介绍了如何使用OpenCV库生成随机数并绘制文本。通过CV::RNG类生成随机数,用于在图像上绘制随机位置、颜色和大小的几何图形。同时,利用putText函数在图像上书写文本,调整字体、位置和颜色。示例代码展示了如何实现这一系列操作,包括随机线条、矩形、椭圆、多边形、圆以及文本的绘制。

一、学习目标

  • 学会使用OpenCV的RNG接口生成随机数
  • 学会使用OpenCV在图像上书写文字

二、使用CV::RNG生成随机数

在之前的教程中,我们绘制了各种几何图形,其输入参数,如坐标(cv::Point的形式)、颜色、粗细等,我们为这些参数指定了特定的值。在本教程中,我们打算为绘图参数使用随机值。此外,我们打算用大量几何图形填充图像。因为我们将以随机方式初始化它们,这个过程将是自动的,并通过使用循环来完成。

首先,我们需要初始化一个随机数生成器对象(RNG):

RNG rng( 0xFFFFFFFF );

RNG实现了一个随机数生成器。在这个例子中,rng是一个初始值为0xFFFFFFFF的对象
RNG类有两个构造函数:

cv::RNG::RNG()	              // 无参构造函数

和:

cv::RNG::RNG(uint64 state)    // 有参构造函数

第一种形式将state设置为一些预定义的值,在当前实现中等于232-1。第二种形式将状态设置为指定的值。如果传递state=0,构造函数将使用上面的默认值来代替,以避免由所有零组成的奇异随机数序列。

接下来,有了随机数生成器后,我们便可以调用生成器对象的接口生成随机数:

int min=0;
int max=100;
Point pt1;
pt1.x = rng.uniform( min, max);
pt1.y = rng.uniform( min, max);

对于点pt1,其坐标值xy均为随机值。

rng.uniform函数的原型为:

int cv::RNG::uniform(int 	a,
					 int 	b)	
  • 参数 a: 生成随机数的下边界,包含值a在内
  • 参数 b: 生成随机数的上边界,不包括值b在内

cv::RNG::uniform函数返回[a,b)范围内均匀分布的整数随机数。该方法使用MWC算法对状态进行转换,并从范围[a, b)中返回由输入参数类型推导出的下一个指定类型的均匀分布随机数。这个函数还有另外两种重载形式,与上述函数的唯一区别就在于接受参数的类型分别为 floatdouble 类型。下面的例子说明了其中的细微差别:

RNG rng;
// a的值一直是0,因为参数类型为整型,[0, 1)之间的整数取值为集合{0}
double a = rng.uniform(0, 1);
// a1的值是区间[0, 1)之间的均匀分布的double类型的小数
double a1 = rng.uniform((double)0, (double)1);
// b的值是区间[0, 1)之间的均匀分布的float类型的小数
float b = rng.uniform(0.f, 1.f);
// c的值是区间[0, 1)之间的均匀分布的double类型的小数
double c = rng.uniform(0., 1.);
// 由于参数类型的歧义性,下面的代码可能会产生编译错误
double d = rng.uniform(0, 0.999999);

三、在图像上书写文本

OpenCV提供了 cv::putText 函数作为接口,以便在图像上书写文本。其函数原型为:

void cv::putText(InputOutputArray 	img,
				 const String & 	text,
				 Point 				org,
				 int 				fontFace,
				 double 			fontScale,	
				 Scalar 			color,
				 int 				thickness = 1,
				 int 				lineType = LINE_8,
				 bool 				bottomLeftOrigin = false)
  • 参数 img: 书写文本的图像
  • 参数 text: 要绘制的文本字符串
  • 参数 org: 图像中文本字符串的左下角位置
  • 参数 fontFace: 字体类型,枚举自HersheyFonts
  • 参数 fontScale: 字体比例系数乘以特定字体的基础大小
  • 参数 color: 字体的颜色
  • 参数 thickness: 用于绘制文本的线条的粗细
  • 参数 lineType: 字体的线条类型
  • 参数 bottomLeftOrigin: 当为true时,图像数据坐标原点位于左下角。否则,它在左上角

函数cv::putText在图像中呈现指定的文本字符串,不能使用指定字体呈现的符号将被问号替换。字体的取值见下表:

参数取值 取值说明
FONT_HERSHEY_SIMPLEX 正常大小无衬线 (不知所云,下同)字体
FONT_HERSHEY_PLAIN 小号无衬线字体
FONT_HERSHEY_DUPLEX 正常大小无衬线字体(比FONT_HERSHEY_SIMPLEX更复杂)
FONT_HERSHEY_COMPLEX 正常大小的衬线字体
FONT_HERSHEY_TRIPLEX 正常大小衬线字体(比FONT_HERSHEY_COMPLEX更复杂)
FONT_HERSHEY_COMPLEX_SMALL FONT_HERSHEY_COMPLEX的小版本
FONT_HERSHEY_SCRIPT_SIMPLEX 手写风格的字体
FONT_HERSHEY_SCRIPT_COMPLEX FONT_HERSHEY_SCRIPT_SIMPLEX的更复杂的变体
FONT_ITALIC 斜体字体

其中,我们常用FONT_HERSHEY_SIMPLEX字体,其它字体可以在需要的时候查询即可。
使用实例:

Mat src = Mat::zeros...;
putText( src, "OpenCV forever!", Size(100,100), FONT_HERSHEY_COMPLEX, 
         3,Scalar(255, 255, 255), 5, LINE_8);

在某些应用中,我们可能需要搭配 cv::getTextSize 函数使用,其原型为:

Size cv::getTextSize(const String & 	text,
					 int 				fontFace,
					 double 			fontScale,
					 int 				thickness,
					 int * 				baseLine)	
  • 参数 text: 输入文本字符串
  • 参数 fontFace: 使用的字体
  • 参数 fontScale: 字体比例系数乘以特定字体的基础大小
  • 参数 thickness: 文本的线条的粗细
  • 参数 baseLine: 基线相对于最底部文本点的y坐标函数

cv::getTextSize计算并返回包含指定文本的框的大小。下面的代码实现了将文本绘制在图像的正中间,并在文本的周围紧贴了一个矩形框:

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
   
   
    // 声明和初始化要显示的文本内容
    String text = "Funny text inside the box";

    // 定义字体、系数和字体线条的粗细
    int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
    double fontScale = 2;
    int thickness = 3;

    // 声明并初始化一个600*800的画布,背景颜色为黑色
    Mat img(600, 800, CV_8UC3, Scalar::all(0));

    int baseline = 0;
    // 获取在指定文本、字体、系数和线条粗细的情况下的框体大小
    Size textSize = getTextSize(text, fontFace, fontScale, thickness, &baseline);
    baseline += thickness;

    // 定义文本的位置,使文本框处于画布的正中间。注意结合理解:
    // 在绘制文本时,用到的是文本框左下角的位置(不指定bottomLeftOrigin值为True的情况),要使文本框
    // 处于画布中间,则需要让文本框的左下角位置偏移文本框大小一半的尺寸,正如下面公式所示
    Point textOrg((img.cols - textSize.width) / 2, (img.rows + textSize.height) / 2);
    // 由于文本线条的粗细占用了一定像素,在考虑偏移时需要注意
    rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0, 0, 255));
    line
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值