【opencv 450 Image Processing 】Basic-Random generator and text with OpenCV

本文档介绍如何使用OpenCV库进行随机图形绘制和文本显示。通过创建一个随机数生成器对象RNG,利用其生成的随机数来决定图形的位置、颜色、大小等属性,实现如线条、矩形、椭圆、多边形、圆圈和文本的随机绘制。在每个图形绘制函数中,使用随机数设置位置、尺寸、颜色和样式,然后在窗口中显示。此外,还展示了如何在随机位置显示文本以及一个独特的‘大结局’效果,动态改变文本颜色。
摘要由CSDN通过智能技术生成

Random generator and text with OpenCV

使用 OpenCV 的随机生成器和文本

Goals

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

使用随机数生成器类 (cv::RNG) 以及如何均匀分布中获取随机数

使用函数 cv::putText 在 OpenCV 窗口上显示文本

Code

在之前的教程(Basic Drawing)中,我们绘制了不同的几何图形,将坐标(以 cv::Point 的形式)、颜色、厚度等作为输入参数。您可能已经注意到,我们为这些参数提供了特定的值 .

在本教程中,我们打算对绘图参数使用随机值。 此外,我们打算用大量几何图形填充我们的图像。 由于我们将以随机方式初始化它们,因此此过程将是自动的,并通过使用循环来完成。

此代码位于您的 OpenCV 示例文件夹中。 否则你可以从这里获取opencv/Drawing_2.cpp at 4.x · opencv/opencv (github.com).

/**
 * @file Drawing_2.cpp
 * @brief Simple sample code
 */

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdio.h>

using namespace cv;

/// 全局变量
const int NUMBER = 100; //直线数
const int DELAY = 5;//延迟时间

const int window_width = 900;
const int window_height = 600;
int x_1 = -window_width/2;
int x_2 = window_width*3/2;
int y_1 = -window_width/2;
int y_2 = window_width*3/2;

/// Function headers
static Scalar randomColor( RNG& rng );
int Drawing_Random_Lines( Mat image, char* window_name, RNG rng );
int Drawing_Random_Rectangles( Mat image, char* window_name, RNG rng );
int Drawing_Random_Ellipses( Mat image, char* window_name, RNG rng );
int Drawing_Random_Polylines( Mat image, char* window_name, RNG rng );
int Drawing_Random_Filled_Polygons( Mat image, char* window_name, RNG rng );
int Drawing_Random_Circles( Mat image, char* window_name, RNG rng );
int Displaying_Random_Text( Mat image, char* window_name, RNG rng );
int Displaying_Big_End( Mat image, char* window_name, RNG rng );


/**
 * @function main
 */
int main( void )
{
  int c;

  ///开始创建窗口 Start creating a window
  char window_name[] = "Drawing_2 Tutorial";

  /// 同时创建一个随机对象 (RNG) Also create a random object (RNG)
  RNG rng( 0xFFFFFFFF );

  /// 初始化一个用零填充的矩阵Initialize a matrix filled with zeros
  Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
  /// 在 DELAY ms 期间将其显示在窗口中 Show it in a window during DELAY ms
  imshow( window_name, image ); //黑色
  waitKey( DELAY );

  /// 现在,让我们画一些线 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 );
  if( c != 0 ) return 0;

  waitKey(0);
  return 0;
}

/// 函数定义

/**
 * @function randomColor
 * @brief 给定随机对象产生随机颜色Produces a random color given a random object
 */
static Scalar randomColor( RNG& rng )
{
  int icolor = (unsigned) rng;
  return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}


/**
 * @function Drawing_Random_Lines
 */
int Drawing_Random_Lines( Mat image, char* window_name, RNG rng )
{
  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;
}

/**
 * @function Drawing_Rectangles
 */
int Drawing_Random_Rectangles( Mat image, char* window_name, RNG rng )
{
  Point pt1, pt2;
  int lineType = 8;
  int thickness = rng.uniform( -3, 10 );

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

    rectangle( image, pt1, pt2, randomColor(rng), MAX( thickness, -1 ), lineType );

    imshow( window_name, image );
    if( waitKey( DELAY ) >= 0 )
      { return -1; }
  }

  return 0;
}

/**
 * @function Drawing_Random_Ellipses
 */
int Drawing_Random_Ellipses( Mat image, char* window_name, RNG rng )
{
  int lineType = 8;

  for ( int i = 0; i < NUMBER; i++ )
  {
    Point center;
    center.x = rng.uniform(x_1, x_2);
    center.y = rng.uniform(y_1, y_2);

    Size axes;//轴尺寸
    axes.width = rng.uniform(0, 200);
    axes.height = rng.uniform(0, 200);

    double angle = rng.uniform(0, 180);

    ellipse( image, center, axes, angle, angle - 100, angle + 200,
             randomColor(rng), rng.uniform(-1,9), lineType );

    imshow( window_name, image );

    if( waitKey(DELAY) >= 0 )
      { return -1; }
  }

  return 0;
}

/**
 * @function Drawing_Random_Polylines
 */
int Drawing_Random_Polylines( Mat image, char* window_name, RNG rng )
{
  int lineType = 8;

  for( int i = 0; i< NUMBER; i++ )
  {
    Point pt[2][3];//2X3 
    pt[0][0].x = rng.uniform(x_1, x_2);
    pt[0][0].y = rng.uniform(y_1, y_2);
    pt[0][1].x = rng.uniform(x_1, x_2);
    pt[0][1].y = rng.uniform(y_1, y_2);
    pt[0][2].x = rng.uniform(x_1, x_2);
    pt[0][2].y = rng.uniform(y_1, y_2);
    pt[1][0].x = rng.uniform(x_1, x_2);
    pt[1][0].y = rng.uniform(y_1, y_2);
    pt[1][1].x = rng.uniform(x_1, x_2);
    pt[1][1].y = rng.uniform(y_1, y_2);
    pt[1][2].x = rng.uniform(x_1, x_2);
    pt[1][2].y = rng.uniform(y_1, y_2);

    const Point* ppt[2] = {pt[0], pt[1]};//两个点数组指针
    int npt[] = {3, 3};//每个数组3个点

    polylines(image, ppt, npt, 2, true, randomColor(rng), rng.uniform(1,10), lineType);

    imshow( window_name, image );
    if( waitKey(DELAY) >= 0 )
      { return -1; }
  }
  return 0;
}

/**
 * @function Drawing_Random_Filled_Polygons
 */
int Drawing_Random_Filled_Polygons( Mat image, char* window_name, RNG rng )
{
  int lineType = 8;

  for ( int i = 0; i < NUMBER; i++ )
  {
    Point pt[2][3];//2X3 点数组
    pt[0][0].x = rng.uniform(x_1, x_2);
    pt[0][0].y = rng.uniform(y_1, y_2);
    pt[0][1].x = rng.uniform(x_1, x_2);
    pt[0][1].y = rng.uniform(y_1, y_2);
    pt[0][2].x = rng.uniform(x_1, x_2);
    pt[0][2].y = rng.uniform(y_1, y_2);
    pt[1][0].x = rng.uniform(x_1, x_2);
    pt[1][0].y = rng.uniform(y_1, y_2);
    pt[1][1].x = rng.uniform(x_1, x_2);
    pt[1][1].y = rng.uniform(y_1, y_2);
    pt[1][2].x = rng.uniform(x_1, x_2);
    pt[1][2].y = rng.uniform(y_1, y_2);

    const Point* ppt[2] = {pt[0], pt[1]};//点数组指针  
    int npt[] = {3, 3};

    fillPoly( image, ppt, npt, 2, randomColor(rng), lineType );//填充多边形

    imshow( window_name, image );
    if( waitKey(DELAY) >= 0 )
       { return -1; }
  }
  return 0;
}

/**
 * @function Drawing_Random_Circles
 */
int Drawing_Random_Circles( Mat image, char* window_name, RNG rng )
{
  int lineType = 8;

  for (int i = 0; i < NUMBER; i++)
  {
    Point center;//圆心 随机
    center.x = rng.uniform(x_1, x_2);
    center.y = rng.uniform(y_1, y_2);

    circle( image, center, rng.uniform(0, 300), randomColor(rng),
            rng.uniform(-1, 9), lineType );

    imshow( window_name, image );
    if( waitKey(DELAY) >= 0 )
      { return -1; }
  }

  return 0;
}

/**
 * @function Displaying_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;
}

/**
 * @function Displaying_Big_End
 */
int Displaying_Big_End( Mat image, char* window_name, 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;
}

Explanation

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

RNG rng( 0xFFFFFFFF );

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

  1. 然后我们创建一个初始化为零的矩阵(这意味着它将显示为黑色),指定它的高度、宽度和类型:
Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );

imshow( window_name, image );
  1. 然后我们继续绘制疯狂的东西。 看了下代码可以看到主要分为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 );

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

  1. 检查函数 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;

}

我们可以观察到以下几点:

  1. for 循环将重复 NUMBER 次。 由于函数 cv::line 在此循环内,这意味着将生成 NUMBER 行。
  2. line极值由 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 的极值将是随机值,因此线条的位置将非常难以预测,从而产生了很好的视觉效果(查看下面的结果部分)。

作为另一个观察,我们注意到在 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,分别作为线条颜色的 R、G 和 B 参数。 因此,线条的颜色也会是随机的!

  1. 上面的解释适用于生成圆、椭圆、多边形等的其他函数。中心和顶点等参数也是随机生成的。
  2. 在结束之前,我们还应该看一下函数 Display_Random_Text 和 Displaying_Big_End,因为它们都有一些有趣的特性:
  3. 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 有什么作用呢? 在我们的示例中:

在图像中绘制文本**“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 个文本。

  1. 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)

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

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

Result

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

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

 

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

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

 

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

 

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

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

 

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

8. 大结局big end (顺便说一句,这也表达了一个大道理):

 

OpenCV: Random generator and text with OpenCVicon-default.png?t=M276https://docs.opencv.org/4.5.5/df/d61/tutorial_random_generator_and_text.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值