OpenCV 4.12.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. 然后,我们创建一个初始化为zeros(这意味着它将显示为黑色)的矩阵,指定它的高度、宽度和类型
    Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
    imshow( window_name, image );
    CV_8UC3
    #define CV_8UC3
  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的参数中,对于color输入我们输入
        randomColor(rng)
        让我们检查一下函数实现
        static Scalar randomColor( RNG& rng )
        {
        int icolor = (unsigned) rng;
        return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
        }
        正如我们所看到的,返回值是一个Scalar,带有 3 个随机初始化的值,这些值用作线条颜色的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"
    • 文本的左下角将位于点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 forever!", org, FONT_HERSHEY_COMPLEX, 3,
    Scalar(i, i, 255), 5, lineType );
    imshow( window_name, image2 );
    if( waitKey(DELAY) >= 0 )
    { return -1; }
    }
    return 0;
    }

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

    image2 = image - Scalar::all(i)

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

    还请记住,减法运算总是在内部执行一个saturate操作,这意味着获得的结果将始终在允许的范围内(对于我们的示例,没有负数且介于 0 和 255 之间)。

结果

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

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