第六部分、图像操作-2
- 第一节、图像几何形状绘制
- 1.几何形状
- 2.填充、绘制与着色
- 3.代码练习与测试
- 第二节、多边形填充与绘制
- 1.多边形绘制函数
- 2.绘制与填充
- 3.代码练习与测试
- 第三节、图像像素类型转换与归一化
- 1.归一化方法与支持
- 2.归一化函数
- 3.代码练习与测试
- 第四节、图像几何变换
- 1.图像几何变换矩阵
- 2.函数支持
- 3.代码练习与测试
- 学习参考
第一节、图像几何形状绘制
1.几何形状
- 支持绘制线、矩形、圆形
- 支持填充矩形、圆形、椭圆
- 支持绘制文本
注意:绘制只能用英文
几何形状的函数:
相关函数
1.cv.line() # 线
2.cv.circle() # 圆形
3.cv.rectangle() # 矩形
4.cv.ellipse() # 椭圆
5.cv.putText() # 文本
# 相关参数解释:
# img表示输入图像
# color表示颜色,如(255, 0,0)表示蓝色,注意颜色维度要和通道数匹配
# thickness表示线宽, 大于0表示绘制,小于0表示填充
# lineType表示渲染模式, 默认LINE_8, LINE_AA表示反锯齿
# 渲染指的是,绘制一个图的时候会对每个像素点周围4个或8个点进行渲染,常用的是LINE_8
# 反锯齿是另一种渲染方式,使用反锯齿渲染的图片效果更好,但是会比较耗时
# 如果追求用户体验并且计算机带的动就用LINE_AA,如果追求性能就用LINE_8
文本绘制:
- putText 默认只支持英文
- org表示文字起始坐标点
- fontFace表示字体类型
- fontScale表示字体大小
计算文本区域大小:
# 计算文本区域大小的函数
getTextSize (
text, # 表示文本信息
fontFace, # 表示字体类型
fontScale, # 表示字体大小
thickness # 表示线宽
)
# 返回文本信息区域大小,与字体的基线baseline位置
如下图包裹OpenCV-Python的白色框就是文本区域大小
2.填充、绘制与着色
def draw_demo_1():
# 创建一个512*512*3大小的图像作为画布
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
# (100, 100)是起点坐标,(300, 300)是终点坐标
# 绘制一个红色矩形
cv.rectangle(canvas, (100, 100), (300, 300), (0, 0, 255), 2, 8)
# 填充一个紫色矩形
cv.rectangle(canvas, (400, 100), (450, 150), (255, 0, 255), -1, 8)
# 绘制一个蓝色圆形
cv.circle(canvas, (250, 250), 50, (255, 0, 0), 2, cv.LINE_8)
# 填充一个蓝色圆形
cv.circle(canvas, (425, 200), 20, (255, 0, 0), -1, cv.LINE_8)
# 绘制一个绿色线段,lineType=8指的是8联通线型,涉及到线的产生算法,另一种是lineType=4指的是4联通线型
cv.line(canvas, (100, 100), (300, 300), (0, 255, 0), 2, 8)
# 添加一个文本
cv.putText(canvas, "OpenCV-Python", (100, 100), cv.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 255), 2)
cv.imshow("canvas", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:右图是矩形的参数列表
3.代码练习与测试
# 动态显示文本区域
def draw_demo_2():
# 创建一个512*512*3大小的图像作为画布
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
# 深度学习对象检测经典颜色:土耳其蓝(140, 199, 0)
font_color = (140, 199, 0)
cv.rectangle(canvas, (100, 100), (300, 300), font_color, 2, 8)
label_txt = "OpenCV-Python"
label_txt2 = "Hello world is a nice sentence."
font = cv.FONT_HERSHEY_SIMPLEX # 字体选择建议就是cv.FONT_HERSHEY_SIMPLEX 或者 cv.FONT_HERSHEY_PLAIN
font_scale = 0.5 # 字体大小0.5
thickness = 1 # 线宽1
# cv.getTextSize动态获取文本,(fw, uph)是宽、高,dh是基线
(fw, uph), dh = cv.getTextSize(label_txt, font, font_scale, thickness)
(fw2, uph2), dh2 = cv.getTextSize(label_txt2, font, font_scale, thickness)
cv.rectangle(canvas, (100, 80-uph-dh), (100+fw, 80), (255, 255, 255), -1, 8)
cv.rectangle(canvas, (100, 100-uph2-dh2), (100+fw2, 100), (255, 255, 255), -1, 8)
cv.putText(canvas, label_txt, (100, 80-dh), font, font_scale, (255, 0, 255), thickness)
cv.putText(canvas, label_txt2, (100, 100-dh), font, font_scale, (255, 0, 255), thickness)
cv.imshow("canvas", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
动态显示文本示例:
第二节、多边形填充与绘制
1.多边形绘制函数
# 填充多边形
1.cv.fillPoly(img, pts, color[, lineType[, shift[, offset]]]) ->img
# 绘制多边形
2.cv.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]] ) ->img
# pts表示一个或者多个点集
# color表示颜色
# thickness表示线宽,注意:必须大于0
# lineType 表示渲染方式
pts表示一个或多个点集
pts = []
pts.append((100, 100))
pts.append((200, 50))
pts.append((280, 100))
pts.append((290, 300))
pts.append((50, 300))
pts = np.asarray(pts, dtype=np.int32)
print(pts.shape)
# 要求:必须是CV_32S, 对应np.int32
2.绘制与填充
支持一次绘制多个图形
例如:红色边框是绘制、蓝色区域是填充
3.代码练习与测试
# 多边形绘制
def poly_demo():
# 设置画布
canvas = np.zeros((512, 512, 3), dtype=np.uint8)
# pts = [(100, 100), (200, 50), (280, 100), (290, 300), (50, 300)]
pts = []
pts.append((100, 100))
pts.append((200, 50))
pts.append((280, 100))
pts.append((290, 300))
pts.append((50, 300))
pts = np.array(pts, dtype=np.int32)
print(pts.shape)
pts2 = []
pts2.append((300, 300))
pts2.append((400, 250))
pts2.append((500, 300))
pts2.append((500, 500))
pts2.append((250, 500))
pts2 = np.array(pts2, dtype=np.int32)
print(pts2.shape)
# 同时绘制两个点集
cv.polylines(canvas, [pts, pts2], True, (0, 0, 255), 2, 8)
# 填充
cv.fillPoly(canvas, [pts, pts2], (255, 0, 0), 8, 0)
cv.imshow("poly-demo", canvas)
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
第三节、图像像素类型转换与归一化
1.归一化方法与支持
图像归一化就是让图像在不同情况下来回转换。
OpenCV中常用的归一化方法:
- NORM_MINMAX
- NORM_INF
- NORM_L1
- NORM_L2
- 最常用 NORM_MINMAX
- NORM_L1与NORM_L2范数
- 下图中L1范数 = x / (∑ xi),例如0.1 = 2.0 / (2.0 + 8.0 + 10.0)
- 下图中L2范数 = x / (∑ xi ^ 2) ^ 1/2 ,例如0.15 = 2.0 / (4.0 + 64.0 +100.0) ^ 1/2
2.归一化函数
1.cv.normalize( src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]] ) -> dst
# src表示输入图像, dst表示输出图像
# alpha, beta 默认是1, 0,是归一化的区间值
# norm_type默认是NORM_L2,
# norm_type常用是NORM_MINMAX
2.数据转换
# Imread读入默认是uint8, 转换为float32
# 通过imshow显示之前,必须归一化到[0~1]之间。
3.代码练习与测试
图像像素NORM_MINMAX归一化:
# 图像像素类型转换与归一化
def norm_demo():
image_uint8 = cv.imread(r"F:\python\opencv-4.x\samples\data\ml.png")
cv.imshow("image_uint8", image_uint8)
img_f32 = np.float32(image_uint8)
cv.imshow("image_f32", img_f32)
cv.normalize(img_f32, img_f32, 1, 0, cv2.NORM_MINMAX)
cv.imshow("norm-img_f32", img_f32)
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:当图片类型从uint8转换到f32之后,如果不适用归一化结果如中间所示只有一堆点,使用归一化之后结果如右图所示。
因为imshow只支持两种类型显示,一种是uint8(0, 255),另一种是f32(0, 1)。
滚动条显示四种归一化方法:
# 定义滚动条的注册响应
def trackbar_norm_callback(pos):
print(pos)
# 用滚动条实现四种归一化方式
def norm_trackbar_demo():
image_uint8 = cv.imread(r"F:\python\opencv-4.x\samples\data\ml.png")
cv.namedWindow("norm-demo", cv.WINDOW_AUTOSIZE)
# 注意使用cv.createTrackbar滚动条之前线要定义注册响应trackbar_norm_callback
cv.createTrackbar("normtype", "norm-demo", 0, 3, trackbar_norm_callback)
while True:
dst = np.float32(image_uint8)
pos = cv.getTrackbarPos("normtype", "norm-demo")
if pos == 0:
cv.normalize(dst, dst, 1, 0, cv.NORM_MINMAX)
if pos == 1:
cv.normalize(dst, dst, 1, 0, cv.NORM_L1)
if pos == 2:
cv.normalize(dst, dst, 1, 0, cv.NORM_L2)
if pos == 3:
cv.normalize(dst, dst, 1, 0, cv.NORM_INF)
cv.imshow("norm-demo", dst)
# 每过50ms就获取一个键值,默认键值为-1,ESC键值为27
c = cv.waitKey(50)
if c == 27:
break
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
第四节、图像几何变换
1.图像几何变换矩阵
图像的变化使用几何变换矩阵实现的
所以图像几何变换最重要的就是几何变换矩阵M(2x3),前面四个参数是控制放缩,最后一列是平移。
例如:矩形变圆形
-
平移变换
-
放缩变换
-
旋转变换
2.函数支持
# 仿射变换
1. cv.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]] ) --> dst
# src表示输入图像
# M 表示2x3变换矩阵
# dsize表示目标图像输出dst的大小
# 支持平移变换、放缩变换、旋转变换
输出dst形式如下所示:实现原坐标(x,y)到目标位置的变换
# 旋转矩阵获取
2. cv.getRotationMatrix2D
# Center表示旋转中心
# angle表示度数,>0表示逆时针旋转
# scale表示放缩尺度大小
# 翻转
3. cv.flip(src, flipCode[, dst] ) ->dst
# 特殊角度旋转
4. cv.rotate(src, rotateCode[, dst] ) -> dst
# src表示输入图像
# flipCode支持0水平、1垂直,-1对角线翻转,只表示翻转
# rotateCode只支持旋转90°,180°,270°,不支持任意角度旋转
3.代码练习与测试
# 图像几何旋转
def affine_demo():
image = cv.imread(r"F:\python\opencv-4.x\samples\data\ml.png")
h, w, c = image.shape
# 获取中心位置
cx = int(w/2)
cy = int(h/2)
cv.imshow("image", image)
# 定义原图放缩0.7倍,上下均平移50的矩阵M
M = np.zeros((2, 3), dtype=np.float32)
M[0, 0] = .7
M[1, 1] = .7
M[0, 2] = 50
M[1, 2] = 50
print("M(2x3) = \n", M)
dst = cv.warpAffine(image, M, (int(w*.7), int(h*.7)))
cv.imshow("rescale-demo", dst)
# 在指定路径写一个图片
cv.imwrite(r"F:\python\opencv-4.x\result.png", dst)
# 定义旋转,获取旋转矩阵degree>0,表示逆时针旋转,原点在左上角
# (w/2, h/2)表示旋转中心,逆时针旋转45°,放缩1.0即不做放缩操作。
M = cv.getRotationMatrix2D((w/2, h/2), 45.0, 1.0)
dst = cv.warpAffine(image, M, (w, h))
cv.imshow("rotate-demo", dst)
# 图像翻转,0表示水平翻转
dst = cv.flip(image, 0)
cv.imshow("flip-demo", dst)
# 图像特殊角度旋转,顺时针旋转90°
dst = cv.rotate(image, cv.ROTATE_90_CLOCKWISE)
cv.imshow("rotate-90-demo", dst)
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
学习参考
本系列所有OpenCv相关的代码示例和内容均来自博主学习的网站:opencv_course