Basic Drawing {#tutorial_basic_geometric_drawing}
=============
+@prev_tutorial{tutorial_basic_linear_transform}
+@next_tutorial{tutorial_random_generator_and_text}
+
Goals
-----
In this tutorial you will learn how to:
-- Use @ref cv::Point to define 2D points in an image.
-- Use @ref cv::Scalar and why it is useful
-- Draw a **line** by using the OpenCV function @ref cv::line
-- Draw an **ellipse** by using the OpenCV function @ref cv::ellipse
-- Draw a **rectangle** by using the OpenCV function @ref cv::rectangle
-- Draw a **circle** by using the OpenCV function @ref cv::circle
-- Draw a **filled polygon** by using the OpenCV function @ref cv::fillPoly
+- Draw a **line** by using the OpenCV function **line()**
+- Draw an **ellipse** by using the OpenCV function **ellipse()**
+- Draw a **rectangle** by using the OpenCV function **rectangle()**
+- Draw a **circle** by using the OpenCV function **circle()**
+- Draw a **filled polygon** by using the OpenCV function **fillPoly()**
+@add_toggle_cpp
OpenCV Theory
-------------
Scalar( a, b, c )
@endcode
We would be defining a BGR color such as: *Blue = a*, *Green = b* and *Red = c*
+@end_toggle
+
+@add_toggle_java
+OpenCV Theory
+-------------
+
+For this tutorial, we will heavily use two structures: @ref cv::Point and @ref cv::Scalar :
+
+### Point
+
+It represents a 2D point, specified by its image coordinates \f$x\f$ and \f$y\f$. We can define it as:
+@code{.java}
+Point pt = new Point();
+pt.x = 10;
+pt.y = 8;
+@endcode
+or
+@code{.java}
+Point pt = new Point(10, 8);
+@endcode
+### Scalar
+
+- Represents a 4-element vector. The type Scalar is widely used in OpenCV for passing pixel
+ values.
+- In this tutorial, we will use it extensively to represent BGR color values (3 parameters). It is
+ not necessary to define the last argument if it is not going to be used.
+- Let's see an example, if we are asked for a color argument and we give:
+ @code{.java}
+ Scalar( a, b, c )
+ @endcode
+ We would be defining a BGR color such as: *Blue = a*, *Green = b* and *Red = c*
+@end_toggle
Code
----
+@add_toggle_cpp
- This code is in your OpenCV sample folder. Otherwise you can grab it from
- [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp)
+ [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp)
@include samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp
+@end_toggle
+
+@add_toggle_java
+- This code is in your OpenCV sample folder. Otherwise you can grab it from
+ [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java)
+ @include samples/java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java
+@end_toggle
+
+@add_toggle_python
+- This code is in your OpenCV sample folder. Otherwise you can grab it from
+ [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py)
+ @include samples/python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py
+@end_toggle
Explanation
-----------
--# Since we plan to draw two examples (an atom and a rook), we have to create two images and two
- windows to display them.
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp create_images
-
--# We created functions to draw different geometric shapes. For instance, to draw the atom we used
- *MyEllipse* and *MyFilledCircle*:
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_atom
-
--# And to draw the rook we employed *MyLine*, *rectangle* and a *MyPolygon*:
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_rook
-
--# Let's check what is inside each of these functions:
- - *MyLine*
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myline
-
- As we can see, *MyLine* just call the function @ref cv::line , which does the following:
-
- - Draw a line from Point **start** to Point **end**
- - The line is displayed in the image **img**
- - The line color is defined by **Scalar( 0, 0, 0)** which is the RGB value correspondent
- to **Black**
- - The line thickness is set to **thickness** (in this case 2)
- - The line is a 8-connected one (**lineType** = 8)
- - *MyEllipse*
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myellipse
-
- From the code above, we can observe that the function @ref cv::ellipse draws an ellipse such
- that:
-
- - The ellipse is displayed in the image **img**
- - The ellipse center is located in the point **(w/2, w/2)** and is enclosed in a box
- of size **(w/4, w/16)**
- - The ellipse is rotated **angle** degrees
- - The ellipse extends an arc between **0** and **360** degrees
- - The color of the figure will be **Scalar( 255, 0, 0)** which means blue in BGR value.
- - The ellipse's **thickness** is 2.
- - *MyFilledCircle*
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myfilledcircle
-
- Similar to the ellipse function, we can observe that *circle* receives as arguments:
-
- - The image where the circle will be displayed (**img**)
- - The center of the circle denoted as the Point **center**
- - The radius of the circle: **w/32**
- - The color of the circle: **Scalar(0, 0, 255)** which means *Red* in BGR
- - Since **thickness** = -1, the circle will be drawn filled.
- - *MyPolygon*
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp mypolygon
-
- To draw a filled polygon we use the function @ref cv::fillPoly . We note that:
-
- - The polygon will be drawn on **img**
- - The vertices of the polygon are the set of points in **ppt**
- - The total number of vertices to be drawn are **npt**
- - The number of polygons to be drawn is only **1**
- - The color of the polygon is defined by **Scalar( 255, 255, 255)**, which is the BGR
- value for *white*
- - *rectangle*
- @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp rectangle
-
- Finally we have the @ref cv::rectangle function (we did not create a special function for
- this guy). We note that:
-
- - The rectangle will be drawn on **rook_image**
- - Two opposite vertices of the rectangle are defined by *\* Point( 0, 7*w/8 )*\*
- andPoint( w, w)*\*
- - The color of the rectangle is given by **Scalar(0, 255, 255)** which is the BGR value
- for *yellow*
- - Since the thickness value is given by **FILLED (-1)**, the rectangle will be filled.
+Since we plan to draw two examples (an atom and a rook), we have to create two images and two
+windows to display them.
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp create_images
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java create_images
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py create_images
+@end_toggle
+
+We created functions to draw different geometric shapes. For instance, to draw the atom we used
+**MyEllipse** and **MyFilledCircle**:
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_atom
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java draw_atom
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py draw_atom
+@end_toggle
+
+And to draw the rook we employed **MyLine**, **rectangle** and a **MyPolygon**:
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_rook
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java draw_rook
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py draw_rook
+@end_toggle
+
+
+Let's check what is inside each of these functions:
+@add_toggle_cpp
+@end_toggle
+
+<H4>MyLine</H4>
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp my_line
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java my_line
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py my_line
+@end_toggle
+
+- As we can see, **MyLine** just call the function **line()** , which does the following:
+ - Draw a line from Point **start** to Point **end**
+ - The line is displayed in the image **img**
+ - The line color is defined by <B>( 0, 0, 0 )</B> which is the RGB value correspondent
+ to **Black**
+ - The line thickness is set to **thickness** (in this case 2)
+ - The line is a 8-connected one (**lineType** = 8)
+
+<H4>MyEllipse</H4>
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp my_ellipse
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java my_ellipse
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py my_ellipse
+@end_toggle
+
+- From the code above, we can observe that the function **ellipse()** draws an ellipse such
+ that:
+
+ - The ellipse is displayed in the image **img**
+ - The ellipse center is located in the point <B>(w/2, w/2)</B> and is enclosed in a box
+ of size <B>(w/4, w/16)</B>
+ - The ellipse is rotated **angle** degrees
+ - The ellipse extends an arc between **0** and **360** degrees
+ - The color of the figure will be <B>( 255, 0, 0 )</B> which means blue in BGR value.
+ - The ellipse's **thickness** is 2.
+
+<H4>MyFilledCircle</H4>
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp my_filled_circle
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java my_filled_circle
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py my_filled_circle
+@end_toggle
+
+- Similar to the ellipse function, we can observe that *circle* receives as arguments:
+
+ - The image where the circle will be displayed (**img**)
+ - The center of the circle denoted as the point **center**
+ - The radius of the circle: **w/32**
+ - The color of the circle: <B>( 0, 0, 255 )</B> which means *Red* in BGR
+ - Since **thickness** = -1, the circle will be drawn filled.
+
+<H4>MyPolygon</H4>
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp my_polygon
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java my_polygon
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py my_polygon
+@end_toggle
+
+- To draw a filled polygon we use the function **fillPoly()** . We note that:
+
+ - The polygon will be drawn on **img**
+ - The vertices of the polygon are the set of points in **ppt**
+ - The color of the polygon is defined by <B>( 255, 255, 255 )</B>, which is the BGR
+ value for *white*
+
+<H4>rectangle</H4>
+@add_toggle_cpp
+@snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp rectangle
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/core/BasicGeometricDrawing/BasicGeometricDrawing.java rectangle
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/core/BasicGeometricDrawing/basic_geometric_drawing.py rectangle
+@end_toggle
+
+- Finally we have the @ref cv::rectangle function (we did not create a special function for
+ this guy). We note that:
+
+ - The rectangle will be drawn on **rook_image**
+ - Two opposite vertices of the rectangle are defined by <B>( 0, 7*w/8 )</B>
+ and <B>( w, w )</B>
+ - The color of the rectangle is given by <B>( 0, 255, 255 )</B> which is the BGR value
+ for *yellow*
+ - Since the thickness value is given by **FILLED (-1)**, the rectangle will be filled.
Result
------
- @subpage tutorial_basic_geometric_drawing
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
/**
* @file Drawing_1.cpp
- * @brief Simple sample code
+ * @brief Simple geometric drawing
+ * @author OpenCV team
*/
-
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
/// Function Declaration
-//![myellipse]
/**
* @function MyEllipse
* @brief Draw a fixed-size ellipse with different angles
*/
+//![my_ellipse]
void MyEllipse( Mat img, double angle )
{
int thickness = 2;
thickness,
lineType );
}
-//![myellipse]
+//![my_ellipse]
-//![myfilledcircle]
/**
* @function MyFilledCircle
* @brief Draw a fixed-size filled circle
*/
+//![my_filled_circle]
void MyFilledCircle( Mat img, Point center )
{
circle( img,
FILLED,
LINE_8 );
}
-//![myfilledcircle]
+//![my_filled_circle]
-//![mypolygon]
/**
* @function MyPolygon
* @brief Draw a simple concave polygon (rook)
*/
+//![my_polygon]
void MyPolygon( Mat img )
{
int lineType = LINE_8;
Scalar( 255, 255, 255 ),
lineType );
}
-//![mypolygon]
+//![my_polygon]
-//![myline]
/**
* @function MyLine
* @brief Draw a simple line
*/
+//![my_line]
void MyLine( Mat img, Point start, Point end )
{
int thickness = 2;
int lineType = LINE_8;
+
line( img,
start,
end,
thickness,
lineType );
}
-//![myline]
+//![my_line]
--- /dev/null
+import org.opencv.core.*;
+import org.opencv.core.Point;
+import org.opencv.highgui.HighGui;
+import org.opencv.imgproc.Imgproc;
+
+import java.util.*;
+import java.util.List;
+
+class GeometricDrawingRun{
+
+ private static final int W = 400;
+
+ public void run(){
+ //! [create_images]
+ /// Windows names
+ String atom_window = "Drawing 1: Atom";
+ String rook_window = "Drawing 2: Rook";
+
+ /// Create black empty images
+ Mat atom_image = Mat.zeros( W, W, CvType.CV_8UC3 );
+ Mat rook_image = Mat.zeros( W, W, CvType.CV_8UC3 );
+ //! [create_images]
+
+ //! [draw_atom]
+ /// 1. Draw a simple atom:
+ /// -----------------------
+ MyEllipse( atom_image, 90.0 );
+ MyEllipse( atom_image, 0.0 );
+ MyEllipse( atom_image, 45.0 );
+ MyEllipse( atom_image, -45.0 );
+
+ /// 1.b. Creating circles
+ MyFilledCircle( atom_image, new Point( W/2, W/2) );
+ //! [draw_atom]
+
+ //! [draw_rook]
+ /// 2. Draw a rook
+ /// ------------------
+ /// 2.a. Create a convex polygon
+ MyPolygon( rook_image );
+
+ //! [rectangle]
+ /// 2.b. Creating rectangles
+ Imgproc.rectangle( rook_image,
+ new Point( 0, 7*W/8 ),
+ new Point( W, W),
+ new Scalar( 0, 255, 255 ),
+ -1,
+ 8,
+ 0 );
+ //! [rectangle]
+
+ /// 2.c. Create a few lines
+ MyLine( rook_image, new Point( 0, 15*W/16 ), new Point( W, 15*W/16 ) );
+ MyLine( rook_image, new Point( W/4, 7*W/8 ), new Point( W/4, W ) );
+ MyLine( rook_image, new Point( W/2, 7*W/8 ), new Point( W/2, W ) );
+ MyLine( rook_image, new Point( 3*W/4, 7*W/8 ), new Point( 3*W/4, W ) );
+ //! [draw_rook]
+
+ /// 3. Display your stuff!
+ HighGui.imshow( atom_window, atom_image );
+ HighGui.moveWindow( atom_window, 0, 200 );
+ HighGui.imshow( rook_window, rook_image );
+ HighGui.moveWindow( rook_window, W, 200 );
+
+ HighGui.waitKey( 0 );
+ System.exit(0);
+ }
+
+ /// Function Declaration
+
+ /**
+ * @function MyEllipse
+ * @brief Draw a fixed-size ellipse with different angles
+ */
+ //! [my_ellipse]
+ private void MyEllipse( Mat img, double angle ) {
+ int thickness = 2;
+ int lineType = 8;
+ int shift = 0;
+
+ Imgproc.ellipse( img,
+ new Point( W/2, W/2 ),
+ new Size( W/4, W/16 ),
+ angle,
+ 0.0,
+ 360.0,
+ new Scalar( 255, 0, 0 ),
+ thickness,
+ lineType,
+ shift );
+ }
+ //! [my_ellipse]
+ /**
+ * @function MyFilledCircle
+ * @brief Draw a fixed-size filled circle
+ */
+ //! [my_filled_circle]
+ private void MyFilledCircle( Mat img, Point center ) {
+ int thickness = -1;
+ int lineType = 8;
+ int shift = 0;
+
+ Imgproc.circle( img,
+ center,
+ W/32,
+ new Scalar( 0, 0, 255 ),
+ thickness,
+ lineType,
+ shift );
+ }
+ //! [my_filled_circle]
+ /**
+ * @function MyPolygon
+ * @function Draw a simple concave polygon (rook)
+ */
+ //! [my_polygon]
+ private void MyPolygon( Mat img ) {
+ int lineType = 8;
+ int shift = 0;
+
+ /** Create some points */
+ Point[] rook_points = new Point[20];
+ rook_points[0] = new Point( W/4, 7*W/8 );
+ rook_points[1] = new Point( 3*W/4, 7*W/8 );
+ rook_points[2] = new Point( 3*W/4, 13*W/16 );
+ rook_points[3] = new Point( 11*W/16, 13*W/16 );
+ rook_points[4] = new Point( 19*W/32, 3*W/8 );
+ rook_points[5] = new Point( 3*W/4, 3*W/8 );
+ rook_points[6] = new Point( 3*W/4, W/8 );
+ rook_points[7] = new Point( 26*W/40, W/8 );
+ rook_points[8] = new Point( 26*W/40, W/4 );
+ rook_points[9] = new Point( 22*W/40, W/4 );
+ rook_points[10] = new Point( 22*W/40, W/8 );
+ rook_points[11] = new Point( 18*W/40, W/8 );
+ rook_points[12] = new Point( 18*W/40, W/4 );
+ rook_points[13] = new Point( 14*W/40, W/4 );
+ rook_points[14] = new Point( 14*W/40, W/8 );
+ rook_points[15] = new Point( W/4, W/8 );
+ rook_points[16] = new Point( W/4, 3*W/8 );
+ rook_points[17] = new Point( 13*W/32, 3*W/8 );
+ rook_points[18] = new Point( 5*W/16, 13*W/16 );
+ rook_points[19] = new Point( W/4, 13*W/16 );
+
+ MatOfPoint matPt = new MatOfPoint();
+ matPt.fromArray(rook_points);
+
+ List<MatOfPoint> ppt = new ArrayList<MatOfPoint>();
+ ppt.add(matPt);
+
+ Imgproc.fillPoly(img,
+ ppt,
+ new Scalar( 255, 255, 255 ),
+ lineType,
+ shift,
+ new Point(0,0) );
+ }
+ //! [my_polygon]
+ /**
+ * @function MyLine
+ * @brief Draw a simple line
+ */
+ //! [my_line]
+ private void MyLine( Mat img, Point start, Point end ) {
+ int thickness = 2;
+ int lineType = 8;
+ int shift = 0;
+
+ Imgproc.line( img,
+ start,
+ end,
+ new Scalar( 0, 0, 0 ),
+ thickness,
+ lineType,
+ shift );
+ }
+ //! [my_line]
+}
+
+public class BasicGeometricDrawing {
+ public static void main(String[] args) {
+ // Load the native library.
+ System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+ new GeometricDrawingRun().run();
+ }
+}
--- /dev/null
+import cv2
+import numpy as np
+
+W = 400
+## [my_ellipse]
+def my_ellipse(img, angle):
+ thickness = 2
+ line_type = 8
+
+ cv2.ellipse(img,
+ (W / 2, W / 2),
+ (W / 4, W / 16),
+ angle,
+ 0,
+ 360,
+ (255, 0, 0),
+ thickness,
+ line_type)
+## [my_ellipse]
+## [my_filled_circle]
+def my_filled_circle(img, center):
+ thickness = -1
+ line_type = 8
+
+ cv2.circle(img,
+ center,
+ W / 32,
+ (0, 0, 255),
+ thickness,
+ line_type)
+## [my_filled_circle]
+## [my_polygon]
+def my_polygon(img):
+ line_type = 8
+
+ # Create some points
+ ppt = np.array([[W / 4, 7 * W / 8], [3 * W / 4, 7 * W / 8],
+ [3 * W / 4, 13 * W / 16], [11 * W / 16, 13 * W / 16],
+ [19 * W / 32, 3 * W / 8], [3 * W / 4, 3 * W / 8],
+ [3 * W / 4, W / 8], [26 * W / 40, W / 8],
+ [26 * W / 40, W / 4], [22 * W / 40, W / 4],
+ [22 * W / 40, W / 8], [18 * W / 40, W / 8],
+ [18 * W / 40, W / 4], [14 * W / 40, W / 4],
+ [14 * W / 40, W / 8], [W / 4, W / 8],
+ [W / 4, 3 * W / 8], [13 * W / 32, 3 * W / 8],
+ [5 * W / 16, 13 * W / 16], [W / 4, 13 * W / 16]], np.int32)
+ ppt = ppt.reshape((-1, 1, 2))
+ cv2.fillPoly(img, [ppt], (255, 255, 255), line_type)
+ # Only drawind the lines would be:
+ # cv2.polylines(img, [ppt], True, (255, 0, 255), line_type)
+## [my_polygon]
+## [my_line]
+def my_line(img, start, end):
+ thickness = 2
+ line_type = 8
+
+ cv2.line(img,
+ start,
+ end,
+ (0, 0, 0),
+ thickness,
+ line_type)
+## [my_line]
+## [create_images]
+# Windows names
+atom_window = "Drawing 1: Atom"
+rook_window = "Drawing 2: Rook"
+
+# Create black empty images
+size = W, W, 3
+atom_image = np.zeros(size, dtype=np.uint8)
+rook_image = np.zeros(size, dtype=np.uint8)
+## [create_images]
+## [draw_atom]
+# 1. Draw a simple atom:
+# -----------------------
+
+# 1.a. Creating ellipses
+my_ellipse(atom_image, 90)
+my_ellipse(atom_image, 0)
+my_ellipse(atom_image, 45)
+my_ellipse(atom_image, -45)
+
+# 1.b. Creating circles
+my_filled_circle(atom_image, (W / 2, W / 2))
+## [draw_atom]
+## [draw_rook]
+
+# 2. Draw a rook
+# ------------------
+# 2.a. Create a convex polygon
+my_polygon(rook_image)
+## [rectangle]
+# 2.b. Creating rectangles
+cv2.rectangle(rook_image,
+ (0, 7 * W / 8),
+ (W, W),
+ (0, 255, 255),
+ -1,
+ 8)
+## [rectangle]
+
+# 2.c. Create a few lines
+my_line(rook_image, (0, 15 * W / 16), (W, 15 * W / 16))
+my_line(rook_image, (W / 4, 7 * W / 8), (W / 4, W))
+my_line(rook_image, (W / 2, 7 * W / 8), (W / 2, W))
+my_line(rook_image, (3 * W / 4, 7 * W / 8), (3 * W / 4, W))
+## [draw_rook]
+cv2.imshow(atom_window, atom_image)
+cv2.moveWindow(atom_window, 0, 200)
+cv2.imshow(rook_window, rook_image)
+cv2.moveWindow(rook_window, W, 200)
+
+cv2.waitKey(0)
+cv2.destroyAllWindows()