opencv c++函数 基础7 随机数发生器&绘制文字

目的

本节你将学到:

  • 使用 随机数发生器类 (RNG) 并得到均匀分布的随机数。
  • 通过使用函数 putText 显示文字。

代码

  • 在之前的章节中 (基本绘图) 我们绘制过不同的几何图形, 我提供了一些绘制参数,比如 coordinates(坐标) (在绘制点 Points 的时候 ), color(颜色), thickness(线条-粗细,点-大小), 等等... ,你会发现我们给出了这些参数明确的数值。
  • 在本章中, 我们会试着赋予这些参数 random随机 的数值。 并且, 我们会试图在图像上绘制大量的几何图形. 因为我们将用随机的方式初始化这些图形, 这个过程将很自然的用到 loops循环 .
  • 本代码在OpenCV的sample文件夹下,如果招不到,你可以从这里 here 得到它: .

说明

  1. 让我们检视 main 函数。我们发现第一步是实例化一个 Random Number Generator(随机数发生器对象) (RNG):

    RNG rng( 0xFFFFFFFF );
    

    RNG的实现了一个随机数发生器。 在上面的例子中, rng 是用数值 0xFFFFFFFF 来实例化的一个RNG对象。

  2. 然后我们初始化一个 0 矩阵(代表一个全黑的图像), 并且指定它的宽度,高度,和像素格式:

    /// 初始化一个0矩阵
    Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
    
    /// 把它会知道一个窗口中
    imshow( window_name, image );
    
  3. 然后我们开始疯狂的绘制。看过代码时候你会发现它主要分八个部分,正如函数定义的一样:

    /// 现在我们先画线
    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;
    
    /// 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 循环将重复 NUMBER 次。 并且函数 line 在循环中, 这意味着要生成 NUMBER 条线段。

    • 线段的两个端点分别是 pt1 和 pt2. 对于 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)。

      • 由上面的说明,我们可以推断出 pt1 和 pt2 将会是随机的数值,因此产生的线段是变幻不定的,这会产生一个很好的视觉效果(从下面绘制的图片可以看出)。

      • 我们还可以发现, 在 line 的参数设置中,对于 color 的设置我们用了:

        randomColor(rng)
        

        让我们来看看函数的实现:

        static Scalar randomColor( RNG& rng )
          {
          int icolor = (unsigned) rng;
          return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
          }
        

        正如我们看到的,函数的返回值是一个用三个随机数初始化的 Scalar 对象,这三个随机数代表了颜色的 RGB 分量。所以,线段的颜色也是随机的!

  5. 上面的解释同样适用于其它的几何图形,比如说参数 center(圆心) 和 vertices(顶点) 也是随机的。

  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( 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” 。
    • 文字的左下角将用点 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!", 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 (用于获取文字的大小参数), 我们可以发现在 for 循环里的新操作:

      image2 = image - Scalar::all(i)
    
    **image2** 是 **image** 和 **Scalar::all(i)** 的差。事实上,**image2** 的每个像素都是 **image** 的每个像素减去 **i** (对于每个像素,都是由R,G,B三个分量组成,每个分量都会独立做差)的差。
我们还要知道,减法操作  总是 保证是  合理 的操作, 这表明结果总是在合理的范围内 (这个例子里结果不会为负数,并且保证在 0~255的合理范围内)。

结果

正如你在代码部分看到的, 程序将依次执行不同的绘图函数,这将:

  1. 首先 NUMBER 条线段将出现在屏幕上,正如截图所示:

  2. 然后,一个新的图形,这次是一些矩形:

  3. 现在,一些弧线会出现,每一个弧线都有随机的位置,大小,边缘的粗细和弧长:

  4. 现在,带有三个参数的 polylines(折线) 将会出现在屏幕上,同样以随机的方式:

    opencv c++函数 基础7 随机数发生器&绘制文字_第1张图片
  5. 填充的多边形 (这里是三角形) 会出现.

  6. 最后出现的图形:圆

    opencv c++函数 基础7 随机数发生器&绘制文字_第2张图片
  7. 在结尾处,文字 “Testing Text Rendering” 将会以不同的字体,大小,颜色和位置出现在屏幕上。

  8. 最后 (这也顺便表达了OpenCV的宗旨):

    opencv c++函数 基础7 随机数发生器&绘制文字_第3张图片

你可能感兴趣的:(opencv c++函数 基础7 随机数发生器&绘制文字)