因为要涉及到图像处理部分,所以需要整体第学习opencv的代码,以供后面项目上使用。
需要快速完成这个库的练习和使用。
大概需要两个星期的时间掌握c++以及java库的编写工作。
首先是安装opencv
然后根据官网的教程进行make make install的安装。
第一章 Introduction to OpenCV
这章介绍了opencv在各个版本上的安装过程,有些安装过程已经很老了,比如android部分,所以需要对cmake有一定的掌握。
现在写app都是用android studio,不过已经包含了opencv-sdk,这部分的安装可以查看之前的文章。
这章主要的小节有
1. Installation in Linux
2. Using OpenCV with gcc and CMake
3. Load and Display an Image
4. Load, Modify, and Save an Image
第一节 在ubuntu上安装opencv
需要安装一下库工具之类的程序
[compiler] sudo apt-get install build-essential
[required] sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
[optional] sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff5-dev libjasper-dev libdc1394-22-dev
安装完成之后下载
git clone https://github.com/opencv/opencv.git
下载完成之后开始编译
cmake的时候可以增加BUILD_DOCS,编译生成文档
cd ~/opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
make -j7
sudo make install
第二节 显示图像
这里是用网页来显示图像所以ishow没什么作用,具体还是需要读取图像,然后保存,传递给php,进行网页前端显示。
这里需要指定保存的路径,然后php根据保存的路径进行显示,前面的文章已经介绍过,这里不再介绍。
所以还是需要通过php端读取数据,交给opencv处理保存,然后还是通过php读取数据返回给nginx服务器,显示到客户端。
DisplayImage.cpp文件只是读取文件到Mat结构体中
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char** argv )
{
if ( argc != 2 )
{
printf("usage: DisplayImage.out <Image_Path>\n");
return -1;
}
Mat image;
image = imread( argv[1], 1 );
if ( !image.data )
{
printf("No image data \n");
return -1;
}
namedWindow("Display Image", WINDOW_AUTOSIZE );
imshow("Display Image", image);
waitKey(0);
return 0;
}
然后编写cmake文件,记得文件名大小写不要错。
CMakeLists.txt file
cmake_minimum_required(VERSION 2.8)
project( DisplayImage )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( DisplayImage DisplayImage.cpp )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )
cmake make
然后运行
最好在窗口中显示结果。
第三节 加载和显示图片
和第二小节是重复的
第四节 加载修改和保存图片
这小节使用cvrColor将图片从BGR颜色变成Grayscale颜色模式,然后进行保存。
#include <opencv2/opencv.hpp>
using namespace cv;
int main( int argc, char** argv )
{
char* imageName = argv[1];
Mat image;
image = imread( imageName, IMREAD_COLOR );
if( argc != 2 || !image.data )
{
printf( " No image data \n " );
return -1;
}
Mat gray_image;
cvtColor( image, gray_image, COLOR_BGR2GRAY );
imwrite( "../../images/Gray_Image.jpg", gray_image );
namedWindow( imageName, WINDOW_AUTOSIZE );
namedWindow( "Gray image", WINDOW_AUTOSIZE );
imshow( imageName, image );
imshow( "Gray image", gray_image );
waitKey(0);
return 0;
}
没什么好讲的,就是一个cvtColor函数。
第二章 OpenCV核心模块功能介绍
1. Mat - The Basic Image Container
2. How to scan images, lookup tables and time measurement with OpenCV
3. Mask operations on matrices
4. Operations with images
5. Adding (blending) two images using OpenCV
6. Changing the contrast and brightness of an image!
7. Basic Drawing
8. Random generator and text with OpenCV
9. Discrete Fourier Transform
第一节 图片矩阵
The first thing you need to know about Mat is that you no longer need to manually allocate its memory and release it as soon as you do not need it.
Mat is basically a class with two data parts: the matrix header and a pointer to the matrix containing the pixel values.
OpenCV使用引用,Moreover, the copy operators will only copy the headers and the pointer to the large matrix, not the data itself.
Mat A, C; // creates just the header parts
A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix)
Mat B(A); // Use the copy constructor
C = A; // Assignment operator
这几个都只是复制了矩阵的头,没有作实际的数据copy.
roi感兴趣的区域
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
一个大矩阵中圈出一个小矩阵
Mat 有自动回收机制,所以在赋值的时候count自动加1,当count值为0的时候就会释放该内存。
clone和copyTo两个函数进行的实际的数据copy
Mat F = A.clone();
Mat G;
A.copyTo(G);
现在如果改变F或者G就不会影响到A的数据。
Mat结构的创建模式
几个参数,
Mat M(2,2, CV_8UC3, Scalar(0,0,255));
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]这几个参数的解释,对应CV_8UC3
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));
创建多维数组。
第二节 遍历图形像素和需要时间对比
这章列出了四种方法进行一张图片的遍历,举的例子就是缩小原来的图片的大小,减少计算量。
原理是这样的,设置一个除数值,所有的像素除以这个数,再乘以这个数,会得到这个数的整数倍,除数越大,计算量越小。
这里没有让每个数进行乘除运算,而是进行查表操作。
首先是获取这张表格,这里用的是8位的unsigned char类型,这样数据也已经很大。
how_to_scan_images imageName.jpg intValueToReduce [G]
G表示传送灰度图。
这里是获取表格的算法
int divideWith = 0; // convert our input string to number - C++ style
stringstream s;
s << argv[2];
s >> divideWith;
if (!s || !divideWith)
{
cout << "Invalid number entered for dividing. " << endl;
return -1;
}
uchar table[256];
for (int i = 0; i < 256; ++i)
table[i] = (uchar)(divideWith * (i/divideWith));
然后计算时间的算法
double t = (double)getTickCount();
// do something ...
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
图片是怎么保存的呢?下面的这张图片很清晰第反应了如何保存。
row是排, column是列,bgr每个有三列
1.有效的计算方式是这样的
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
int channels = I.channels();
int nRows = I.rows;
int nCols = I.cols * channels;
if (I.isContinuous())
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
Mat 是传入的图片数据,将这个矩阵转换成为只有一排,然后有R * C * channels列的一个vector.
然后进行转换操作,通过改变p相应的Mat结构数组里面的内容也会改变。
2. 迭代方法
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch(channels)
{
case 1:
{
MatIterator_<uchar> it, end;
for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
*it = table[*it];
break;
}
case 3:
{
MatIterator_<Vec3b> it, end;
for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
{
(*it)[0] = table[(*it)[0]];
(*it)[1] = table[(*it)[1]];
(*it)[2] = table[(*it)[2]];
}
}
}
return I;
}
利用了Iterator,c++不过关的同学继续回去复习c++,这里使用了迭代器从头迭代到尾。
MatIterator_<>是新建立的一个泛型迭代类。
3. 通过vector的方法
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch(channels)
{
case 1:
{
for( int i = 0; i < I.rows; ++i)
for( int j = 0; j < I.cols; ++j )
I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
break;
}
case 3:
{
Mat_<Vec3b> _I = I;
for( int i = 0; i < I.rows; ++i)
for( int j = 0; j < I.cols; ++j )
{
_I(i,j)[0] = table[_I(i,j)[0]];
_I(i,j)[1] = table[_I(i,j)[1]];
_I(i,j)[2] = table[_I(i,j)[2]];
}
I = _I;
break;
}
}
return I;
}
这种方法所花的时间最高,所以这里并不作深究。
4. 核心函数所采用的方法
需要的时间最短,其它的一半都不到。
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
p[i] = table[i];
首先查看Mat的构造器
cv::Mat::Mat ( int rows,
int cols,
int type
)
第一个是拍,第二个是列,第三个是类型,这里很明显第一步是构建一个查询的table,跟前面的方式一样。
uchar *p = lookUpTable.ptr()应该是作为引用拷贝,通过*p来改变数组的lookUpTable中的值。
最后调用这个函数
Finally call the function (I is our input image and J the output one):
LUT(I, lookUpTable, J);
章节的最后附上了一个示例来比较这四种方法。
具体的程序在
https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp
可以看出来,自己电脑上的输出结果,LUT明显快很多。
wang@wang:~/test/opencvproject$ ./how_to_scan_images ~/IMG_9362_1.JPG 15
./how_to_scan_images <imageNameToUse <divideWith> [G]
If you add a G parameter the image is processed in gray scale
Time of reducing with the C operator [] (average for100 runs): 87.0279 milliseconds.
Time of reducing with the iterator (average for 100 runs): 330.479 milliseconds.
Time of reducing with the on-the-fly address generation - at function (average for 100 runs): 344.312 milliseconds.
Time of reducing with the LUT function (arverage for 100 runs): 7.82402 milliseconds.
第三节 矩阵的掩位操作
通过一个mask matrix(也称为kernel)重新计算每个像素的值。
这个值表达了临近的像素值对于该像素值的权重比。
下面是一个图像对比增强的例子,每种图形都采用下面的计算公式
想不明白上面的公式是怎么等价的,矩阵线性代数没有学习好。
void Sharpen(const Mat& myImage,Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); // accept only uchar images
const int nChannels = myImage.channels();
Result.create(myImage.size(),myImage.type());
for(int j = 1 ; j < myImage.rows-1; ++j)
{
const uchar* previous = myImage.ptr<uchar>(j - 1);
const uchar* current = myImage.ptr<uchar>(j );
const uchar* next = myImage.ptr<uchar>(j + 1);
uchar* output = Result.ptr<uchar>(j);
for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
{
*output++ = saturate_cast<uchar>(5*current[i]
-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
}
}
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows-1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols-1).setTo(Scalar(0));
}
真有点不好理解。
有一个核,kernel
Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
使用这个函数变模糊
filter2D( src, dst1, src.depth(), kernel );
Returns a pointer to the specified matrix row.
The methods return uchar* or typed pointer to the specified matrix row. See the sample in Mat::isContinuous to know how to use these methods.
Parameters
i0 A 0-based row index.
Examples:
image_alignment.cpp.
那个ptr是干嘛用的,如果深入看里面的计算,对于语言的理解很大的帮助。
参考示例,好像让图片变得更加清晰。
第四章 文件的基本操作
文件输入imread
8UC1单通道读入单个像素
Scalar intensity = img.at<uchar>(y, x);
多通道,然后可以读取bgr值
Vec3b intensity = img.at<Vec3b>(y, x);
也可以是float类型
Vec3f intensity = img.at<Vec3f>(y, x);
修改某个像素值反过来。
Selecting a region of interest
Rect r(10, 10, 100, 100);
Mat smallImg = img(r);
第五节 两个图形混合
这章主要学习线性混合,使用cv::addWeighted()函数
举了一个示例。
void cv::addWeighted ( InputArray src1,
double alpha,
InputArray src2,
double beta,
double gamma,
OutputArray dst,
int dtype = -1
)
Calculates the weighted sum of two arrays.
The function addWeighted calculates the weighted sum of two arrays as follows:
dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma)
where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed independently. The function can be replaced with a matrix expression:
dst = src1*alpha + src2*beta + gamma;
Note
Saturation is not applied when the output array has the depth CV_32S. You may even get result of an incorrect sign in the case of overflow.
Parameters
src1 first input array.
alpha weight of the first array elements.
src2 second input array of the same size and channel number as src1.
beta weight of the second array elements.
gamma scalar added to each sum.
dst output array that has the same size and number of channels as the input arrays.
dtype optional depth of the output array; when both input arrays have the same depth, dtype can be set to -1, which will be equivalent to src1.depth().
第六节 改变图片的对比度
g(x)=(1−α)f0(x)+α
对比度和亮度比较。
需要传入三个参数
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main(int argc, char *argv[]) {
double alpha = 1.0; // simple contrast control
int beta = 0; // simple brightness control
string imageName = argv[1];
alpha = stod(argv[2]);
beta = stoi(argv[3]);
Mat image =imread(imageName);
Mat new_image = Mat::zeros(image.size(), image.type());
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
for (int c = 0; c < 3; c++) {
new_image.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>(alpha*(image.at<Vec3b>(y,x)[c]) + beta);
}
}
}
imwrite("brightness.jpg", new_image);
return 0;
}
增加p的值在255溢出之后重新回到0值。
gamma校正
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma_) * 255.0);
Mat res = img.clone();
LUT(img, lookUpTable, res);
第七节 基本绘图
Point绘制点。
line, ellipse rectangle circle polygon
Scalar(a, b, c)定义abc值为多少。
#include <opencv2/opencv.hpp>
using namespace cv;
#define w 400
void MyEllipse(Mat img, double angle);
void MyFilledCircle(Mat img, Point center);
void MyPolygon(Mat img);
void MyLine(Mat img, Point start, Point end);
int main() {
char atom_window[] = "Drawing 1: Atom";
char rook_window[] = "Drawing 2: Rook";
Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
Mat rook_image = Mat::zeros( w, w, CV_8UC3 );
MyEllipse( atom_image, 90 );
MyEllipse( atom_image, 0 );
MyEllipse( atom_image, 45 );
MyEllipse( atom_image, -45 );
MyFilledCircle( atom_image, Point( w/2, w/2) );
MyPolygon( rook_image );
rectangle( rook_image,
Point( 0, 7*w/8 ),
Point( w, w),
Scalar( 0, 255, 255 ),
FILLED,
LINE_8 );
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 ) );
imshow( atom_window, atom_image );
moveWindow( atom_window, 0, 200 );
imshow( rook_window, rook_image );
moveWindow( rook_window, w, 200 );
waitKey( 0 );
return(0);
}
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 );
}
void MyFilledCircle( Mat img, Point center )
{
circle( img,
center,
w/32,
Scalar( 0, 0, 255 ),
FILLED,
LINE_8 );
}
void MyPolygon( Mat img )
{
int lineType = LINE_8;
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 );
}
void MyLine( Mat img, Point start, Point end )
{
int thickness = 2;
int lineType = LINE_8;
line( img,
start,
end,
Scalar( 0, 0, 0 ),
thickness,
lineType );
}
第七节 随机生成器
使用RNG生成统一分布
使用putText生成文本。
#include <opencv2/opencv.hpp>
#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,100)*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;
}
第八节 离散傅里叶变换
第九节 使用xml作为文件输入输出
第十节 多线程编程