让我们通过一个程序实例的学习来掌握OpenCV中各种绘制函数的用法。a:用于绘制直线的line函数;
b:用于绘制椭圆的ellipse函数;c:用于绘制矩形的rectangle函数;d:用于绘制圆的circle函数;
e:用于绘制填充的多边形的fillPoly函数。
1、DrawEllipse()的写法
void DrawEllipse(Mat img, double angle)
{
int thickness = 2;
int lineType = 8;
ellipse(img,//将椭圆画到img图像上
Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2),//椭圆中心点
Size(WINDOW_WIDTH/4, WINDOW_WIDTH/16),//椭圆长度
angle,//椭圆旋转角度
0,//扩展弧度从0度到360度
360,
Scalar(255, 129, 0),//图形颜色为蓝色
thickness,//线宽
lineType);//线型
}
自定义的绘制函数,实现了绘制不同角度、相同尺寸的椭圆,函数中DrawElipse调用了OpenCV中的ellipse函数,将椭圆画到图像img上。
2、DrawFilledCircle()函数的写法
void DrawFilledCircle( Mat img, Point center )
{
int thickness = -1;
int lineType = 8;
circle( img,
center,//圆心由点center定义
WINDOW_WIDTH/32,//圆的半径
Scalar( 0, 0, 255 ),圆的颜色
thickness,//线粗
lineType );
}
DrawFilledCircle()调用了OpenCV中的circle函数,将圆画到图像img上。
3、DrawPolygon()函数的写法
void DrawPolygon( Mat img )
{
int lineType = 8;
//创建一些点
Point rookPoints[1][20];
rookPoints[0][0] = Point( WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8 );
rookPoints[0][1] = Point( 3*WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8 );
rookPoints[0][2] = Point( 3*WINDOW_WIDTH/4, 13*WINDOW_WIDTH/16 );
rookPoints[0][3] = Point( 11*WINDOW_WIDTH/16, 13*WINDOW_WIDTH/16 );
rookPoints[0][4] = Point( 19*WINDOW_WIDTH/32, 3*WINDOW_WIDTH/8 );
rookPoints[0][5] = Point( 3*WINDOW_WIDTH/4, 3*WINDOW_WIDTH/8 );
rookPoints[0][6] = Point( 3*WINDOW_WIDTH/4, WINDOW_WIDTH/8 );
rookPoints[0][7] = Point( 26*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][8] = Point( 26*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][9] = Point( 22*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][10] = Point( 22*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][11] = Point( 18*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][12] = Point( 18*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][13] = Point( 14*WINDOW_WIDTH/40, WINDOW_WIDTH/4 );
rookPoints[0][14] = Point( 14*WINDOW_WIDTH/40, WINDOW_WIDTH/8 );
rookPoints[0][15] = Point( WINDOW_WIDTH/4, WINDOW_WIDTH/8 );
rookPoints[0][16] = Point( WINDOW_WIDTH/4, 3*WINDOW_WIDTH/8 );
rookPoints[0][17] = Point( 13*WINDOW_WIDTH/32, 3*WINDOW_WIDTH/8 );
rookPoints[0][18] = Point( 5*WINDOW_WIDTH/16, 13*WINDOW_WIDTH/16 );
rookPoints[0][19] = Point( WINDOW_WIDTH/4, 13*WINDOW_WIDTH/16 );
const Point* ppt[1] = { rookPoints[0] };
int npt[] = { 20 };
fillPoly( img,
ppt, //多边形的顶点集
npt, //多边形定点数目
1, //多边形数量
Scalar( 255, 255, 255 ), //多边形的颜色
lineType );
}
DrawPolygon()调用了OpenCV的fillPoly函数,将多边形画到图像img上。
4、DrawLine()函数的写法
void DrawLine( Mat img, Point start, Point end )
{
int thickness = 2;
int lineType = 8;
line( img,
start, //线段始点
end, //线段终点
Scalar( 0, 0, 0 ), //黑色线条
thickness, //线粗
lineType );
}
DrawLine()调用了OpenCV中的line函数,用于在图像img上画一条直线段。
下面看看整体效果:
#include
#include
using namespace cv;
//OpenCV3需加入头文件:
#include
//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME1 "【绘制图1】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【绘制图2】" //为窗口标题定义的宏
#define WINDOW_WIDTH 600//定义窗口大小的宏
//--------------------------------【全局函数声明部分】-------------------------------------
// 描述:全局函数声明
//-----------------------------------------------------------------------------------------------
void DrawEllipse( Mat img, double angle );//绘制椭圆
void DrawFilledCircle( Mat img, Point center );//绘制圆
void DrawPolygon( Mat img );//绘制多边形
void DrawLine( Mat img, Point start, Point end );//绘制线段
//---------------------------------------【main( )函数】--------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main( void )
{
// 创建空白的Mat图像
Mat atomImage = Mat::zeros( WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3 );
Mat rookImage = Mat::zeros( WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3 );
// ---------------------<1>绘制化学中的原子示例图------------------------
//【1.1】先绘制出椭圆
DrawEllipse( atomImage, 90 );
DrawEllipse( atomImage, 0 );
DrawEllipse( atomImage, 45 );
DrawEllipse( atomImage, -45 );
//【1.2】再绘制圆心
DrawFilledCircle( atomImage, Point( WINDOW_WIDTH/2, WINDOW_WIDTH/2) );
// ----------------------------<2>绘制组合图-----------------------------
//【2.1】先绘制出椭圆
DrawPolygon( rookImage );
// 【2.2】绘制矩形
rectangle( rookImage,
Point( 0, 7*WINDOW_WIDTH/8 ),
Point( WINDOW_WIDTH, WINDOW_WIDTH),
Scalar( 0, 255, 255 ),
-1,
8 );
// 【2.3】绘制一些线段
DrawLine( rookImage, Point( 0, 15*WINDOW_WIDTH/16 ), Point( WINDOW_WIDTH, 15*WINDOW_WIDTH/16 ) );
DrawLine( rookImage, Point( WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8 ), Point( WINDOW_WIDTH/4, WINDOW_WIDTH ) );
DrawLine( rookImage, Point( WINDOW_WIDTH/2, 7*WINDOW_WIDTH/8 ), Point( WINDOW_WIDTH/2, WINDOW_WIDTH ) );
DrawLine( rookImage, Point( 3*WINDOW_WIDTH/4, 7*WINDOW_WIDTH/8 ), Point( 3*WINDOW_WIDTH/4, WINDOW_WIDTH ) );
// ---------------------------<3>显示绘制出的图像------------------------
imshow( WINDOW_NAME1, atomImage );
moveWindow( WINDOW_NAME1, 0, 200 );
imshow( WINDOW_NAME2, rookImage );
moveWindow( WINDOW_NAME2, WINDOW_WIDTH, 200 );
waitKey( 0 );
return(0);
}
/访问图像的像素
#include
#include
#include
using namespace cv;
using namespace std;
void colorReduce(Mat& inputImage, Mat&outputImage, int div);
int main()
{
Mat srcImage = imread("group.jpg");
imshow("原始图像", srcImage);
Mat dstImage;
dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());
double time0 = static_cast(getTickCount());//记录起始时间
colorReduce(srcImage, dstImage, 32);//调用
time0 = ((double)getTickCount() - time0) / getTickFrequency();//计算运行时间并输出
cout << "此方法运行时间为" << time0 << "秒" << endl;
imshow("效果图", dstImage);//显示效果图
waitKey(0);
}
void colorReduce(Mat& inputImage, Mat& outputImage, int div)//颜色空间缩减函数,使用指针访问像素
{
outputImage = inputImage.clone();//复制实参到临时变量
int rowNumber = outputImage.rows;//行数
int colNumber = outputImage.cols*outputImage.channels();//列数*通道数=每一行元素的个数
for (int i = 0; i < rowNumber; i++)//双重循环,遍历所有像素值,行循环开始
{
uchar*data = outputImage.ptr(i);//获取第i行的首地址
for (int j = 0; j < colNumber; j++)//列循环
{//开始处理每个像素
data[j] = data[j] / div * div + div / 2;
}//处理结束
}
}
效果如下:
遍历像素的十四种方法:
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序24
// 程序描述:来自一本国外OpenCV2书籍的示例-遍历图像像素的14种方法
// 测试所用IDE版本:Visual Studio 2010
// 测试所用OpenCV版本: 2.4.9
// 2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------
/*------------------------------------------------------------------------------------------*\
This file contains material supporting chapter 2 of the cookbook:
Computer Vision Programming using the OpenCV Library.
by Robert Laganiere, Packt Publishing, 2011.
This program is free software; permission is hereby granted to use, copy, modify,
and distribute this source code, or portions thereof, for any purpose, without fee,
subject to the restriction that the copyright notice may not be removed
or altered from any source or altered source distribution.
The software is released on an as-is basis and without any warranties of any kind.
In particular, the software is not guaranteed to be fault-tolerant or free from failure.
The author disclaims all warranties with regard to this software, any use,
and any consequent failure, is purely the responsibility of the user.
Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*/
//---------------------------------【头文件、命名空间包含部分】-----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include
#include
#include
using namespace cv;
using namespace std;
//---------------------------------【宏定义部分】---------------------------------------------
// 描述:包含程序所使用宏定义
//-------------------------------------------------------------------------------------------------
#define NTESTS 14
#define NITERATIONS 20
//----------------------------------------- 【方法一】-------------------------------------------
// 说明:利用.ptr 和 []
//-------------------------------------------------------------------------------------------------
void colorReduce0(Mat &image, int div=64) {
int nl= image.rows; //行数
int nc= image.cols * image.channels(); //每行元素的总元素数量
for (int j=0; j(j);
for (int i=0; i(j);
for (int i=0; i(j);
for (int i=0; i(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<(j);
for (int i=0; i(log(static_cast(div))/log(2.0));
int step= image.step; //有效宽度
//掩码值
uchar mask= 0xFF<(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<(j);
for (int i=0; i(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<(j);
for (int i=0; i(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<(j);
for (int i=0; i::iterator it= image.begin();
Mat_::iterator itend= image.end();
for ( ; it!= itend; ++it) {
//-------------开始处理每个像素-------------------
(*it)[0]= (*it)[0]/div*div + div/2;
(*it)[1]= (*it)[1]/div*div + div/2;
(*it)[2]= (*it)[2]/div*div + div/2;
//-------------结束像素处理------------------------
}//单行处理结束
}
//-------------------------------------【方法十】-----------------------------------------------
// 说明:利用Mat_ iterator以及位运算
//-------------------------------------------------------------------------------------------------
void colorReduce9(Mat &image, int div=64) {
// div必须是2的幂
int n= static_cast(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<::iterator it= image.begin();
Mat_::iterator itend= image.end();
//扫描所有元素
for ( ; it!= itend; ++it)
{
//-------------开始处理每个像素-------------------
(*it)[0]= (*it)[0]&mask + div/2;
(*it)[1]= (*it)[1]&mask + div/2;
(*it)[2]= (*it)[2]&mask + div/2;
//-------------结束像素处理------------------------
}//单行处理结束
}
//------------------------------------【方法十一】---------------------------------------------
// 说明:利用Mat Iterator_
//-------------------------------------------------------------------------------------------------
void colorReduce10(Mat &image, int div=64) {
//获取迭代器
Mat_ cimage= image;
Mat_::iterator it=cimage.begin();
Mat_::iterator itend=cimage.end();
for ( ; it!= itend; it++) {
//-------------开始处理每个像素-------------------
(*it)[0]= (*it)[0]/div*div + div/2;
(*it)[1]= (*it)[1]/div*div + div/2;
(*it)[2]= (*it)[2]/div*div + div/2;
//-------------结束像素处理------------------------
}
}
//--------------------------------------【方法十二】--------------------------------------------
// 说明:利用动态地址计算配合at
//-------------------------------------------------------------------------------------------------
void colorReduce11(Mat &image, int div=64) {
int nl= image.rows; //行数
int nc= image.cols; //列数
for (int j=0; j(j,i)[0]= image.at(j,i)[0]/div*div + div/2;
image.at(j,i)[1]= image.at(j,i)[1]/div*div + div/2;
image.at(j,i)[2]= image.at(j,i)[2]/div*div + div/2;
//-------------结束像素处理------------------------
} //单行处理结束
}
}
//----------------------------------【方法十三】-----------------------------------------------
// 说明:利用图像的输入与输出
//-------------------------------------------------------------------------------------------------
void colorReduce12(const Mat &image, //输入图像
Mat &result, // 输出图像
int div=64) {
int nl= image.rows; //行数
int nc= image.cols ; //列数
//准备好初始化后的Mat给输出图像
result.create(image.rows,image.cols,image.type());
//创建无像素填充的图像
nc= nc*nl;
nl= 1; //单维数组
int n= static_cast(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<(j);
const uchar* idata= image.ptr(j);
for (int i=0; i(log(static_cast(div))/log(2.0));
//掩码值
uchar mask= 0xFF<
效果图: