opencv基础:随机生成器和文本

811 阅读5分钟

已经更文9天


1. 目标

在本文中,将学习如何:

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

2. 代码

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

3. 代码解释

3.1. 从main函数开始。需要做的第一件事是创建一个随机数生成器对象 (RNG):


 RNG rng(0xFFFFFFFF);

RNG 实现了一个随机数生成器。在这个例子中,rng是一个 RNG 元素,初始化为0xFFFFFFFF

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

Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
imshow( window_name, image );

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

所有这些函数都遵循相同的模式,因此将只分析其中的几个,因为相同的解释适用于所有函数。

3.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,即区间[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参数。因此,线条的颜色也是随机的!

3.5 上面的代码适用于生成圆、椭圆、多边形等的其他函数。中心顶点等参数也是随机生成的。

3.6 现在看一下函数Display_Random_TextDisplaying_Big_End,因为它们都有一些有趣的特性:

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

那么,函数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个文本。

3.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(获取参数文本的大小)之外,可以观察到的新操作是在foo循环内:

image2 = image - Scalar::all(i)

因此,image2imageScalar::all(i) 的相减后的差。实际上,这里发生的情况是image2的每个像素将是image的每个像素减去 i的值的结果(请记住,对于每个像素,我们正在考虑 R、G 和 B 等三个值,所以它们中的每一个会受到影响)

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

4. 结果

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

  1. 首先,屏幕上会出现一组随机的NUMBER行,如下图所示:

    Drawing_2_Tutorial_Result_0.jpg

  2. 然后,一组新的数字,这些时间矩形将出现。

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

    Drawing_2_Tutorial_Result_2.jpg

  4. 现在,具有 03 段的多段线将再次以随机配置出现在屏幕上。

    Drawing_2_Tutorial_Result_3.jpg

  5. 填充多边形(在此示例中为三角形)将在随后出现。

  6. 最后出现的几何图形:圆圈!

    Drawing_2_Tutorial_Result_5.jpg

  7. 接近尾声时,文本 “Testing Text Rendering” 将以各种字体、大小、颜色和位置出现。

  8. 大结局(最终的结果):

    Drawing_2_Tutorial_Result_big.jpg

原文连接