01_OpenCV 中的 Gui 特性
1 OpenCV 中的 Gui 特性
1.1 图片
本节重点:
-
图片的读入(
cv2.imread()) -
图片的显示(
cv2.imshow()) -
图片的保存(
cv2.imwrite()) -
拓展:matplotlib
1.1.1 图片的读入
cv2.imread()
查看该函数的帮助文档:
>>> import cv2
>>> help(cv2.imread)
由帮助文档,我们可以看出,imread() 使用的语法格式如下:
imread(filename[, flags])
- filename:图像路径及名称。
- flags:告诉函数应该如何读取这幅图片。
- cv2.IMREAD_COLOR:读入一副彩色图像。图像的透明度会被忽略,默认参数。 --->传递参数:1
- cv2.IMREAD_GRAYSCALE:以灰度模式读入图像 。--->传递参数:0
- cv2.IMREAD_UNCHANGED:读入一幅图像,并且包括图像的 alpha 通道
import numpy as np
import cv2
# 以灰度模式加载图像
# img = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.imread('test.jpg', 0)
此时,打印img,返回一组矩阵值。
注意:就算图像的路径是错的, OpenCV 不会产生任何提醒,但是当print(img)时,得到的结果是None。
1.1.2 图片的显示
cv2.imshow(),其语法格式如下:
imshow(winname, mat)
显示图像时,图像会自动调整为图像大小。
- winname:窗口名称
- mat:图像(矩阵)
cv2.imshow('demo', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中,
cv2.waitKey()- 键盘绑定函数
- 它的时间尺度是毫秒级。函数等待特定的几毫秒,看是否有键盘输入。特定的几毫秒之内,如果按下任意键,这个函数会返回按键的 ASCII 码值,程序将会继续运行。如果没有键盘输入,返回值为 -1,如果我们设置这个函数的参数为 0,那它将会无限期的等待键盘输入。它也可以被用来检测特定键是否被按下,例如按键 a 是否被按下, 后续会讨论。
- 键盘绑定函数
cv2.destroyAllWindows()- 退出任何已建立的窗口。
- 如果退出指定的窗口,可以使用
cv2.destroyWindow([name]),[name]为我们欲退出的窗口名称。
Notes:
一 种 特 殊 的 情 况 是, 你 也 可 以 先 创 建 一 个 窗 口, 之 后再 加 载 图 像。 这 种 情 况 下, 你 可 以 决 定 窗 口 是 否 可 以 调 整大 小。 使 用 到 的 函 数 是 cv2.namedWindow()。 初 始 设 定 函 数标 签 是 cv2.WINDOW_AUTOSIZE。 但 是 如 果 你 把 标 签 改 成cv2.WINDOW_NORMAL,你就可以调整窗口大小了。当图像维度太大,或者要添加轨迹条时,调整窗口大小将会很有用
Demo:
import numpy as np import cv2 img = cv2.imread('demo.jpg') cv2.namedWindow('demo', cv2.WINDOW_NORMAL) cv2.imshow('demo', img) cv2.waitKey(0) cv2.destroyAllWindows()此时,显示出来的图片,我们就可以调整窗口了。
1.1.3 图片的保存
cv2.imwrite(),其语法格式如下:
imwrite(filename, img[, params])
- filename:图像要保存的路径及名称。
- img:图像矩阵。
cv2.imwrite('./savetest.png', img)
1.1.4 键盘控制窗口
首先,看一个例子:
import numpy as np
import cv2
img = cv2.imread('demo.jpg', 0)
cv2.imshow('demo', img)
k = cv2.waitKey(0)
if k == ord('q'):
cv2.destroyAllWindows()
elif k == ord('s'):
cv2.imwrite('savetest.jpg', img)
cv2.destroyAllWindows()
注意:如果你用的是 64 位系统,你需要将 k = cv2.waitKey(0) 这行改成k = cv2.waitKey(0)&0xFF。
1.1.5 matplotlib的结合
Matplotib 是 python 的一个绘图库,有各种各样的绘图方法。之后会陆续了解到。现在,你可以学习怎样用 Matplotib 显示图像。你可以放大图像,保存它等等。
import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('demo.jpg', 0) # grayimage
plt.imshow(img, cmap='gray', interpolation='bicubic')
plt.axis('off')
plt.show()
延伸:
程序中,我们以灰度模式读取图像,尝试其他模式读取图像,看一下最终显示的图像有什么不同。
彩色图像使用 OpenCV 加载时是 BGR 模式。但是 Matplotib 是 RGB模式。所以彩色图像如果已经被 OpenCV 读取,那它将不会被 Matplotib 正确显示。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('demo.jpg')
b, g, r = cv2.split(img)
img2 = cv2.merge([r, g, b])
plt.subplot(121);plt.imshow(img) # expects distorted color
plt.subplot(122);plt.imshow(img2) # expect true color
plt.show()
cv2.imshow('bgr image',img) # expects true color
cv2.imshow('rgb image',img2) # expects distorted color
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('demo.jpg')
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow('RGB image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1.2 视频
本节重点
- 视频文件读取
- 视频文件显示
- 视频文件保存
- 摄像头获取并显示视频
- 两个函数cv2.VideoCapture()和cv2.VideoWriter()
1.2.1 用摄像头捕获视频
OpenCV为摄像头捕捉实时图像提供了一个十分简单的接口。
现在我们尝试捕捉一段视频,并将其转换为灰度视频并显示出来。
cv2.VideoCapture():视频获取函数。
通过help()命令查看其使用:
help(cv2.VideoCapture)
为获取视频,需要创建一个 VideoCapture 对象。其参数可以是设备的索引号,或者是一个视频文件。设备索引号就是指定要使用的摄像头。一般的笔记本电脑都有内置摄像头。所以参数就是 0。你可以通过设置成 1 或者其他的来选择别的摄像头。之后,你就可以一帧一帧的捕获视频了。但是最后,别忘了停止捕获视频。
Demo:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Can't open camera")
exit()
while True:
# 一帧一帧的捕获视频
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting...")
break
# 对幁视频进行操作
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 显示结果
cv2.imshow('frame', gray)
if cv2.waitKey(1) & 0xff == ord('q'):
break
# 释放捕获
cap.release()
cv2.destroyAllWindows()
- cap.read() 返回一个布尔值。
- 如果幁读取正确,则返回True,否则,返回False。
- 可以通过检查其返回值来查看文件是否到了结尾。
cap可能不能成功的初始化摄像头设备。此时,代码会报错。这个时候,可以使用cap.isOpened(),来检查是否成功初始化了。如果返回值为True,说明初始化成功。否则,可以使用函数cap.open()。
你可以使用函数cap.get(propId) 来获得视频的一些参数信息。这里propId 可以是 0 到 18 之间的任何整数。每一个数代表视频的一个属性,见下表 cv::VideoCapture::get() ,其中的一些值可以使用 cap.set(propId,value) 来修改, value 就是你想要设置成的新值。
例如,我可以使用cap.get(cv.CAP_PROP_FRAME_WIDTH) 和 cap.get(cv.CAP_PROP_FRAME_HEIGHT) (比如cpa.get(3)和cap.get(4) 来查看每一帧的宽和高。默认情况下得到的值是 640X480。但是我们可以使用 ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320) and ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)(比如ret=cap.set(3,320)和 ret=cap.set(4,240) )来把宽和高改成 320X240。
1.2.2 视频保存
我们捕获视频,逐帧处理,我们希望保存该视频。 对于图像,保存非常简单,只需使用cv.imwrite()。 对于视频的保存,需要做更多的工作。
这次我们创建一个VideoWriter对象。 我们应该指定输出文件名(例如:output.avi)。 然后我们应该指定FourCC编码。 然后,应传递的每秒帧数(fps)和帧大小。 最后一个是isColor标志。 如果是True,则是彩色帧,否则,它适用于灰度帧。
FourCC是一个4字节编码,用于指定视频编解码器。 可在fourcc.org中找到可用代码列表。 它的平台是独立的。 以下编解码器对我来说很好。
- In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)
- In Windows: DIVX (More to be tested and added)
- In OSX: MJPG (.mp4), DIVX (.avi), X264 (.mkv).
FourCC 码以下面的格式传给程序,以 MJPG 为例:
cv2.cv2.FOURCC('M','J','P','G') 或者 cv2.cv2.FOURCC(*'MJPG')。
下面的代码是从摄像头中捕获视频,沿水平方向旋转每一帧并保存它 。
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create Videowriter object
fourcc = cv2.VideoWriter_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)
# write the flipped frame
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) &0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
1.2.3 从文件中播放视频
与从摄像头中捕获相同,我们只需要把设备索引号改成视频文件的名字。在播放每一帧时,使用cv2.waitKey()设置适当的持续时间。如果设置的太低,视频会播放的很快。如果设置的太大,视频就是播放的很慢(可用来控制视频的播放速度,通常25ms即可)
import numpy as np
import cv2
cap = cv2.VideoCapture('output.avi')
while cap.isOpened():
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting...")
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
1.3 OpenCV中的绘图函数
目标:
- 学会用OpenCV绘制不同的几何形状
- 将要学习的函数:
- cv2.line()
- cv2.circle()
- cv2.rectangle()
- cv2.ellipse()
- cv2.putText()
- etc.
编码约定
涉及的所有绘图函数,设置如下:
•img:你想要绘制图形的图像。
•color:形状的颜色。以 RGB 为例,需要传入一个元组,例如:(255,0,0),代表蓝色。对于灰度图只需要传入灰度值。
•thickness:线条的粗细。如果给一个闭合图形设置参数为 -1,那么这个图形就会被填充。默认值是 1。
•linetype:线条的类型, 8 联通线型,抗锯齿线型等。默认情况是 8 联通线型。 cv2.LINE_AA为抗锯齿线型,这样看起来会非常平滑。
1.3.1 直线绘制
要绘制线条,需要传递线条的起点和终点坐标。
接下里的例子中,我们将创建一个黑色图像,并在其中从左上角到右下角绘制一条蓝线。
import numpy as np
import cv2
# Create a black image
img = np.zeros((512, 512, 3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
cv2.imshow('bgr', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
matplotlib:
import numpy as np
import cv2
import matplotlib.pyplot as plt
# Create a black image
img = np.zeros((512, 512, 3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img, (0, 0), (511, 511), (0, 0, 255), 5)
plt.imshow(img, 'gray')
plt.show()
1.3.2 矩形绘制
要绘制矩形,您需要指定矩形的左上角和右下角。 这次我们将在图像的右上角绘制一个绿色矩形。
# Draw a green rectangle at the top-right corner of image
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
1.3.3 圆形绘制
要绘制圆,需要其中心坐标和半径。
我们将在上面绘制的矩形内绘制一个圆。
# Draw a circle inside the rectangle drawn above
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
1.3.4 椭圆绘制
要绘制椭圆,我们需要传递几个参数。 一个参数是中心位置(x,y)。 下一个参数是轴长度(长轴长度,短轴长度)。 角度是椭圆在逆时针方向上的旋转角度。 startAngle和endAngle表示从主轴顺时针方向测量的椭圆弧的起点和终点。 即给出值0和360给出完整的椭圆。 有关更多详细信息,请查看cv.ellipse()的文档。 下面的示例在图像的中心绘制一个半椭圆。
# Draws a half ellipse at the center of the image
cv2.ellipse(img, (255, 256), (100, 50), 0, 0, 180, (0, 0, 255), -1)
1.3.5 多边形绘制
要绘制多边形,首先需要顶点坐标。 将这些点组成一个形状为ROWSx1x2的数组,其中ROWS是顶点数,它应该是int32类型。 在这里,我们绘制一个带有四个黄色顶点的小多边形。
# raw a small polygon of with four vertices in yellow color
pts = np.array([[10, 5],
[20, 30],
[70, 20],
[50, 10]],
np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 255, 255))
注意
- 如果第三个参数为False,您将获得连接所有点的折线,而不是闭合形状。
cv2.polylines()可用于绘制多条线。 只需创建要绘制的所有行的列表,然后将其传递给函数。 所有线条都将单独绘制。 绘制一组行比为每行调用cv2.line()要好得多,速度更快。
1.3.6 向图像添加文本:
为了将文本放入图像中,您需要指定以下内容:
- 要写入的文本数据
- 放置位置坐标(即数据开始的左下角)。
- 字体类型(使用
cv2.putText()的帮助文档可以查看OpenCV支持的字体) - 字体缩放(指定字体大小)
- 常规的东西,如颜色,粗细,线型等。为了更好看,建议使用
lineType = cv2.LINE_AA。
我们将在图像上书写白色的"OpenCV"字样。
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'Hello, OpenCV', (10, 500), font, 2, (255, 255, 255), 2, cv2.LINE_AA)
最后,是时候看看我们绘图的最终结果了。
正如之前文章中所研究的那样,显示图像以查看它:
import numpy as np
import cv2
# Create a black image
img = np.zeros((512, 512, 3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
cv2.ellipse(img, (255, 256), (100, 50), 0, 0, 180, 255, -1)
pts = np.array([[10, 5],
[20, 30],
[70, 20],
[50, 10]],
np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 255, 255))
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'Hello, OpenCV', (10, 500), font, 2, (255, 255, 255), 2, cv2.LINE_AA)
cv2.imshow('bgr', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

其他资源
椭圆函数中使用的角度不是我们的圆角。 有关更多详细信息,请访问此讨论。
练习
尝试使用OpenCV中提供的绘图功能创建OpenCV的徽标。
# OpenCV徽标绘制
import numpy as np
import cv2
# 创建白色背景画布
img = np.ones((512, 512, 3), np.uint8) * 255
# 绘制3个圆
cv2.circle(img,(256,200),60,(0,0,255),-1)
cv2.circle(img,(256,200),25,(255,255,255),-1)
cv2.circle(img,(181,328),60,(0,255,0),-1)
cv2.circle(img,(181,328),25,(255,255,555),-1)
cv2.circle(img,(331,328),60,(255,0,0),-1)
cv2.circle(img,(331,328),25,(255,255,255),-1)
# 在圆环上叠加三角形,形成缺口圆环的效果
tri1=np.array([256,200,219,264,293,264],np.int32)
tri1=tri1.reshape((-1,1,2))
tri2=np.array([[181,328],[256,328],[218,264]],np.int32)
tri3=np.array([[331,328],[368,264],[293,264]],np.int32)
cv2.fillPoly(img,[tri1,tri2,tri3],(255,255,255)) # 为方便看清,颜色可先设置
# 添加文字
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'OpenCV', (125,450), font, 2, (0, 0, 0), 10)
cv2.imshow('bgr', img)
cv2.waitKey(0)
cv2.destroyAllWindows()


浙公网安备 33010602011771号