【OpenCV:从零到一】07:绘制图像与文字

前言
这是我《OpenCV:从零到一》专栏的第七篇博客,想看跟多请戳
本文概要

  • 使用cv::Point与cv::Scalar
  • 绘制线、矩形、园、椭圆等基本几何形状
    • 画线 cv::line (LINE_4\LINE_8\LINE_AA)
    • 画椭圆cv::ellipse
    • 画矩形cv::rectangle
    • 画圆cv::circle
    • 画填充cv::fillPoly
  • 随机生成与绘制文本
    • RNG类
    • 生成高斯随机数RNG.gaussian (double sigma)
    • 生成正态分布随机数RNG.uniform (int a, int b)

案例代码
大概内容: 绘制线、矩形、园、椭圆、文字、随机线 。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;
Mat bgImage;
const char* drawdemo_win = "draw shapes and text demo";
void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
void MyPolygon();
void RandomLineDemo();
int main(int argc, char** argv) {
	bgImage = imread("D:/vcprojects/images/test1.png");
	if (!bgImage.data) {
		printf("could not load image...\n");
		return -1;
	}
	MyLines();
	MyRectangle();
	MyEllipse();
	MyCircle();
	MyPolygon();

	putText(bgImage, "Hello OpenCV", Point(300, 300), FONT_HERSHEY_COMPLEX, 1.0, Scalar(12, 23, 200), 3, 8);
	//opencv4中一般取消了cv前缀;应该用FONT_HERSHEY_COMPLEX_SMALL和下面的用WINDOW_AUTOSIZE
	namedWindow(drawdemo_win, WINDOW_AUTOSIZE);
	imshow(drawdemo_win, bgImage);

	RandomLineDemo();
	waitKey(0);
	return 0;
}

void MyLines() {
	Point p1 = Point(20, 30);
	Point p2;
	p2.x = 400;
	p2.y = 400;
	Scalar color = Scalar(0, 0, 255);
	line(bgImage, p1, p2, color, 1, LINE_AA);
}

void MyRectangle() {
	Rect rect = Rect(200, 100, 300, 300);
	Scalar color = Scalar(255, 0, 0);
	rectangle(bgImage, rect, color, 2, LINE_8);
}

void MyEllipse() {
	Scalar color = Scalar(0, 255, 0);
	ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 90, 0, 360, color, 2, LINE_8);
}

void MyCircle() {
	Scalar color = Scalar(0, 255, 255);
	Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
	circle(bgImage, center, 150, color, 2, 8);
}

void MyPolygon() {
	Point pts[1][5];
	pts[0][0] = Point(100, 100);
	pts[0][1] = Point(100, 200);
	pts[0][2] = Point(200, 200);
	pts[0][3] = Point(200, 100);
	pts[0][4] = Point(100, 100);

	const Point* ppts[] = { pts[0] };
	int npt[] = { 5 };
	Scalar color = Scalar(255, 12, 255);

	fillPoly(bgImage, ppts, npt, 1, color, 8);
}

void RandomLineDemo() {
	RNG rng(12345);
	Point pt1;
	Point pt2;
	Mat bg = Mat::zeros(bgImage.size(), bgImage.type());
	namedWindow("random line demo");
	for (int i = 0; i < 100000; i++) {
		pt1.x = rng.uniform(0, bgImage.cols);
		pt2.x = rng.uniform(0, bgImage.cols);
		pt1.y = rng.uniform(0, bgImage.rows);
		pt2.y = rng.uniform(0, bgImage.rows);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		if (waitKey(50) > 0) {
			break;
		}
		line(bg, pt1, pt2, color, 1, 8);
		imshow("random line demo", bg);
	}
}



运行效果:
在这里插入图片描述在这里插入图片描述

解析及注意事项

  • 之前第三篇里面提到了scalar、point、size是三个很常见的图像处理数据结构。
  • 之前在图像操作那一篇提到改变像素值的操作函数的参数都差多,都有那几个固定的项,而绘制图像类也是这样的。第一个参数一般是背景图像InputOutputArray img 后面四个const Scalar & color,int thickness = 1,int lineType = LINE_8,int shift = 0 分别是颜色、线的粗细、线的类型(锯齿)、点坐标的小数位数。
  • 几个图形之中椭圆和矩形的一个重载有点难理解,矩形传的也是两个点,分别是左上角和右下角,所以画出来的矩形永远都是正的
  • 椭圆外接矩形的重载不难理解,难理解的是三个角度的重载。angle是整个椭圆的旋转角度,如果旋转角度为0的话,椭圆永远都是正的,而endAngle-startAngle就是这个椭圆要从哪里画到哪里(不一定画一整个,可以之画一部分线段)axes要包括宽和高,宽和高决定椭圆的形状,如果一样就是圆。
  • 参照下面官方给的这个图。红色为椭圆,蓝色为实际画出来的曲线段,其中左右的椭圆形态不同是因为AXES.WIDTH和AXES.HEIGHT的大小关系不同。看左边的图不要把它看成三维的图,他就是一个实实在在的二维图,注意黑色的坐标轴。这下配合图片就应该能很清晰的理解参数了。
    在这里插入图片描述
  • C和C++中产生随机数的方法如rand()、srand()等在OpenCV中仍可以用。也可以使用opencv里的RNG类,可以得到高斯分布(正态)的、和均匀分布的随机数。
  • 之前使用一些宏的时候经常会报错“未定义”,看了别的博客才知道是版本不一样引起的,我们平时看的教程大多是opencv2,或者早起的opencv3,所以一些宏不一样很正常。他们的区别大概是,前带cv的都是C里的写法,不带cv的是C++里的写法,比如FONT_HERSHEY_COMPLEX和CV_FONT_HERSHEY_COMPLEX,其本质都是一样的,只不过后者要加一个c的头文件才能识别出来,也就不难解释我们加的头文件都是****c.h 。总言而之,如果使用宏的时候飘红表示未定义可以试一下把CV或者CV(以此类推)删掉试试,屡试不爽。

全注释代码

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;
Mat bgImage;//全局变量
const char* drawdemo_win = "draw shapes and text demo";

void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
void MyPolygon();
void RandomLineDemo();

int main(int argc, char** argv) {
	bgImage = imread("D:\\86186\\Documents\\opencv\\white.png");
	if (!bgImage.data) {
		printf("could not load image...\n");
		return -1;
	}
	MyLines();
	MyRectangle();
	MyEllipse();
	MyCircle();
	MyPolygon();

	putText(bgImage, "Hello OpenCV", Point(300, 300), FONT_HERSHEY_COMPLEX, 1.0, Scalar(12, 23, 200), 3, 8);
	/*
	InputOutputArray 	img,
	const String & 	text,//	Text string to be drawn.
	Point 	org,//Bottom-left corner of the text string in the image.
	int 	fontFace,//Font type, see HersheyFonts.
	double 	fontScale,
	Scalar 	color,
	int 	thickness = 1,
	int 	lineType = LINE_8,
	bool 	bottomLeftOrigin = false

	HersheyFonts:
	FONT_HERSHEY_SIMPLEX		normal size sans-serif font
	FONT_HERSHEY_PLAIN			small size sans-serif font
	FONT_HERSHEY_DUPLEX			normal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX)
	FONT_HERSHEY_COMPLEX		normal size serif font
	FONT_HERSHEY_TRIPLEX		normal size serif font (more complex than FONT_HERSHEY_COMPLEX)
	FONT_HERSHEY_COMPLEX_SMALL	smaller version of FONT_HERSHEY_COMPLEX
	FONT_HERSHEY_SCRIPT_SIMPLEX hand-writing style font
	FONT_HERSHEY_SCRIPT_COMPLEX more complex variant of FONT_HERSHEY_SCRIPT_SIMPLEX
	FONT_ITALIC					flag for italic font
	*/
	//opencv4中一般取消了cv前缀;应该用FONT_HERSHEY_COMPLEX_SMALL和下面的用WINDOW_AUTOSIZE
	namedWindow(drawdemo_win, WINDOW_AUTOSIZE);
	imshow(drawdemo_win, bgImage);
	RandomLineDemo();
	waitKey(0);
	return 0;
}

void MyLines() {
	//两种创建point的方法
	Point p1 = Point(20, 30);
	Point p2;
	p2.x = 400;
	p2.y = 400;

	//创建一个色彩标量
	Scalar color = Scalar(0, 0, 255);
	//画一条连接两点的线段。
	line(bgImage, p1, p2, color, 1, LINE_AA);//Draws a line segment connecting two points.
	/*
	For non-antialiased lines with integer coordinates, the 8-connected or 4-connected Bresenham algorithm is used.
	对于具有整数坐标的非抗锯齿线,采用8连通或4连通Bresenham算法。
	Thick lines are drawn with rounding endings. Antialiased lines are drawn using Gaussian filtering.
	绘制粗线以四舍五入结尾。使用高斯滤波绘制抗锯齿线。
	参数:
		InputOutputArray 	img,
		Point pt1,
		Point pt2,
		const Scalar & color,
		int thickness = 1,
		int lineType = LINE_8,
		int shift = 0 ,//Number of fractional bits in the point coordinates.点坐标中的小数位数。
	lineType有下列四种:
		FILLED
		LINE_4  4-connected line
		LINE_8  8-connected line
		LINE_AA  antialiased line
	*/
}

void MyRectangle() {
	Rect rect = Rect(200, 100, 300, 300);
	Scalar color = Scalar(255, 0, 0);
	rectangle(bgImage, rect, color, 2, LINE_8);//Draws a simple, thick, or filled up-right rectangle.
	/*
	参数
		InputOutputArray 	img,
		Rect rec{//use rec parameter as alternative specification of the drawn rectangle: r.tl() and r.br()-Point(1,1) are opposite corners
			Point 	pt1,//Vertex of the rectangle.//根据rec的出此为矩形左上角
			Point 	pt2, //Vertex of the rectangle opposite to pt1 .//右下角
		}//意思是rect和两个point是等价的,要么填前者,要么填后者
		const Scalar & 	color,
		int 	thickness = 1,
		int 	lineType = LINE_8,
		int 	shift = 0 
	*/
}

void MyEllipse() {
	Scalar color = Scalar(0, 255, 0);
	//不建议下面这么写参数,可读性太差了。
	ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 90, 0, 360, color, 2, LINE_8);
	/*
	参数:
		InputOutputArray 	img,
		Point 	center,
		Size 	axes, //Half of the size of the ellipse main axes.
		double 	angle, //Ellipse rotation angle in degrees.
		double 	startAngle, //Starting angle of the elliptic arc in degrees.
		double 	endAngle, //Ending angle of the elliptic arc in degrees.
		const Scalar & 	color,
		int		thickness = 1,//Thickness of the ellipse arc outline, if positive. Otherwise, this indicates that a filled ellipse sector is to be drawn.
		int 	lineType = LINE_8,
		int 	shift = 0 
	参数和正方形差不多主要是那三个角度
	angle是整个椭圆的旋转角度,如果旋转角度为0的话,椭圆永远都是正的
	而endAngle-startAngle就是这个椭圆要从哪里画到哪里(不一定画一整个,可以之画一部分线段)
	axes要包括宽和高,宽和高决定椭圆的形状,如果一样就是圆
	重载参数
		const RotatedRect & box,
		这个参数可以代替center+axes+angle,starAngle和endAngle也不用填了,外切矩形确定唯一一个椭圆(只能画一整个)
	*/
}

void MyCircle() {
	Scalar color = Scalar(0, 255, 255);
	Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
	circle(bgImage, center, 150, color, 2, 8);
	/*
	InputOutputArray 	img,
	Point 	center,
	int 	radius,//半径
	const Scalar & 	color,
	int 	thickness = 1,
	int 	lineType = LINE_8,
	int 	shift = 0 
	参数和椭圆差不多
	*/
}

void MyPolygon() {//多边形
	Point pts[1][5];
	pts[0][0] = Point(100, 100);
	pts[0][1] = Point(100, 200);
	pts[0][2] = Point(200, 200);
	pts[0][3] = Point(200, 100);
	pts[0][4] = Point(100, 100);

	const Point* ppts[] = { pts[0] };
	int npt[] = { 5 };
	Scalar color = Scalar(255, 12, 255);

	fillPoly(bgImage, ppts, npt, 1, color, 8);
	/*
	InputOutputArray img,
	InputArrayOfArrays 	pts{//	Array of polygons where each polygon is represented as an array of points.
		const Point ** 	pts,//点s
		const int * npts,//点的数量
		int ncontours,//轮廓数量
	}
	const Scalar & 	color,
	int ineType = LINE_8,
	int shift = 0,
	Point offset = Point(),//Optional offset of all points of the contours.可选的轮廓的所有点的偏移。
	*/
}

void RandomLineDemo() {
	RNG rng((int)getTickCount());//里面的数值一样的话产生的随机数也是一样的,可以用getTickCount()来做到真正的随机
	Point pt1;
	Point pt2;
	Mat bg = Mat::zeros(bgImage.size(), bgImage.type());
	namedWindow("random line demo");
	for (int i = 0; i < 100000; i++) {
		pt1.x = rng.uniform(0, bgImage.cols);//uniformly-distributed 均匀分布
		pt2.x = rng.uniform(0, bgImage.cols);//eturns uniformly distributed integer random number from [a,b) range
		pt1.y = rng.uniform(0, bgImage.rows);
		pt2.y = rng.uniform(0, bgImage.rows);
		//double cv::RNG::gaussian(double sigma)//参数:分布的标准差。
		//Returns the next random number sampled from the Gaussian distribution.
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		line(bg, pt1, pt2, color, 1, 8);
		putText(bg, "Open CV", Point(bg.cols / 2 - 200, bg.rows / 2),
			FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 255, 0), 3, LINE_8);
		if (waitKey(50) > 0) {
			break;
		}
		imshow("random line demo", bg);
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值