OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
OpenCV:随机数生成器和文本

上一教程: 基本绘图
下一教程: 图像平滑

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,您将学习如何:

  • 使用随机数生成器类 (cv::RNG )以及如何从均匀分布中获取随机数。
  • 使用函数cv::putText在OpenCV窗口上显示文本。

代码

  • 在之前的教程(基本绘图)中,我们绘制了各种几何图形,输入参数例如坐标(cv::Point形式),颜色,粗细等。您可能已经注意到我们为这些参数赋予了特定值。
  • 在本教程中,我们打算对绘图参数使用随机值。此外,我们打算用大量几何图形填充我们的图像。由于我们将以随机方式初始化它们,因此此过程将是自动的,并通过使用循环来完成。
  • 此代码位于您的OpenCV示例文件夹中。否则,您可以从此处获取:此处

解释

  1. 让我们从检查main函数开始。我们观察到,我们首先要做的是创建一个随机数生成器对象(RNG)
    RNG rng( 0xFFFFFFFF );
    RNG实现了一个随机数生成器。在这个例子中,rng是一个用值0xFFFFFFFF初始化的RNG元素。
  2. 然后我们创建一个初始化为的矩阵(这意味着它将显示为黑色),指定其高度、宽度及其类型。
    Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
    imshow( window_name, image );
    #define CV_8UC3
    定义 interface.h:90
  3. 然后我们继续绘制各种图形。查看代码后,您可以看到它主要分为8个部分,定义为函数。
    c = Drawing_Random_Lines(image, window_name, rng);
    if( c != 0 ) return 0;
    c = Drawing_Random_Rectangles(image, window_name, rng);
    if( c != 0 ) return 0;
    c = Drawing_Random_Ellipses( image, window_name, rng );
    if( c != 0 ) return 0;
    c = Drawing_Random_Polylines( image, window_name, rng );
    if( c != 0 ) return 0;
    c = Drawing_Random_Filled_Polygons( image, window_name, rng );
    if( c != 0 ) return 0;
    c = Drawing_Random_Circles( image, window_name, rng );
    if( c != 0 ) return 0;
    c = Displaying_Random_Text( image, window_name, rng );
    if( c != 0 ) return 0;
    c = Displaying_Big_End( image, window_name, rng );
    所有这些函数都遵循相同的模式,因此我们将仅分析其中的几个,因为相同的解释适用于所有函数。
  4. 检查函数Drawing_Random_Lines
    int Drawing_Random_Lines( Mat image, char* window_name, RNG rng )
    {
    int lineType = 8;
    Point pt1, pt2;
    for( int i = 0; i < NUMBER; i++ )
    {
    pt1.x = rng.uniform( x_1, x_2 );
    pt1.y = rng.uniform( y_1, y_2 );
    pt2.x = rng.uniform( x_1, x_2 );
    pt2.y = rng.uniform( y_1, y_2 );
    line( image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), 8 );
    imshow( window_name, image );
    if( waitKey( DELAY ) >= 0 )
    { return -1; }
    }
    return 0;
    }
    我们可以观察到以下几点:
    • for循环将重复NUMBER次。由于函数cv::line在此循环内,这意味着将生成NUMBER条线。
    • 线的端点由pt1pt2给出。对于pt1,我们可以看到:
      pt1.x = rng.uniform( x_1, x_2 );
      pt1.y = rng.uniform( y_1, y_2 );
      • 我们知道rng是一个随机数生成器对象。在上面的代码中,我们调用rng.uniform(a,b)。这将在值ab之间生成一个随机均匀分布(在a中包含,在b中不包含)。
      • 根据上面的解释,我们推断端点pt1pt2将是随机值,因此线的位 置将是不可预测的,从而产生良好的视觉效果(请查看下面的“结果”部分)。
      • 作为另一个观察结果,我们注意到在cv::line参数中,对于颜色输入,我们输入:
        randomColor(rng)
        让我们检查函数的实现:
        static Scalar randomColor( RNG& rng )
        {
        int icolor = (unsigned) rng;
        return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
        }
        正如我们所看到的,返回值是一个具有3个随机初始化值的Scalar,它们用作线的颜色参数RGB。因此,线的颜色也将是随机的!
  5. 上述解释适用于生成圆、椭圆、多边形等的其它函数。诸如中心顶点之类的参数也会随机生成。
  6. 在结束之前,我们还应该查看函数Display_Random_TextDisplaying_Big_End,因为它们都有一些有趣的特性。
  7. Display_Random_Text

    int Displaying_Random_Text( Mat image, char* window_name, RNG rng )
    {
    int lineType = 8;
    for ( int i = 1; i < NUMBER; i++ )
    {
    Point org;
    org.x = rng.uniform(x_1, x_2);
    org.y = rng.uniform(y_1, y_2);
    putText( image, "Testing text rendering", org, rng.uniform(0,8),
    rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType);
    imshow( window_name, image );
    if( waitKey(DELAY) >= 0 )
    { return -1; }
    }
    return 0;
    }
    _Tp x
    点的x坐标
    定义 types.hpp:201

    一切看起来都很熟悉,但表达式:

    putText( image, "Testing text rendering", org, rng.uniform(0,8),
    rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType);

    那么,函数cv::putText做了什么?在我们的例子中:

    • image中绘制文本"Testing text rendering"
    • 文本的左下角将位于Point org
    • 字体类型是范围为\([0, 8>\)的随机整数值。
    • 字体的比例由表达式rng.uniform(0, 100)x0.05 + 0.1表示(这意味着其范围为\([0.1, 5.1>\))。
    • 文本颜色是随机的(由randomColor(rng)表示)。
    • 文本粗细范围为1到10,由rng.uniform(1,10)指定。

    结果,我们将(类似于其他绘图函数)在图像上获得NUMBER个文本,位置随机。

  8. Displaying_Big_End

    int Displaying_Big_End( Mat image, char* window_name, RNG rng )
    {
    Size textsize = getTextSize("OpenCV forever!", FONT_HERSHEY_COMPLEX, 3, 5, 0);
    Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2);
    int lineType = 8;
    Mat image2;
    for( int i = 0; i < 255; i += 2 )
    {
    image2 = image - Scalar::all(i);
    putText( image2, "OpenCV 万岁!" , org, FONT_HERSHEY_COMPLEX, 3,
    Scalar(i, i, 255), 5, lineType );
    imshow( window_name, image2 );
    if( waitKey(DELAY) >= 0 )
    { return -1; }
    }
    return 0;
    }

    除了getTextSize函数(获取参数文本的大小)之外,我们还可以观察到新的操作在for循环内

    image2 = image - Scalar::all(i)

    因此,image2imageScalar::all(i) 的差值。事实上,这里发生的是,image2 的每个像素将是image 的每个像素减去i 的值的结果(记住,对于每个像素,我们都考虑三个值,例如 R、G 和 B,因此每个值都会受到影响)。

    还要记住,减法运算始终会在内部执行饱和运算,这意味着获得的结果始终在允许的范围内(对于我们的示例,没有负值,介于 0 和 255 之间)。

结果

正如您在代码部分看到的,程序将依次执行各种绘图函数,这将产生

  1. 首先,屏幕上会出现一组随机的NUMBER条线,如下图所示
  1. 然后,是一组新的图形,这次是矩形
  2. 现在,一些椭圆将出现,每个椭圆都有随机的位置、大小、粗细和弧长。
  1. 现在,屏幕上将出现具有 03 个线段的多边形,同样是随机配置。
  1. 接下来是填充的多边形(在这个例子中是三角形)。
  2. 最后出现的几何图形:圆形!
  1. 接近结尾,文本“测试文本渲染”将以各种字体、大小、颜色和位置出现。
  2. 以及最终结果(顺便说一句,这也表达了一个重要的真理)。