部分II:GUI 特征
4. 图片
学习目标
- 读入图像
- 显示图像
- 保存图像
函数
cv2.imread()读取图像cv2.imshow()显示图像cv2.imwrite()保存图像
扩展
cv2.waitKey()异步等待,读入一个键盘值cv2.destroyAllWindows()关闭所有窗体cv2.namedWindow()创建命名窗体- 如何使用 Matplotlib 显示图片,并解决颜色错乱的问题
4.1 读取一张图片
import numpy as np
import cv2
img = cv2.imread('messi5.jpg', 0)【警告】 即使图像的路径是错的,OpenCV 也不会提醒你的,结果是
None。
读取参数
cv2.IMREAD_COLOR = 1:读入一副彩色图像。图像的透明度会被忽略,这是默认参数cv2.IMREAD_UNCHANGED = -1:读入一幅图像,并且包括图像的alpha通道cv2.IMREAD_GRAYSCALE = 0:以灰度模式读入图像
4.2 显示图像
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()【建议】你也可以先创建一个窗口,之后再加载图像。这种情况下,你可以决定窗口是否可以调整大小。使用到的函数是
cv2.namedWindow(),此时默认值为cv2.WINDOW_AUTOSIZE = 1,可以设置为cv2.WINDOW_NORMAL = 0。
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image', img)4.3 保存图像
cv2.imwrite('messigray.png', img)4.4 综合示例
以灰度模式打开图像,按 s 保存,ESC 退出则不保存。
import cv2
img = cv2.imread('messi5.jpg', 0)
cv2.imshow('image', img)
k = cv2.waitKey(0) & 0xff
if k == 27:
cv2.destroyAllWindows()
elif k == ord('s'):
cv2.imwrite('messigray.png', img)
cv2.destroyAllWindows()4.5 使用 matplotlib
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('cv2test.png', 0)
plt.imshow(img, cmap='gray', interpolation='bicubic')
plt.xticks([])
plt.yticks([])
plt.show()【警告】 彩色图像使用 OpenCV 加载时是 BGR 模式。但是 Matplotib 是 RGB 模式。所以彩色图像如果已经被 OpenCV 读取,那它将不会被 Matplotib 正确显示。
颜色转换参考 Stack Overflow,也可以使用
img2 = img[:,:,::-1]转换图像颜色空间。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('cv2test.png')
b, g, r = cv2.split(img)
img2 = cv2.merge([r, g, b])
plt.subplot(121)
# expects distorted color(错误的颜色)
plt.imshow(img)
plt.subplot(122)
# expect true color(正确的颜色)
plt.imshow(img2)
plt.show()
# expects true color(正确的颜色)
cv2.imshow('bgr image', img)
# expects distorted color(错误的颜色)
cv2.imshow('rgb image', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()5. 视频
学习目标
- 读取视频
- 显示视频
- 保存视频
- 从摄像头读取并显示视频
函数
cv2.VideoCapture()读取摄像头cv2.VideoWrite()写入视频
扩展
cv2.cvtColor()转换颜色空间cv2.flip()翻转图像
5.1 捕获摄像头
cv2.VideoCapture(0) 捕获第一个摄像头,cap.read() 读取图像。
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cap.release()
cv2.destroyAllWindows()如果可能打开失败时,使用
cap.isOpened()判断是否打开成功。
你可以使用函数 cap.get(propId) 来获得视频的一些参数信息。这里 propId 每一个数代表视频的一个属性,见下表。
其中的一些值可以使用 cap.set(propId, value) 来修改,value 就是你想要设置成的新值。例如,可以使用 cap.get(3) 和 cap.get(4) 来查看每一帧的宽和高。
5.2 从文件中播放视频
输入文件名,然后播放视频文件的内容
import cv2
video_path = input('video path:')
cap = cv2.VideoCapture(video_path)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 可以翻转过来播放
# frame = cv2.flip(frame, 0)
cv2.imshow('frame', frame)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()预测模型示例,参考 https://blog.csdn.net/learn_learn_/article/details/112007757
import cv2
# 此处可以设定模型,然后进行预测处理
detector = ...
video_path = 'test.mp4'
cap = cv2.VideoCapture(video_path)
while True:
ret, frame = cap.read()
if not ret:
break
results = detector.predict(frame)
cap.release()
cv2.waitKey(-1)跳帧的预测模型,每秒预测一次
import cv2
# 此处可以设定模型,然后进行预测处理
detector = ...
video_path = 'test.mp4'
capture = cv2.VideoCapture(video_path)
# 视频的帧率
fps = capture.get(cv2.CAP_PROP_FPS)
# 视频的总帧数
total_frame = capture.get(cv2.CAP_PROP_FRAME_COUNT)
for i in range(int(total_frame)):
ret = capture.grab()
if not ret:
print('Error grabbing frame from movie!')
break
if i % fps == 0:
ret, frame = capture.retrieve()
if ret:
results = detector.predict(frame)
else:
print('Error retrieving frame from movie!')
break
cv2.waitKey(-1)注意:你应该确保你已经装了合适版本的
ffmpeg或者gstreamer。
5.3 保存捕获的视频
使用 cv2.cv.FOURCC(*'MJPG') 保存,cv2.VideoWriter() 用于写入视频。
import cv2
cap = cv2.VideoCapture(0)
# 定义 codec 并创建 VideoWriter 对象
fourcc = cv2.cv.FOURCC(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while cap.isOpened():
ret, frame = cap.read()
if ret == True:
frame = cv2.flip(frame, 0)
# 写入裁剪的帧
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 释放内存
cap.release()
out.release()
cv2.destroyAllWindows()编码指南:
X264适合小尺寸视频MJPG适合大尺寸视频XVID适合自适应DIVX适合 Windows 系统WMV1?WMV2?
如果想查找编码的详细信息,参考 fourcc.org 。
6. 绘图函数
学习目标
- 使用 OpenCV 绘制不同的几何图形
函数
cv2.line()画线cv2.circle()画圈cv2.rectangle()矩形cv2.ellipse()椭圆形cv2.putText()绘制文本
扩展
img:你想要绘制图形的那幅图像color:形状的颜色。以 RGB 为例,需要传入一个元组,例如:(255, 0, 0)代表蓝色。对于灰度图只需要传入灰度值thickness:线条的粗细。如果给一个闭合图形设置为-1,那么这个图形就会被填充。默认值是1linetype:线条的类型,8 连接,抗锯齿等。默认情况是 8 连接。cv2.LINE_AA为抗锯齿,这样看起来会非常平滑
语法总结
line(img, pt1, pt2, color, thickness=..., lineType=..., shift=...)rectangle(img, pt1, pt2, color, thickness=..., lineType=..., shift=...)circle(img, center, radius, color, thickness=..., lineType=..., shift=...)ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness=..., lineType=..., shift=...)polylines(img, pts, isClosed, color, thickness=..., lineType=..., shift=...)
6.1 画线
import numpy as np
import cv2
# 黑色的背景图
img = np.zeros((512, 512, 3), np.uint8)
# 蓝色的线, 5px
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
winname = 'example'
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyWindow(winname)6.2 画矩形
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)6.3 画圆
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)6.4 画椭圆
cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)6.5 画多边形
pts = np.array(
[[10, 5],
[20, 30],
[70, 20],
[50, 10]],
np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (255, 255, 255), 1)如果
cv2.polylines()第三个参数是False,我们得到的多边形是不闭合的(首尾不相连)。
注意:
cv2.polylines()可以被用来画很多条线。只需要把想要画的线放在一个列表中,将这个列表传给函数就可以了。每条线都会被独立绘制。这会比用cv2.line()一条一条的绘制要快一些。
6.6 在图片上添加文字
设置参数
- 你要绘制的文字
- 你要绘制的位置
- 字体类型(通过查看
cv2.putText()的文档找到支持的字体) - 字体的大小
- 文字的一般属性如颜色,粗细,线条的类型等。为了更好看一点推荐使用
linetype = cv2.LINE_AA
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255), 2)
winname = 'example'
cv2.namedWindow(winname)
cv2.imshow(winname, img)
cv2.waitKey(0)
cv2.destroyWindow(winname)可以使用
img = cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)来获得新的图像。
5. 鼠标事件
学习目标
- 学习使用 OpenCV 处理鼠标事件
函数
cv2.setMouseCallback()设置鼠标回调函数
5.1 双击的地方绘制圆
查看有哪些事件受支持
import cv2
def print_const(prefix: str) -> None:
prefix += '_'
names = ('{:22} = {:5}'.format(key, val)
for key, val in vars(cv2).items()
if key.startswith(prefix))
print(*names, sep='\n')
print_const('EVENT')ESC 退出,双击的地方绘制圆,不要按 X 关闭窗口,否则会无法绘制
import cv2
import numpy as np
# 鼠标回调函数
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img, (x, y), 100, (255, 0, 0), -1)
# 创建图像与窗口并将窗口与回调函数绑定
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while True:
cv2.imshow('image', img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()拖动绘制绿色矩形,按 m 切换为绘制红色圆点
import cv2
import numpy as np
drawing = False
mode = True
ix, iy = -1, -1
def draw_circle(event: int, x: int, y: int, flags: int,
param) -> None:
global ix, iy, drawing, mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE and\
flags == cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
cv2.circle(img, (x, y), 3, (0, 0, 255), -1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
img = np.zeros((512, 512, 3), np.uint8)
# assert isinstance(img, np.ndarray)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while True:
cv2.imshow('image', img)
key = cv2.waitKey(1) & 0xff
if key == ord('m'):
print('mode:', mode)
mode = not mode
elif key == 27:
break
cv2.destroyAllWindows()8. 调色板
学习目标
- 把滑动条绑定到 OpenCV 窗口上
函数
cv2.creatTrackbar()创建拖动条cv2.getTrackbarPos()获取拖动条位置
import cv2
import numpy as np
def nothing(x: object) -> None:
...
img = np.zeros((300, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R', 'image', 0, 255, nothing)
cv2.createTrackbar('G', 'image', 0, 255, nothing)
cv2.createTrackbar('B', 'image', 0, 255, nothing)
switch = '0:OFF\n1:ON'
cv2.createTrackbar(switch, 'image', 0, 1, nothing)
while True:
cv2.imshow('image', img)
key = cv2.waitKey(1) & 0xff
if key == 27:
break
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
s = cv2.getTrackbarPos(switch, 'image')
if s == 0:
img[:] = 0
else:
img[:] = b, g, r
cv2.destroyAllWindows()结合上一节的知识,创建一个画板,可以自选各种颜色的画笔绘画各种图形
import cv2
import numpy as np
def nothing(x: object) -> None:
pass
drawing = False
mode = True
ix, iy = -1, -1
def draw_circle(event: int, x: int, y: int, flags: int,
param) -> None:
global ix, iy, drawing, mode
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
color = (b, g, r)
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE and\
flags == cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y),
color, -1)
else:
cv2.circle(img, (x, y), 3, color, -1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
img = np.zeros((300, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R', 'image', 0, 255, nothing)
cv2.createTrackbar('G', 'image', 0, 255, nothing)
cv2.createTrackbar('B', 'image', 0, 255, nothing)
cv2.setMouseCallback('image', draw_circle)
while True:
cv2.imshow('image', img)
key = cv2.waitKey(1) & 0xff
if key == 27:
break
elif key == ord('m'):
mode = not mode
cv2.destroyAllWindows()