注释图像和视频有多种用途,OpenCV使这个过程简单明了。看看如何使用它:
- 向演示添加信息
- 在物体周围绘制边框,以便检测物体
- 用不同颜色高亮像素进行图像分割
一旦你学会了注释图像,注释视频帧看起来也很简单。这是因为视频中的每一帧都表示为一幅图像。我们将在这里演示如何用几何形状和文本注释图像。
这是我们将在所有例子中用到的图像。
1.简单实现画线
首先,快速查看一下注释图像的代码。我们将详细讨论代码中的每一行,以便您能够完全理解它。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 在图像上画线
imageLine = img.copy()
# 在图像上绘制从A点到B点
pointA = (200,80)
pointB = (450,80)
cv2.line(imageLine, pointA, pointB, (255, 255, 0), thickness=3, lineType=cv2.LINE_AA)
cv2.imshow('Image Line', imageLine)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 在图像上画线
Mat imageLine = img.clone();
Point pointA(200,80);
Point pointB(450,80);
line(imageLine, pointA, pointB, Scalar(255, 255, 0), 3, 8, 0);
imshow("Lined Image", imageLine);
waitKey();
}
2.代码解析
在第一个例子中,让我们使用OpenCV中的line()
函数为图像添加一条彩色线。在调用line()
函数之前,通过以下方法创建原始图像的副本:
- 在
Python中copy()函数
- 在
C++中clone()函数
副本将确保您对图像所做的任何更改不会影响原始图像。在c++中,首先为原始图像的副本创建一个矩阵。
下面是line()
函数的语法:line(image, start_point, end_point, color, thickness)
- 第一个参数是图像
- 接下来的两个参数是线段的起点和终点。
从点A (x1, y1)
到点B(x2, y2)
画一条直线,其中A
和B
代表图像中的任意两点。看图像的左上角,你会发现这里是xy坐标系的原点。
- x轴表示图像的水平方向或列。
- y轴表示图像的垂直方向或行。
如代码所示:
- 指定起始点和结束点,以便在图像上水平绘制一条250像素长的直线。
- 指定它的颜色为蓝色和绿色的混合物,线宽指定为3。
3.画圆
接下来,让我们使用OpenCV中的circle()
函数为图像添加一个圆圈注释。看看它的语法:circle(image, center_coordinates, radius, color, thickness)
- 与OpenCV中的所有绘图函数一样,第一个参数是图像。
- 接下来的两个参数定义圆心的坐标及其半径。
- 最后两个参数指定线条的颜色和粗细。
在这个例子中,您用一个红色的圆圈围绕着狗的脸来注释图像。然后使用imshow()
函数显示带注释的图像。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
imageCircle = img.copy()
# 定义圆心
circle_center = (415,190)
# 定义圆的半径
radius =100
# 使用circle()函数绘制一个圆
cv2.circle(imageCircle, circle_center, radius, (0, 0, 255), thickness=3, lineType=cv2.LINE_AA)
# 显示结果
cv2.imshow("Image Circle",imageCircle)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
imageCircle = img.copy()
// 定义圆的中心
circle_center = (415,190)
// 定义圆的半径
radius =100
// 使用circle()函数绘制一个圆
cv2.circle(imageCircle, circle_center, radius, (0, 0, 255), thickness=3, lineType=cv2.LINE_AA)
// 显示结果
cv2.imshow("Image Circle",imageCircle)
cv2.waitKey(0)
}
4.画填充的圆
您刚刚完成了用红色圆圈对图像的注释。如果你想用纯色填充这个圆呢?这很简单。只需将线宽参数更改为-1,如下面的代码所示。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
imageCircle = img.copy()
# 定义圆心
circle_center = (415,190)
# 定义圆的半径
radius =100
# 使用circle()函数绘制一个圆
cv2.circle(imageCircle, circle_center, radius, (0, 0, 255), thickness=-1, lineType=cv2.LINE_AA)
# 显示结果
cv2.imshow("Image Circle",imageCircle)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
imageCircle = img.copy()
// 定义圆的中心
circle_center = (415,190)
// 定义圆的半径
radius =100
// 使用circle()函数绘制一个圆
cv2.circle(imageCircle, circle_center, radius, (0, 0, 255), thickness=-1, lineType=cv2.LINE_AA)
// 显示结果
cv2.imshow("Image Circle",imageCircle)
cv2.waitKey(0)
}
5.画矩形
现在,您将使用OpenCV中的rectangle()
函数在图像上绘制一个矩形。看看它的语法:rectangle(image, start_point, end_point, color, thickness)
在rectangle()
函数中,为矩形的各个角提供起始点(左上)和结束点(右下)。
现在浏览一下这个示例代码,并在小狗的脸上用一个红色矩形注释这个图像。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
imageRectangle = img.copy()
# 定义矩形的起点和终点
start_point =(300,115)
end_point =(475,225)
# 画矩形
cv2.rectangle(imageRectangle, start_point, end_point, (0, 0, 255), thickness= 3, lineType=cv2.LINE_8)
# 输出显示
cv2.imshow('imageRectangle', imageRectangle)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
Mat rect_image = image.clone();
// 定义矩形的起始点和结束点
Point start_point(300,115);
Point end_point(475,225);
// 使用 rectangle() 函数绘制一个矩形
rectangle(rect_image, start_point, end_point, Scalar(0,0,255), 3, 8, 0);
imshow("Rectangle on Image", rect_image);
waitKey();
}
6.画椭圆
ellipse(image, centerCoordinates, axesLength, angle, startAngle, endAngle, color, thickness)
你可以使用OpenCV中的ellipse()
函数在图像上画一个椭圆。ellipse()
函数的语法与circle
非常相似。除了,你需要指定的不是半径,而是:
- 椭圆的长和短轴长度
- 旋转角度
- 椭圆的起始和结束角,这些角度让我们只绘制弧线的一部分
在下面的示例代码中,您可以使用:
- 水平蓝色椭圆
- 垂直的红色椭圆
正如您再次看到的,OpenCV中的绘图函数非常相似,因此很容易掌握。此外,它们还提供可选参数,以便您可以自由定义许多基本几何形状的位置和方向。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
imageEllipse = img.copy()
# 定义椭圆的中心点
ellipse_center = (415,190)
# 定义椭圆的长轴和短轴
axis1 = (100,50)
axis2 = (125,50)
# 绘制椭圆
#水平
cv2.ellipse(imageEllipse, ellipse_center, axis1, 0, 0, 360, (255, 0, 0), thickness=3)
#垂直
cv2.ellipse(imageEllipse, ellipse_center, axis2, 90, 0, 360, (0, 0, 255), thickness=3)
# 显示输出
cv2.imshow('ellipse Image',imageEllipse)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
Mat imageEllipse = img.clone();
// 定义椭圆的中心点
Point ellipse_center(415,190);
// 定义椭圆的长轴和短轴
Point axis1(100, 50);
Point axis2(125, 50);
// 使用ellipse()函数绘制一个椭圆
// 水平
ellipse(imageEllipse, ellipse_center, axis1, 0, 0, 360, Scalar(255, 0, 0), 3, 8, 0);
// 垂直
ellipse(imageEllipse, ellipse_center, axis2, 90, 0, 360, Scalar(0, 0, 255), 3, 8, 0);
// 显示输出
imshow("Ellipses on Image", imageEllipse);
waitKey();
}
7.绘制半椭圆
在这个例子中,我们将前面的代码修改为:
- 只画蓝色椭圆的一半
- 将垂直的红色椭圆改为半填充的水平红色椭圆
要做到这一点,请进行以下更改:
- 设置蓝色椭圆的结束角为180度
- 改变红色椭圆的方向从90到0
- 指定红色椭圆的起始角和结束角,分别为0和180
- 将红色椭圆的厚度指定为负数
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
halfEllipse = img.copy()
# 定义半椭圆的中心
ellipse_center = (415,190)
# 定义轴点
axis1 = (100,50)
# 画一个不完整/开放的椭圆,只是一个轮廓
cv2.ellipse(halfEllipse, ellipse_center, axis1, 0, 180, 360, (255, 0, 0), thickness=3)
# 如果您想绘制一个填充椭圆,请使用这行代码
# cv2.ellipse(halfEllipse, ellipse_center, axis1, 0, 0, 180, (0, 0, 255), thickness=-2)
# 输出显示
cv2.imshow('halfEllipse',halfEllipse)
cv2.waitKey(0)
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
Mat halfEllipse = image.clone();
// 定义半椭圆的中心
Point ellipse_center(415,190);
// 定义轴点
Point axis1(100, 50);
// 画半椭圆,只画轮廓
ellipse(halfEllipse, ellipse_center, axis1, 0, 180, 360, Scalar(255, 0, 0), 3, 8, 0);
// 如果您想绘制一个填充椭圆,请使用这行代码
// ellipse(halfEllipse, ellipse_center, axis1, 0, 0, 180, Scalar(0, 0, 255), -2, 8, 0);
// 输出显示
imshow("Half-Ellipses on Image", halfEllipse);
waitKey();
}
8.添加文字
最后,让我们尝试用文本注释图像。要做到这一点,请使用OpenCV中的putText()
函数。看看它的语法,后面跟着参数:putText(image, text, org, font, fontScale, color)
- 和往常一样,第一个参数是输入图像。
- 下一个参数是我们想要注释图像的实际文本字符串。
- 第三个参数指定文本字符串左上角的起始位置。
- 接下来的两个参数指定字体样式和比例。OpenCV支持来自Hershey字体集合的几种字体样式,以及斜体字体。看看这个列表:
FONT_HERSHEY_SIMPLEX = 0,
FONT_HERSHEY_PLAIN = 1,
FONT_HERSHEY_DUPLEX = 2,
FONT_HERSHEY_COMPLEX = 3,
FONT_HERSHEY_TRIPLEX = 4,
FONT_HERSHEY_COMPLEX_SMALL = 5,
FONT_HERSHEY_SCRIPT_SIMPLEX = 6,
FONT_HERSHEY_SCRIPT_COMPLEX = 7,
FONT_ITALIC = 16
- 字体比例是一个浮点值,用于向上或向下缩放字体的基本大小。根据图像的分辨率,选择合适的字体比例。
- 最后一个必需参数是颜色,它被指定为BGR三元组。
看一下这段代码,了解如何实现这些参数来在图像上显示文本字符串。
(1)Python
# 导入依赖
import cv2
# 读取图像
img = cv2.imread('sample.jpg')
# 显示图像
cv2.imshow('Original Image',img)
cv2.waitKey(0)
# 打印错误信息
if img is None:
print('Could not read image')
# 复制图像
imageText = img.copy()
#让我们写下你想要放在图像上的文本
text = 'I am a Happy dog!'
#你想放文本的地方
org = (50,350)
# 将文本写在输入图像上
cv2.putText(imageText, text, org, fontFace = cv2.FONT_HERSHEY_COMPLEX, fontScale = 1.5, color = (250,225,100))
# 显示带有文本的输出图像
cv2.imshow("Image Text",imageText)
cv2.waitKey(0)
cv2.destroyAllWindows()
(2)C++
// 导入依赖
#include <opencv2/opencv.hpp>
#include <iostream>
// 命名空间
using namespace std;
using namespace cv;
int main()
{
// 读取图像
Mat img = imread("sample.jpg");
// 显示图像
imshow("Original Image", img);
waitKey();
// 打印错误信息
if (img.empty())
{
cout << "Could not read image" << endl;
}
// 复制图像
Mat imageText = img.clone();
// 使用 putText() 函数写入文本
putText(imageText, "I am a Happy dog!", Point(50,350), FONT_HERSHEY_COMPLEX, 1.5, Scalar(250,225,100));
imshow("Text on Image", imageText);
waitKey(0);
}
总结
用几何形状和文本注释图像是一种强大的交流方式。它有助于放大图像上的信息。在图像经过各种计算机视觉算法处理后(例如,在物体检测模型检测到的物体周围绘制边界框),图像几乎总是被注释以覆盖结果。
您已经看到用几何形状和文本注释图像是多么容易。甚至绘图函数也有类似的输入参数。只是指定注释的位置和大小的方式可能略有不同。
你还学会了用想要的颜色填充形状。绘制特定方向和长度的椭圆和弧。
最后,您看到了如何用文本注释图像。