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. 和大的結尾(順便說一句,這也表達了一個巨大的真理)