此次学习OpenCV是为了参加一个机器视觉相关的大创项目,老师的要求是OpenCV+Python。
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。OpenCV用C++语言编写,它的主要接口也是C++语言,该库也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的接口。
电脑为win10系统,之前安装了Python3.7,直接在命令行安装:
pip install opencv-python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
# 载入图像
im = cv2.imread('./0.png')
# 打印图像尺寸
h,w = im.shape[:2]
print(h,w)
# 保存PNG格式图像为JPEG格式
cv2.imwrite('./0.jpg',im)
注意:import cv2不是指OpenCV2版本,”cv2”中的”2”并不表示OpenCV的版本号。我们知道,OpenCV是基于C/C++的,”cv”和”cv2”表示的是底层C API和C++API的区别,”cv2”表示使用的是C++API。这主要是一个历史遗留问题,是为了保持向后兼容性。
此外,在OpenCV中,图像就是用numpy.ndarray存储的。
imread()函数原型:imread(const string& filename, int flag=1)
flag=-1时,8位深度,原通道
flag=0,8位深度,1通道
flag=1, 8位深度 ,3通道
flag=2,原深度,1通道
flag=3, 原深度,3通道
flag=4,8位深度 ,3通道
"IMREAD_UNCHANGED"指定用图片的原来格式打开,即以不改变图片的方式打开,图片是彩色就是彩色,图片是灰度图像就是灰度图像
"IMREAD_GRAYSCALE"指定用灰度图像的方式打开图片,即将原始图像转化为灰度图像再打开
"IMREAD_COLOR"指定用彩色图像打开图片
flag默认为1,即读取为彩色图像,如果要读取为灰度图(单通道),只需要把flag修改为为0即可。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
# 载入图像
im = cv2.imread('./2.png')
print(im.shape)
# create a grayscale version
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
print(gray.shape)
运行结果:
(66, 66, 3)
(66, 66)
注:使用opencv读取图片时, 默认的通道顺序是BGR而非RGB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
#不同参数时的加载图像
grayImg = cv2.imread('./3.png')
cv2.imwrite('3_1.png', grayImg)
grayImg = cv2.imread('./3.png', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('3_2.png', grayImg)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img = cv2.imread('4.png')
cv2.imshow('my image', img) # 参数:显示图像的帧名称、要显示的图像本身
cv2.waitKey() # 参数为等待键盘触发的时间,当delay≤0,可以理解为延迟无穷大毫秒,就是暂停
cv2.destroyAllWindows() # 释放全部窗口
注意:imshow()会放大图片,171k的png图片即可占满全屏,再大的图片会有打不开的现象
另外还有一种显示图像的方法:
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# 载入图像
im = cv2.imread('2.png')
#matplotlib 中图像通道为 RGB,而 OpenCV 中图像通道为 BGR。
#因此进行显示的时候,要注意交换通道的顺序。
im2 = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
# 颜色空间转换
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 显示原始图像
fig = plt.figure()
subplot(121)
plt.gray()
imshow(im2)
title(u'彩色图', fontproperties=font)
axis('off')
# 显示灰度化图像
plt.subplot(122)
plt.gray()
imshow(gray)
title(u'灰度图', fontproperties=font)
axis('off')
show()
import cv2
img = cv2.imread('2.png')
print(img.shape)
# (640, 640, 3)
print(img.size)
# 1228800
print(img.dtype)
# uint8
# 在debug的时候,dtype很重要
运行结果:
(3861, 2574, 3)
29814642
uint8
下面的例子将实现缩放图片并保存,这个在使用 OpenCV 做图像处理的时候都是很常用的操作:
import cv2
img = cv2.imread('./4.png')
print(img.shape[:2])
height, width = img.shape[:2]
reSize1 = cv2.resize(img, (2*width, 2*height), interpolation=cv2.INTER_CUBIC)
reSize2 = cv2.resize(img, (int(width/2), int(height/2)), interpolation=cv2.INTER_CUBIC)
cv2.imshow('reSize1', reSize1)
cv2.imshow('reSize2', reSize2)
cv2.waitKey()
cv2.destroyAllWindows()
import cv2
im = cv2.imread('./0.png')
cv2.putText(im, 'Hello World', (50, 50), 0, 0.5, (0, 0, 255), 2)
cv2.imshow('txt', im)
cv2.waitKey()
cv2.destroyAllWindows()
imgflip = cv2.flip(img,1)
imgcopy = img.copy()
OpenCV提供了VideoCapture类和VideoWriter类来支持各种格式的视频文件。
= cv.VideoCapture( )
= cv.VideoCapture( filename[, apiPreference] )
= cv.VideoCapture( index[, apiPreference] )
# 参数为0时打开电脑摄像头
= cv.VideoWriter( )
= cv.VideoWriter( filename, fourcc, fps, frameSize[, isColor] )
= cv.VideoWriter( filename, apiPreference, fourcc, fps, frameSize[, isColor] )
支持的格式类型会因系统的不同而变化,但应该都支持AVI格式。在到达视频文件末尾之前,VideoCapture类可通过read()函数来获取新的帧,每帧都是一幅基于BGR格式的图像。
可将一幅图像传递给VideoWriter类的write()函数,该函数会将这幅图像加到VideoWriter类所指向的文件中。
fourcc:用于压缩帧的4字符编解码器代码。例如,VideoWriter :: fourcc(‘P’,‘I’,‘M’,‘1’)是MPEG-1编解码器,VideoWriter :: fourcc(‘M’,‘J’,‘P’,‘G’)是一个运动jpeg编解码器等。代码列表可以通过FOURCC页面在视频编解码器中获得。
如下示例读取AVI文件的帧,并采用YUV颜色编码将其写入另一帧中:
import cv2
videoCapture = cv2.VideoCapture(0) # 读取视频文件
fps = videoCapture.get(cv2.CAP_PROP_FPS) # 获取帧率(每秒钟帧数)
# 获取视频流中帧的宽度和高度
size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
# cv2.VideoWriter_fourcc()函数的作用是输入四个字符代码即可得到对应的视频编码器。
videoWriter = cv2.VideoWriter('video2.avi', cv2.VideoWriter_fourcc('I', '4', '2', '0'), fps, size)
# videoCapture.read()写入视频抓取,解码并返回下一个视频帧
# 如果没有抓取帧(摄像机已断开连接,或视频文件中没有帧),则方法返回false,函数返回NULL指针
success, frame = videoCapture.read()
while success: # 循环直到所有帧结束
videoWriter.write(frame)
success, frame = videoCapture.read()
要特别注意:必须要为VideoWriter类的构造函数指定视频文件名,这个文件名对应的文件若存在,会被覆盖。也必须指定视频编解码器。编解码器的可用性根据系统不同而不同。下面是一些常用选项:
cv2.VideoWriter_force(‘I’, ‘4’, ‘2’, ‘0’):该选项是一个未压缩的YUV颜色编码,是4:2:0色度子采样。这种编码有很好的兼容性,但会产生较大文件,文件扩展名为.avi。
cv2.VideoWriter_force(‘P’, ‘I’, ‘M’, ‘1’):该选项是MPEG-1编码类型,文件扩展名为.avi。
cv2.VideoWriter_force(‘X’, ‘V’, ‘I’, ‘D’):该选项是MPEG-4编码类型,如果希望得到的视频大小为平均值,推荐使用此选项,文件扩展名为.avi。
cv2.VideoWriter_force(‘T’, ‘H’, ‘E’, ‘O’):该选项是Ogg Vorbis,文件扩展名应为.ogv。
cv2.VideoWriter_force(‘F’, ‘L’, ‘V’, ‘1’):该选项是一个Flash视频,文件扩展名应为.flv。
帧速率和帧大小也必须要指定,因为需要从另一个视频文件复制视频帧,这些属性可以通过VideoCapture类的get()函数得到。
VideoCapture类可以获得摄像头的帧流。但对摄像头而言,通常不是用视频的文件名来构造VideoCapture类,而是需要传递摄像头的设备索引(device index)。
下面的例子会捕获摄像头10秒的视频信息,并将其写入一个AVI文件中:
import cv2
cameraCapture = cv2.VideoCapture(0)
fps = 30
size = (int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
videoWriter = cv2.VideoWriter('MyOutputVid.avi', cv2.VideoWriter_fourcc('I', '4', '2', '0'), fps, size)
success, frame = cameraCapture.read()
numFramesRemaining = 10 * fps - 1
while success and numFramesRemaining > 0:
videoWriter.write(frame)
success, frame = cameraCapture.read()
numFramesRemaining -= 1
cameraCapture.release()
然而,VideoCapture类的get()方法不能反悔摄像头帧速率的准确值,它总是返回0。
为了针对摄像头创建合适的VideoWriter类,要么对帧速率做出假设,要么使用计时器来测量。摄像头的数量和顺序由系统决定,但OpenCV没有提供任何查询摄像头数量和属性的方法。如果使用无效索引构造了VideoCapture类,就不会得到帧,VideoCapture的read()函数会返回(false, None)。为了不让read()函数从没有正确打开的VideoCapture类中获取数据,可在执行该函数之后使用VideoCapture.isOpened方法做一个判断,该方法返回一个Boolean值。
当需要同步一组摄像头或一个多头摄像头(例如立体摄像头或Kinect)时,read()方法就不再适合了,可用grab()和retrive()方法代替它。