Random generator and text with OpenCV

此为OpenCV官方教程的个人翻译

目标

在本篇文章中,您将学习如何:

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

代码

  • 在上一教程(基本绘图)中,我们绘制了各种几何图形,并给出了坐标(以Point的形式),颜色,厚度等输入参数。您可能已经注意到,我们为这些参数提供了特定的值。
  • 在本教程中,我们打算对绘图参数使用随机值。此外,我们打算用大量的几何图形填充我们的图像。由于我们将以随机方式初始化它们,因此此过程将自动进行,并使用 循环
  • 此代码位于 OpenCV 示例文件夹中。或者,您可以从这里获取它。

解释

  1. 让我们从查看 main 函数开始。我们观察到,我们做的第一件事是创建一个随机数生成器对象(RNG):

    RNG rng( 0xFFFFFFFF );
    

    RNG 实现了一个随机数生成器。在此示例中,rng 是一个 RNG 对象,使用值0xFFFFFFFF

  2. 然后,我们创建一个初始化为零的矩阵(这意味着它将显示为黑色),指定其高度,宽度和类型:

    /// Initialize a matrix filled with zeros
    Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
    
    /// Show it in a window during DELAY ms
    imshow( window_name, image );
    
  3. 然后我们继续画疯狂的东西。看一下代码,可以看到它主要分为8个部分,定义为函数:

    /// Now, let's draw some lines
    c = Drawing_Random_Lines(image, window_name, rng);
    if( c != 0 ) return 0;
    
    /// Go on drawing, this time nice rectangles
    c = Drawing_Random_Rectangles(image, window_name, rng);
    if( c != 0 ) return 0;
    
    /// Draw some ellipses
    c = Drawing_Random_Ellipses( image, window_name, rng );
    if( c != 0 ) return 0;
    
    /// Now some polylines
    c = Drawing_Random_Polylines( image, window_name, rng );
    if( c != 0 ) return 0;
    
    /// Draw filled polygons
    c = Drawing_Random_Filled_Polygons( image, window_name, rng );
    if( c != 0 ) return 0;
    
    /// Draw circles
    c = Drawing_Random_Circles( image, window_name, rng );
    if( c != 0 ) return 0;
    
    /// Display text in random positions
    c = Displaying_Random_Text( image, window_name, rng );
    if( c != 0 ) return 0;
    
    /// Displaying the big end!
    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 循环将重复多次。由于函数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)。。这将在值 a 和 b 之间生成随机均匀分布(包含a而不包含b)

      • 从上面的解释中,我们推断出端点 pt1pt2 将是随机值,因此行的位置将非常不可预测,从而产生不错的视觉效果(查看下面的“结果”部分)。

      • 作为另一个观察结果,我们注意到在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_Text函数和Displaying_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;
    }
    

    一切看起来都很熟悉,但对于putText

    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);
    

    那么,函数 putText 是做什么的呢?在我们的示例中:

    • image中绘制文本“Testing text rendering”**
    • 文本的左下角将位于Point
    • 字体类型是以下区域中的随机整数值:\((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!", CV_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, CV_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,因此每个值都会受到影响)

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

结果

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

  1. 首先,屏幕上将出现一组随机的线,如以下屏幕截图所示:

    lines.png

  2. 接下来是一些矩形

    rectangles.png

  3. 椭圆

    ellipse.png

  4. PolyLines

    polylines.png

  5. circle.png

  6. 文字

    text.png

  7. 最终

posted @ 2022-06-27 11:47  帝皇の惊  阅读(121)  评论(0)    收藏  举报