The future of you, waiting for you in the future.

Geoffrey

Long, long the pathway to Cold Hill;
Drear, drear the waterside so chill.

返回顶部

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()

posted @ 2019-12-26 22:11  Geoffreygau  阅读(176)  评论(0)    收藏  举报