目标:
在这个教程中你将学会:
使用随机数生成类(RNG)并且如何从一个均匀分布中得到一个随机数;
使用putText函数在OpenCV窗口中显示文本;
代码:
在之前的教程中我们通过给定输入参数例如坐标,颜色,线宽等来绘制了各种不同的几何图形。你可能已经注意到了我们对每个参数给定了特定的值。
在这个教程中,我们打算对这些参数使用随机数。同时,我们打算让很多几何图形来填充我们的图像。因为我们使用随机数的方式来初始化这些参数,因此这个过程将会使用一个循环来自动进行。
代码如下:
/* Random generator and Text with OpenCV
* Author:York
* Email:y_zhou1991@163.com
* Date:2016/03/04
*/
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <stdio.h>
using namespace cv;
/// Global Variables
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";
/// 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);
/// 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 definitions
/**
* @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];
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 };
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];
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.15, 5.1)/*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;
}
解释:
1、 让我们先来看一下主函数,我们可以看到我们做的第一件事就是先创建一个随机数生成器的对象。
RNG rng(oxFFFFFFFF);
RNG实现一个随机数生成器,在这个例子中,rng是一个以0xFFFFFFFF初始化的RNG元素。
2、 然后我们创建一个矩阵并初始化为0.指定它的高,宽和类型:
Mat image=Mat::zeros(window_height,window_width,CV_8UC3);
Imshow(window_name,image);
3、 然后我们就开始绘制一些比较疯狂的东西。代码可以分成8个部分,分别被定义为了函数:
/// 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 );
所有的函数都是遵循同样的模式,所以我们可以只分析他们中的几个就可以了。
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;
}
我们可以看到:
For循环将重复NUMBER次,因为line函数在循环里面,这就意味着将会产生NUMBER条直线。
直线的两个端点由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之间的一个随机均匀分布。
从上面的解释我们可以知道直线的两个端点pt1和pt2将是随机值。所以直线的位置是不可预知的,这将产生一个很好的视觉效果。
另外,我们还可以看到line的参数,颜色的输入我们是这样确定的:
randomColor(rng);
让我们来看一下这个函数的实现:
Static Scalar randomColor(RNG& rng)
{
Int icolor=(unsigned)rng;
Return Scalar(icolor&255,(icolor>>8)&255,(icolor>>16)&255);
}
正如我们所看到的,返回值是一个由3个随机数初始化的Scalar,因此,直线的颜色也将是随机的。
1、 上面的解释对于其他函数同样是适用的,诸如中心点以及顶点这些参数也都是随机数。
2、 在结束之前,我们也应该看一下函数Display_Random_Text以及Display_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);
这个函数是做什么的?在我们这个例子中:
在image图像中绘制文本”Testingtext 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个文本。
1、 Display_Big_End
int Displaying_Big_End( Mat image, char* window_name, RNG rng )
{
Size textsize = getTextSize("OpenCV forever!", CV_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, CV_FONT_HERSHEY_COMPLEX, 3,
Scalar(i, i, 255), 5, lineType );
imshow( window_name, image2 );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
除了函数getTextSize(这将得到文本的尺寸),在for循环中我们可以看到新的操作:
Image2=image-Scalar::all(i)
所以,image2是image减去Scalar::all(i)得到的。实际上,在image2中的每一个像素都是image图像的对应像素减去一个i值得到的结果。
同样需要记住的是在这个减操作的内部是包含有saturate操作的,这就意味着所获得的结果都将在允许的范围内。