فصل دوم - حوزهٔ مکان

شکل‌های هندسی ساده

در این بخش می‌خواهیم طریقه ترسیم شکل‌های هندسی ساده را آموزش دهیم. این شکل‌ها عبارتند از خط، دایره، بیضی، مستطیل، چند ضلعی.

کد

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#define w 400

using namespace cv;

/// Function headers
void MyEllipse( Mat img, double angle );
void MyFilledCircle( Mat img, Point center );
void MyPolygon( Mat img );
void MyLine( Mat img, Point start, Point end );

/**
 * @function main
 * @brief Main function
 */
int main( void ){

    /// Windows names
    char atom_window[] = "Drawing 1: Atom";
    char rook_window[] = "Drawing 2: Rook";

    /// Create black empty images
    Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
    Mat rook_image = Mat::zeros( w, w, CV_8UC3 );

    /// 1. Draw a simple atom:
    /// -----------------------

    /// 1.a. Creating ellipses
    MyEllipse( atom_image, 90 );
    MyEllipse( atom_image, 0 );
    MyEllipse( atom_image, 45 );
    MyEllipse( atom_image, -45 );

    /// 1.b. Creating circles
    MyFilledCircle( atom_image, Point( w/2, w/2) );

    /// 2. Draw a rook
    /// ------------------

    /// 2.a. Create a convex polygon
    MyPolygon( rook_image );

    /// 2.b. Creating rectangles
    rectangle(rook_image, Point( 0, 7*w/8 ), Point( w, w), Scalar( 0, 255, 255 ), -1, 8);

    /// 2.c. Create a few lines
    MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) );
    MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) );
    MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) );
    MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) );

    /// 3. Display your stuff!
    imshow( atom_window, atom_image );
    moveWindow( atom_window, 0, 200 );
    imshow( rook_window, rook_image );
    moveWindow( rook_window, w, 200 );

    waitKey( 0 );
    return(0);
}

/// Function Declaration

/**
 * @function MyEllipse
 * @brief Draw a fixed-size ellipse with different angles
 */
void MyEllipse( Mat img, double angle )
{
    int thickness = 2;
    int lineType = 8;

    ellipse( img, Point( w/2, w/2 ), Size( w/4, w/16 ),
        angle, 0, 360, Scalar( 255, 0, 0 ), thickness, lineType );
}

/**
 * @function MyFilledCircle
 * @brief Draw a fixed-size filled circle
 */
void MyFilledCircle( Mat img, Point center )
{
    int thickness = -1;
    int lineType = 8;

    circle(img, center, w/32, Scalar( 0, 0, 255 ), thickness, lineType);
}

/**
 * @function MyPolygon
 * @function Draw a simple concave polygon (rook)
 */
void MyPolygon( Mat img )
{
    int lineType = 8;

    /** Create some points */
    Point rook_points[1][20];
    rook_points[0][0]  = Point(    w/4,   7*w/8 );
    rook_points[0][1]  = Point(  3*w/4,   7*w/8 );
    rook_points[0][2]  = Point(  3*w/4,  13*w/16 );
    rook_points[0][3]  = Point( 11*w/16, 13*w/16 );
    rook_points[0][4]  = Point( 19*w/32,  3*w/8 );
    rook_points[0][5]  = Point(  3*w/4,   3*w/8 );
    rook_points[0][6]  = Point(  3*w/4,     w/8 );
    rook_points[0][7]  = Point( 26*w/40,    w/8 );
    rook_points[0][8]  = Point( 26*w/40,    w/4 );
    rook_points[0][9]  = Point( 22*w/40,    w/4 );
    rook_points[0][10] = Point( 22*w/40,    w/8 );
    rook_points[0][11] = Point( 18*w/40,    w/8 );
    rook_points[0][12] = Point( 18*w/40,    w/4 );
    rook_points[0][13] = Point( 14*w/40,    w/4 );
    rook_points[0][14] = Point( 14*w/40,    w/8 );
    rook_points[0][15] = Point(    w/4,     w/8 );
    rook_points[0][16] = Point(    w/4,   3*w/8 );
    rook_points[0][17] = Point( 13*w/32,  3*w/8 );
    rook_points[0][18] = Point(  5*w/16, 13*w/16 );
    rook_points[0][19] = Point(    w/4,  13*w/16 );

    const Point* ppt[1] = { rook_points[0] };
    int npt[] = { 20 };

    fillPoly(img, ppt, npt, 1, Scalar( 255, 255, 255 ), lineType);
}

/**
 * @function MyLine
 * @brief Draw a simple line
 */
void MyLine( Mat img, Point start, Point end )
{
    int thickness = 2;
    int lineType = 8;
    line(img, start, end, Scalar( 0, 0, 0 ), thickness, lineType);
}

توضیح

از آنجایی که می‌خواهیم دو شکل رسم کنیم (یک اتم و یک قلعه)، باید دو ماتریس به عنوان صفحهٔ ترسیم و دو پنجره برای نمایش آنها درست کنیم (خطوط 25 و 26).

برای کشیدن هر شکل یک تابع جداگانه درست کرده‌ایم. به عنوان مثال برای کشیدن اتم از توابع MyEllipse و MyFilledCircle استفاده کرده‌ایم (خطوط 28 تا 39).

برای کشیدن قلعه از توابع MyLine، rectangle و یک MyPolygon استفاده کرده‌ایم (خطوط 40 تا 53).

بهتر است ببینیم درون این توابع چه می‌گذرد:

  • تابع MyLine (خطوط 133 تا 138)

    همان طور که می‌بینید این تابع فقط به روش زیر چندین بار از تابع line (که در ماژول Core موجود است) استفاده می‌کند:

    • یک خط از نقطهٔ start به نقطهٔ end می‌کشد.
    • خط بالا را در تصویر img رسم می‌کند.
    • رنگ خط با یک اسکالر به فرم Scalar(0,0,0)، که نشان دهندهٔ رنگ سیاه RGB است، به تابع line فرستاده شده.
    • میزان نازکی خط با متغیر thickness مشخص شده است.
    • این خط از نوع متصل است و این مورد با متغیر lineType که مقدار 2 دارد مشخص شده است.
  • تابع MyEllipse (خطوط 71 تا 78)

    این تابع به شکل زیر یک بیضی می‌کشد:

    • بیضی در عکس img ترسیم می‌شود.
    • مرکز بیضی نقطهٔ (w/2,w/2) است و در یک مستطیل به اندازهٔ (w/4,w/16) محدود شده.
    • بیضی به اندازه angle درجه چرخانده می‌شود.
    • بیضی به صورت یک قطاع از زاویهٔ 0 تا 360 است.
    • رنگ بیضی با Scalar(255,0,0) که در RGB یعنی آبی، مشخص شده است.
    • نازکی و نوع خط بیضی با متغیرهای thickness و lineType مشخص شده‌اند.
  • تابع MyFilledCircle (خطوط 84 تا 90)

    آرگومان‌های تابع circle به شرح زیر است:

    • img عکسی است که دایره در آن کشیده می‌شود.
    • مرکز دایره با نقطهٔ center مشخص شده است.
    • شعاع دایره W/32 است.
    • رنگ دایره با Scalar(0,0,255) که در RGB به معنی قرمز است، مشخص شده است.
    • به خاطر اینکه مقدار thickness عدد 1- قرار داده شده، دایره توپُر کشیده می‌شود.
  • تابع MyPolygon (خطوط 96 تا 127)

    برای کشیدن یک چند ضلعی توپر، از تابع fillPoly که در ماژول Core موجود است استفاده می‌کنیم. قابل ذکر است که:

    • چندضلعی روی عکس img کشیده می‌شود.
    • رأس‌های چند ضلعی همان مجموعه نقاطی هستند که در ppt قرار داده شده‌اند.
    • تعداد رأس‌هایی که باید رسم شوند در متغیر npt قرار داده شده است.
    • تعداد چند ضلعی‌هایی که باید رسم شوند، 1 عدد است.
    • رنگ چند ضلعی با Scalar(255,255,255) که در RGB به معنای سفید است، مشخص شده است.
  • تابع rectangle (خط 47)

    در آخر تابع rectangle را معرفی می‌کنیم. در این تابع:

    • مستطیل روی عکس rook_image کشیده می‌شود.
    • دو رأس مخالف مستطیل با Point(0,7\*w/8.0) و Point(w,w) مشخص شده‌اند.
    • رنگ مستطیل با Scalar(0,255,255) که نشان دهندهٔ رنگ زرد در سیستم RGB است، مشخص شده است.
    • به خاطر اینکه مقدار thickness عدد 1- قرار داده شده است، مستطیل توپُر خواهد بود.

خروجی

خروجی برنامه به شکل زیر است:

mage1 mage1