实战OpenCV之绘制图形
基础入门
OpenCV除了用于图像显示之外,还提供了一系列接口和工具,以帮助开发者在图像上绘制各种图形。这里的图形包括:直线、矩形、圆形、椭圆、多边形等。另外,OpenCV还支持在图像上添加文字,对多张图像进行叠加操作。
下面,我们将逐一介绍OpenCV中与绘制图形相关的API接口。
1、绘制直线。使用cv::line()函数,其声明如下。
void line(InputOutputArray img, Point pt1, Point pt2,
const Scalar& color, int thickness=1, int lineType=8, int shift=0);
各个参数的含义如下。
img:输入输出图像的数组。
pt1:直线的起点坐标。
pt2:直线的终点坐标。
color:直线颜色。
thickness:线宽。
lineType:线条类型,如8连接线、抗锯齿线等。
shift:坐标点分量的位移量。
2、绘制矩形。使用cv::rectangle()函数,其声明如下。
void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
int thickness=1, int lineType=8, int shift=0);
各个参数的含义如下。
img:输入输出图像的数组。
pt1:矩形的左上角坐标。
pt2:矩形的右下角坐标。
color: 边框颜色。
thickness:边框厚度,若为负值则填充矩形内部。
lineType:同上。
shift:同上。
3、绘制圆形。使用cv::circle()函数,其声明如下。
void circle(InputOutputArray img, Point center, int radius, const Scalar& color,
int thickness=1, int lineType=8, int shift=0);
各个参数的含义如下。
img:输入输出图像的数组。
center:圆心坐标。
radius:圆半径。
color: 圆边框颜色。
thickness:边框厚度,若为负值则填充圆内部。
lineType:同上。
shift:同上。
4、绘制椭圆。使用cv::ellipse()函数,其声明如下。
void ellipse(InputOutputArray img, Point center, Size axes, double angle,
double startAngle, double endAngle, const Scalar& color, int thickness=1,
int lineType=8, int shift=0);
各个参数的含义如下。
img:输入输出图像数组。
center:椭圆中心坐标。
axes:半轴长度,长轴和短轴。
angle:长轴与水平方向的夹角(以度为单位)。
startAngle:开始角度。
endAngle:结束角度。
color:椭圆颜色。
thickness:边框厚度,若为负值则填充椭圆内部。
lineType:同上。
shift:同上。
5、绘制多边形。使用cv::polylines()函数,其声明如下。
void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed,
const Scalar& color, int thickness=1, int lineType=8, int shift=0);
各个参数的含义如下。
img:输入输出图像数组。
pts:多边形顶点的坐标集。
isClosed:是否闭合多边形。
color:边框颜色。
thickness:边框厚度,若为负值则填充多边形内部。
lineType:同上。
shift:同上。
6、填充多边形。使用cv::fillPoly()函数,其声明如下。
void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color,
int lineType=8, int shift=0, int offset=Point());
各个参数的含义如下。
img:输入输出图像数组。
pts:多边形顶点的坐标集。
color:填充颜色。
lineType:同上。
shift:同上。
offset:坐标的偏移量。
实战解析
下面的实战代码使用上述基本绘图函数创建了一个包含多种图形的图像,我们可以通过调整参数来改变这些图形的颜色、位置、大小和其他属性。
#include <opencv2/opencv.hpp>
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
// 创建一个512 x 512的白色背景图像
Mat image(512, 512, CV_8UC3, Scalar(255, 255, 255));
// 绘制绿色的直线
line(image, Point(0, 0), Point(511, 511), Scalar(0, 255, 0), 5);
// 绘制红色的矩形
rectangle(image, Point(384, 0), Point(510, 128), Scalar(0, 0, 255), 3);
// 绘制红色的实心圆
circle(image, Point(447, 63), 63, Scalar(0, 0, 255), -1);
// 绘制蓝色的椭圆
ellipse(image, Point(226, 226), Size(100, 50), 0, 0, 180, Scalar(255, 0, 0), 2);
// 绘制多边形
vector<Point> polygon;
polygon.push_back(Point(200, 100));
polygon.push_back(Point(250, 100));
polygon.push_back(Point(225, 200));
polylines(image, polygon, true, Scalar(255, 255, 0));
// 显示图像
imshow("Draw Shapes Mode 0", image);
cv::waitKey(0);
destroyAllWindows();
return 0;
}
执行上面的示例代码,运行效果可参考下图。
添加文字
有时候,我们希望在图像上添加文字或标注,以增强图像的可读性和信息量。此时,可以使用putText函数。
putText函数的原型如下。
void putText(
InputOutputArray img, // 输入输出图像
const String& text, // 要显示的文本字符串
Point org, // 文本起始位置(左下角或左上角)
int fontFace, // 字体样式
double fontScale, // 字体缩放因子
const Scalar& color, // 文本颜色
int thickness = 1, // 文本线条厚度
int lineType = LINE_8, // 线条类型
bool bottomLeftOrigin = true // 是否以左下角为原点
)
在下面的实战代码中,我们使用putText()函数在图像上添加了蓝色文本"Hello, Hope_Wisdom"。文本的起始位置为(50, 50),字体为cv::FONT_HERSHEY_SIMPLEX,字体大小为1,颜色为蓝色,线条厚度为2。
#include <opencv2/opencv.hpp>
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
// 读取图像,请替换为你自己的图片路径
Mat image = imread("OpenCV.png");
// 检查图像是否被正确读取
if(image.empty())
{
cout << "Can not open or find the image" << endl;
return -1;
}
// 创建一个名为"Draw Shapes Mode 1"的窗口,WINDOW_NORMAL允许调整窗口大小
namedWindow("Draw Shapes Mode 1", WINDOW_NORMAL);
// image.cols代表图像的宽度, image.rows代表图像的高度
resizeWindow("Draw Shapes Mode 1", image.cols, image.rows);
// 添加蓝色的文本
putText(image, "Hello, Hope_Wisdom", Point(50, 50),
FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2);
// 在窗口中显示图像
imshow("Draw Shapes Mode 1", image);
waitKey(0);
destroyAllWindows();
return 0;
}
执行上面的示例代码,运行效果可参考下图。
图像叠加
在处理多图像时,我们有时候需要在同一窗口中叠加显示多张图像,这可以通过图像融合来实现。addWeighted函数能够根据给定的权重将两个图像的像素值线性组合,同时还可以添加一个亮度补偿项,以控制最终图像的亮度。注意,使用此函数前,需要确保两个输入图像具有相同的尺寸和通道数,否则需要先进行调整。
addWeighted函数的原型如下。
Mat addWeighted(
const cv::Mat& src1, // 第一个输入数组
double alpha, // 第一个输入数组的权重
const cv::Mat& src2, // 第二个输入数组
double beta, // 第二个输入数组的权重
double gamma, // 加到和上的标量
cv::Mat& dst, // 输出数组
int ddepth = -1 // 可选,输出图像深度;如果设置为负数,则与输入图像深度相同
)
在下面的实战代码中,我们首先读取了两张图像。如果两张图像的尺寸不一致,我们会使用resize函数来进行调整,以满足addWeighted函数的要求。最后,我们将两张图像以50%的透明度进行了叠加,并将融合后的图像显示出来。
#include <opencv2/opencv.hpp>
using namespace cv;
#include <iostream>
using namespace std;
int main()
{
// 读取图像,请替换为你自己的图片路径
Mat image1 = imread("OpenCV.png");
Mat image2 = imread("C++.png");
// 检查图像是否被正确读取
if(image1.empty() || image2.empty())
{
cout << "Can not open or find the image" << endl;
return -1;
}
// 获取两张图片的尺寸
Size size1 = image1.size();
Size size2 = image2.size();
// 确定目标尺寸,这里以较大尺寸为准
Size targetSize = size1.area() > size2.area() ? size1 : size2;
// 如果尺寸不一致,调整图片大小
if (size1 != targetSize)
{
resize(image1, image1, targetSize);
}
else if (size2 != targetSize)
{
resize(image2, image2, targetSize);
}
else
{
NULL;
}
// 创建一个空的Mat对象来存放结果
Mat result;
double alpha = 0.5; // 图像1的透明度
double beta = 0.5; // 图像2的透明度
double gamma = 0; // 亮度补偿,默认为0
// 使用addWeighted函数叠加图像,两张图以50%透明度叠加
addWeighted(image1, alpha, image2, beta, gamma, result);
// 创建一个名为Draw Shapes Mode 2"的窗口,WINDOW_NORMAL允许调整窗口大小
namedWindow("Draw Shapes Mode 2", WINDOW_NORMAL);
// 在窗口中显示图像
imshow("Draw Shapes Mode 2", result);
waitKey(0);
destroyAllWindows();
return 0;
}
执行上面的示例代码,运行效果可参考下图。