--- /dev/null
- [here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_1.cpp)
+ Basic Drawing {#tutorial_basic_geometric_drawing}
+ =============
+
+ @next_tutorial{tutorial_random_generator_and_text}
+
+ Goals
+ -----
+
+ In this tutorial you will learn how to:
+
+ - 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
+ -------------
+
+ 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{.cpp}
+ Point pt;
+ pt.x = 10;
+ pt.y = 8;
+ @endcode
+ or
+ @code{.cpp}
+ Point pt = 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{.cpp}
+ 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://raw.githubusercontent.com/opencv/opencv/3.4/samples/java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java)
++ [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgProc/basic_drawing/Drawing_1.cpp)
+ @include samples/cpp/tutorial_code/ImgProc/basic_drawing/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/3.4/samples/python/tutorial_code/imgProc/BasicGeometricDrawing/basic_geometric_drawing.py)
++ [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java)
+ @include samples/java/tutorial_code/ImgProc/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/imgProc/BasicGeometricDrawing/basic_geometric_drawing.py)
+ @include samples/python/tutorial_code/imgProc/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.
+ @add_toggle_cpp
+ @snippet cpp/tutorial_code/ImgProc/basic_drawing/Drawing_1.cpp create_images
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java create_images
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp draw_atom
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java draw_atom
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp draw_rook
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java draw_rook
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp my_line
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java my_line
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp my_ellipse
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java my_ellipse
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp my_filled_circle
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java my_filled_circle
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp my_polygon
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java my_polygon
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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/ImgProc/basic_drawing/Drawing_1.cpp rectangle
+ @end_toggle
+
+ @add_toggle_java
+ @snippet java/tutorial_code/ImgProc/BasicGeometricDrawing/BasicGeometricDrawing.java rectangle
+ @end_toggle
+
+ @add_toggle_python
+ @snippet python/tutorial_code/imgProc/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
+ ------
+
+ Compiling and running your program should give you a result like this:
+
+ 
TrainData::~TrainData() {}
-Mat TrainData::getTestSamples() const
-{
- Mat idx = getTestSampleIdx();
- Mat samples = getSamples();
- return idx.empty() ? Mat() : getSubMatrix(samples, idx, getLayout());
-}
-
Mat TrainData::getSubVector(const Mat& vec, const Mat& idx)
{
- if( idx.empty() )
- return vec;
- int i, j, n = idx.checkVector(1, CV_32S);
- int type = vec.type();
- CV_Assert( type == CV_32S || type == CV_32F || type == CV_64F );
- int dims = 1, m;
+ if (!(vec.cols == 1 || vec.rows == 1))
+ CV_LOG_WARNING(NULL, "'getSubVector(const Mat& vec, const Mat& idx)' call with non-1D input is deprecated. It is not designed to work with 2D matrixes (especially with 'cv::ml::COL_SAMPLE' layout).");
+ return getSubMatrix(vec, idx, vec.rows == 1 ? cv::ml::COL_SAMPLE : cv::ml::ROW_SAMPLE);
+ }
+
+ template<typename T>
+ Mat getSubMatrixImpl(const Mat& m, const Mat& idx, int layout)
+ {
+ int nidx = idx.checkVector(1, CV_32S);
+ int dims = m.cols, nsamples = m.rows;
- if( vec.cols == 1 || vec.rows == 1 )
+ Mat subm;
+ if (layout == COL_SAMPLE)
{
- dims = 1;
- m = vec.cols + vec.rows - 1;
+ std::swap(dims, nsamples);
+ subm.create(dims, nidx, m.type());
}
else
{
- dims = vec.cols;
- m = vec.rows;
+ subm.create(nidx, dims, m.type());
}
- Mat subvec;
-
- if( vec.cols == m )
- subvec.create(dims, n, type);
- else
- subvec.create(n, dims, type);
- if( type == CV_32S )
- for( i = 0; i < n; i++ )
+ for (int i = 0; i < nidx; i++)
+ {
+ int k = idx.at<int>(i); CV_CheckGE(k, 0, "Bad idx"); CV_CheckLT(k, nsamples, "Bad idx or layout");
+ if (dims == 1)
{
- int k = idx.at<int>(i);
- CV_Assert( 0 <= k && k < m );
- if( dims == 1 )
- subvec.at<int>(i) = vec.at<int>(k);
- else
- for( j = 0; j < dims; j++ )
- subvec.at<int>(i, j) = vec.at<int>(k, j);
+ subm.at<T>(i) = m.at<T>(k); // at() has "transparent" access for 1D col-based / row-based vectors.
}
- else if( type == CV_32F )
- for( i = 0; i < n; i++ )
+ else if (layout == COL_SAMPLE)
{
- int k = idx.at<int>(i);
- CV_Assert( 0 <= k && k < m );
- if( dims == 1 )
- subvec.at<float>(i) = vec.at<float>(k);
- else
- for( j = 0; j < dims; j++ )
- subvec.at<float>(i, j) = vec.at<float>(k, j);
+ for (int j = 0; j < dims; j++)
+ subm.at<T>(j, i) = m.at<T>(j, k);
}
- else
- for( i = 0; i < n; i++ )
+ else
{
- int k = idx.at<int>(i);
- CV_Assert( 0 <= k && k < m );
- if( dims == 1 )
- subvec.at<double>(i) = vec.at<double>(k);
- else
- for( j = 0; j < dims; j++ )
- subvec.at<double>(i, j) = vec.at<double>(k, j);
+ for (int j = 0; j < dims; j++)
+ subm.at<T>(i, j) = m.at<T>(k, j);
}
- return subvec;
+ }
+ return subm;
+ }
+
+ Mat TrainData::getSubMatrix(const Mat& m, const Mat& idx, int layout)
+ {
+ if (idx.empty())
+ return m;
+ int type = m.type();
+ CV_CheckType(type, type == CV_32S || type == CV_32F || type == CV_64F, "");
+ if (type == CV_32S || type == CV_32F) // 32-bit
+ return getSubMatrixImpl<int>(m, idx, layout);
+ if (type == CV_64F) // 64-bit
+ return getSubMatrixImpl<double>(m, idx, layout);
+ CV_Error(Error::StsInternal, "");
}
+
class TrainDataImpl CV_FINAL : public TrainData
{
public:
return layout == ROW_SAMPLE ? samples.cols : samples.rows;
}
- return idx.empty() ? Mat() : getSubVector(samples, idx);
+ Mat getTestSamples() const CV_OVERRIDE
+ {
+ Mat idx = getTestSampleIdx();
++ return idx.empty() ? Mat() : getSubMatrix(samples, idx, getLayout());
+ }
+
Mat getSamples() const CV_OVERRIDE { return samples; }
Mat getResponses() const CV_OVERRIDE { return responses; }
Mat getMissing() const CV_OVERRIDE { return missing; }