opencv-python
图像入门:
1:读:
cv2.imread()
这个函数用来读取一副图像,第一个参数(必须传)可以是图片的相对路径或者绝对路径
(如果你第一个参数传错,程序不会报错,但是函数的返回值会是None),
第二个参数(可选)指定你要以何种方式读取图片,第二参数是个枚举值它可以是(可以用数字替代):
- cv2.IMREAD_COLOR(1):加载一张彩色图片,忽略它的透明度,在不传第二个参数时,它也是默认值。
- cv2.IMREAD_GRAYSCALE(0):加载灰度图。
- cv2.IMREAD_UNCHANGED(-1):加载一张图片包含它的alpha通道(透明度),就是原图像不做改变的加载。
cv2.imshow()
这个函数用来在一个窗口中显示一幅图片,窗口自动适配图片的大小。
这个函数也接收两个参数,第一个参数是要承载图片的窗口名(字符串类型),第二个参数就是我们要显示的图片。
只要每个窗口的名字不重复,我们可以创建多个窗口。
cv2.waitKey()
是一个键盘绑定函数。它的参数是一个毫秒数。这个函数等待特定的毫秒,如果在这个时间之内有按键按下,
它就会返回相应按键的 ASCII 码(int 类型),然后程序继续运行,如果在给定的时间内没有任何按键按下它会返回 255(int 类型),
然后程序继续运行。特别的,如果你传递一个0(或者一个负数)给这个函数,那么它会一直等待,直到有任何按键按下,然后程序继续运行。
我们也可以只监视某些按键的按下而不是任意按键,这个我们在后面讨论。但是有一点必须注意,cv2.imshow()函数后面必须有cv2.waitKey()函数,否则图片不会显示。
cv2.destroyAllWindows()
将我们创建的所有窗口全部销毁。如果你想销毁任何特定的窗口,
请使用 cv2.destroyWindow() 函数并将特定窗口的名字作为参数传递进去。
cv2.namedWindow()
有时候你可以事先创建好一个窗口后面再载入图片。在这种情况下你可以指定窗口是否可以调整大小,这要用到函数 cv2.namedWindow() 函数。
默认状态下标志位是 cv2.WINDOW_AUTOSIZE 。但是你可以指定标志位为 cv2.WINDOW_NORMAL ,这样你就可以调整窗口的大小了
WINDOW_NORMAL 用户可以调整窗口的大小,也可以将一个窗口从全屏窗口切换到普通窗口
WINDOW_AUTOSIZE 用户不能改变窗口的大小,窗口的大小被所展示的图片所约束
WINDOW_OPENGL opengl支持的窗口
WINDOW_FULLSCREEN 将窗口设置为全屏
WINDOW_FREERATIO 扩展图片不考虑图片的分辨率
WINDOW_KEEPRATIO 扩展图片但考虑图片的分辨率
WINDOW_GUI_EXPANDED 带进度条和工具条
WINDOW_GUI_NORMAL 旧方法
代码:
------------------------------------------
import numpy as np
import cv2# 加载一张彩色图片不包含alpha通道
img = cv2.imread('messi5.jpg',1)
cv2.namedWindow('window_name',cv2.WINDOW_NORMAL)
cv2.imshow('window_name',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
------------------------------------------
2.写
cv2.imwrite()
这个函数用来保存一张图片。
第一个参数是保存之后文件的文件名(可以包下面这段代码首先以彩色忽略透明度的模式加载一张图片,然后显示图片,
如果你按下 ‘s’ 键它会保存图片到指定位置后程序退出,如含文件路径),第二个参数是你想要保存的图片。
如果按下 ‘esc’ 键那么不保存直接退出,如果按了别的键它会提示你,然后程序退出。
提示:官方文档中说如果你使用64位的机器,你必须将 k=cv2.waitKey(0) 改为k=cv2.waitKey(0) & 0xFF,
但是经过我的测试不修改程序仍然可以正常运行。
------------------------------------------
import numpy as np
import cv2img = cv2.imread('messi5.jpg',0)
cv2.imshow('image',img)
k = cv2.waitKey(0)
if k == 27: # wait for ESC key to exit
cv2.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
cv2.imwrite('messigray.png',img)
cv2.destroyAllWindows()
-------------------------------------------
3.Matplotlib
Matplotlib 是python的一个绘图库,它提供了大量的绘图方法。在后面的文章中我们也会遇到,
现在我们来学习如何用 Matplotlib 来显示一张图片。你可以用它来放大、保存图片等等。
注意:在OpenCV中彩色图片是以BGR模式加载的,但在matplotlib中是以RGB模式。
所以如果用OpenCV读取一张彩色图片在matplotlib中将无法正常显示。
-------------------------------------------
import numpy as np
import cv2
from matplotlib import pyplot as pltimg = cv2.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) #对X和Y轴隐藏刻度值
plt.show()
--------------------------------------------
视频入门
1.从相机捕获视频
如果我们想要捕获视频,我们需要创建一个 VideoCapture 对象。它的参数可以是设备的索引或者一个视频文件名。
设备索引就是用来指定从哪个摄像头捕获视频的数字。通常情况下,我们的电脑都只会连接一个摄像头,
所以我们可以简单的传一个0(或-1)。你也可以传一个1来选择第二个摄像头等等。
当你完成这些之后,你就可以一帧一帧的捕获视频了。但是最后我们要释放这个捕捉,请看下面的代码。
--------------------------------------------
import numpy as np
import cv2cap = cv2.VideoCapture(0)
while(True):
#一帧一帧的捕捉视频
ret, frame = cap.read() #捕捉完视频帧之后我们可以对它进行一些操作
resultFrame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #展示处理之后的视频帧
cv2.imshow('frame',resultFrame)
if(cv2.waitKey(1) & 0xFF == ord('q')):
break#最后记得释放捕捉
cap.release()
cv2.destroyAllWindows()
---------------------------------------------
现在对上面的代码进行一些说明,首先我们创建了一个 VideoCapture 对象来捕获视频,视频源为我们的摄像头。
接下来在一个 while 循环里面反复读取我们捕获到的视频帧,这里有几个要注意的地方。当我们读到这一行代码时可能会有疑问。
ret, frame = cap.read()
这里的 read() 函数有两个返回值?要搞清楚这个问题我们必须先了解 VideoCapture 下面的另外两个函数 VideoCapture.grab() 以及 VideoCapture.retrieve()。
VideoCapture.grab() 方法抓取视频文件或摄像头的下一帧,如果抓取成功就返回 true。VideoCapture.retrieve() 方法解码抓取到的视频帧并返回。
而 VideoCapture.read() 函数就是将以上两个函数结合到一起同时返回两个返回值。第一个返回值是一个标志位, true 代表视频帧抓取成功,
第二个返回值就是我们得到的视频帧。
接下来是 cv2.cvtColor() 函数,这个函数用来转换颜色空间。它接收两个参数,第一个参数是要转换的图片,第二个参数是一个枚举值代表如何转换。
比如上面的 cv2.COLOR_BGR2GRAY 就代表要将BGR(OpenCV 读取彩色图像的方式)转换为灰度模式,然后返回转换后的图像。
由于这个函数的枚举值比较多,这里就不一一列举了,具体请参考https://docs.opencv.org/3.2.0/d7/d1b/group__imgproc__misc.html#ga4e0972be5de079fed4e3a10e24ef5ef0
然后这里我们显示视频仍然用的 cv2.imshow()。最后一点是等待按键按下的代码, cv2.waitKey(1) & 0xFF == ord('q') 会对视频的播放产生影响,
这个我们后面再讨论。
有时候,cap 可能没有初始化捕捉器,在这种情况下代码就会出错。你可以用 cap.isOpened() 函数来检查捕捉器是否初始化,如果打开了它会返回 True 。
否则用 cap.open() 手动打开。但是一般情况下 cap 没有初始化都是你的视频文件没有正确传入导致的,在这种情况下请检查你的文件路径或者摄像头索引是否正确。
你还可以使用 cap.get(propid) 方法访问读取到的视频的信息,这里的 propid 就是属性 id 的意思,它是一个从0-18的数字。
其中的一些属性是允许我们通过 cap.set(propid,value) 进行设置的,具体都有哪些属性请参考https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get
举个例子,我们可以用 cap.get(3) 和 cap.get(4) 来取得视频帧的宽和高,默认的是640*480,如果我们想把它改为320*240,
我们可以使用 ret = cap.set(3,320) 和 ret = cap.set(4,240)。
2.从文件播放视频
和从摄像头中读取视频一样,从文件中读取视频只需要把摄像头索引换成文件名,请看下面的代码。
---------------------------------------------------
import numpy as np
import cv2cap = cv2.VideoCapture('demo.avi')
while(cap.isOpened()):
ret,frame = cap.read()
cv2.imshow('frame',frame)
if(cv2.waitKey(1) & 0xFF == ord('q')):
breakcap.release()
cv2.destroyAllWindows()
--------------------------------------------------
这里需要注意的是这一行代码 cv2.waitKey(1) & 0xFF == ord('q') ,这行代码有三个作用:
在 cv2.imshow() 函数之后必须有 cv2.waitKey() 函数否则 cv2.imshow() 函数将不起作用。
这行代码还起到当我们按下 q 键的时候,退出循环。
这段代码还控制视频的播放速度。
现在主要讨论一下第三个作用,如果我们直接运行上面的代码,会发现视频播放速度比它原来的速度快很多,几乎是好几倍的播放速度。
原因是我们是用一个 while 循环读取视频帧的而 cv2.waitKey(value) 在这里的作用是等待 value 毫秒然后执行下一个循环,
换句话说就是每个循环展示一副画面 value 毫秒。注意,这个 value 跟视频的 fps 不是一回事,fps是一秒钟播放多少帧画面,
而 value 是展示一幅图 value 毫秒,大致可以理解为 fps = 1000/value。我们可以用 cap.get(5) 获取视频原本的 fps,比如我上面的视频的 fps 为 24,
所以我的 value 大概取 1000/24 = 42,这样视频的播放速度就大致与它原本的播放速度一致了。
提示1:在进行视频的读取时请确保你已经正确安装了 ffmpeg。如果没有正确安装那么视频将无法读取与播放,好消息是如果你用 pip 安装OpenCV
(使用命令 pip install opencv-python)你会发现在cv2目录下 ffmpeg 的 DLL 文件已经被安装了。
提示2:当你用 cap.get(5) 得到视频源的 fps 时你应该总能得到一个神奇的数字23.976 而不是整数24,对这个问题感兴趣的自行百度。
3.保存视频
保存视频与保存图片不同,我们需要先创建一个 VideoWriter 对象,还要指定输出文件的名字(例如:output.avi),然后指定 FourCC 编码,
之后我们还需要传入输出视频的 fps 以及视频帧的大小(宽和高),最后一个参数是一个 isColor 标志位,如果它为 true 就输出彩色图像,否则输出灰度图像。
FourCC 是一个4个字节的编码用来指定视频的视频的编码格式。在 Windows 平台下主要的视频格式是 DIVX ,它支持 MPEG-4, H.264 和最新 H.265 标准的视频,分辨率可高达4K超高清。
举个例子对于 MJPG 格式的视频,我们可以像cv2.VideoWriter_fourcc('M','J','P','G') 或者 cv2.VideoWriter_fourcc(*'MJPG') 这样的方式来传递 FourCC 码。
下面的代码捕捉一个视频,将它的每一帧沿 x 轴方向翻转,然后保存。
------------------------------------------------
import numpy as np
import cv2cap = cv2.VideoCapture('demo.avi')
# 定义解码器并且创建 VideoWriter 对象
fourcc = cv2.VideoWriter_fourcc(*'XVID')
outWriter = cv2.VideoWriter('output.avi',fourcc,24,(848,480))while(cap.isOpened()):
ret, frame = cap.read()
if(ret==True):
resultFrame = cv2.flip(frame,0) # 写下被翻转后的视频帧
outWriter.write(resultFrame) cv2.imshow('video',resultFrame)
if(cv2.waitKey(42) & 0xFF == ord('q')):
break
else:
break# 所有的工作完成后别忘了释放资源
cap.release()
outWriter.release()
cv2.destroyAllWindows()
-----------------------------------------
这里需要解释的是 cv2.flip() 函数以及 VideoWriter.write() 函数。
cv2.flip() 函数用来翻转一帧图像,他需要两个参数,第一个参数是要翻转的图像,第二个参数是翻转的模式
(0代表按沿 x 轴翻转,整数(比如1)代表按 y 轴翻转,负数代表沿两个坐标轴同时翻转)。
VideoWriter.writer() 函数接收一张图片并把它写到指定的位置,这里指定的位置就是我们创建 VideoWriter 对象时传进去的位置。
绘图入门:
Code
在上面提到的所有函数中,他们都有一些共同的参数:
img : 画板,也就是你要在哪个图像上画图。
color : 你所画图形的颜色。BGR模式,需要传递一个元组,例如(255,0,0)就表示蓝色。对于灰度图传递一个标量值就行了。
thickness : 直线、圆环等图形的线条的粗细。如果这个值是-1就代表闭合的图形,这时图形将被 color 填充。这个参数的默认值是1. lineType : 线型,生成线条的方式,默认值是 8-connected,对这个感兴趣的可以参考这里⑤。其中cv2.LINE_AA可以让曲线获得抗锯齿的效果,从而使曲线更加平滑。
1.绘图线
要画一条直线,我们需要传递直线起始点的坐标。下面的代码我们将在一张黑色的图片上画一条从左上角到右下角的蓝色直线。
-----------------------------------------------------
import numpy as np
import cv2# 创建一个黑色的背景
img = np.zeros((512,512,3),np.uint8)# 画一个宽度为5个像素,颜色为蓝色的对角线。
img = cv2.line(img,(0,0),(511,511),(255,0,0),5)
-----------------------------------------------------
这里说明一下numpy.zeros()函数把一个图像所需要的长宽和通道数用一个三维数组表示出来,并且里面的数据都用0填充,这样我们就会得到一个纯黑的背景。要了解 numpy 里面的array可以参考这里。
2.绘制矩形
要画一个长方形,你需要知道它的左上角与右下角顶点的坐标,我们在背景的右上角画一个绿色的长方形。
---------------------------------------------------------
img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)
---------------------------------------------------------
3.绘图圆
要画一个圆,我们需要指定圆心位置与半径。我们在之前画的长方形内部画一个圆。
---------------------------------------------------------
img = cv2.circle(img,(447,63),63,(0,0,255),-1)
---------------------------------------------------------
4.绘制椭圆
要画一个椭圆,我们需要传递一系列的参数。第一个参数是中心点的位置。下一个参数是椭圆长轴与短轴的长度。angle 参数代表椭圆本身以逆时针方向偏转的角度。startAngle 和 endAngle 代表椭圆的哪一部分被渲染,从长轴开始顺时针方向从 startAngle 到 endAngle 的部分会被渲染。下面我们在背景的中心位置画一个半椭圆。
---------------------------------------------------------
img = cv2.ellipse(img,(255,255),(100,50),0,0,180,(255,0,0),-1)
---------------------------------------------------------
5.绘制多边形
要画一个多边形,我们首先需要知道它顶点的坐标。然后把所有的顶点放到一个形状为ROWSx1x2的数组里面。这里ROWS就是顶点的个数,它必须是 int32 类型的值。
----------------------------------------------------------
pts = np.array([[10,5],[20,30],[70,20],[50,10]],np.int32)
pts = pts.reshape((-1,1,2))
img = cv2.polylines(img,[pts],True,(0,255,255))
----------------------------------------------------------
现在我们讨论上面的几个函数,第一个是numpy.array()这个函数用来生成一个数组,它比 Python 自带的 list 性能要好。这里我们给它传了一个二维数组,
我们要用reshape()函数将它转换为一个ROWSx1x2格式的三维数组。reshape函数里面的-1代表这个维度是有其他两个维度计算而来的,数组的转换规律是不能改变原数组中的元素,
原来二维数组中有8个元素,那么转换后的三维数组也是8个元素,所以其实上面的-1的位置就是4,对numpy.array不熟悉的请参考这里。接下来使用画多条直线的函数cv2.polylines()将多边形画出来。
其中的第三个参数如果是 False 的话图形第一个点和最后一个点不会连起来,你就得不到一个闭合的图形了。
提示:cv2.polylines()可以被用来画一组直线,它比用cv2.line()一条一条的画直线效率高很多。
6.向图像添加文字:
要在图像上显示文字,你需要指定以下内容
你想要写的文字数据
你想要放置文字的坐标位置
字体
字号
颜色、粗细、线型等等,这里推荐使用lineType = cv2.LINE_AA线型
我们写一个白色的 RYAN 在图像的底部。
---------------------------------------------------------
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'RYAN',(10,500),font,4,(255,255,255),2,cv2.LINE_AA)
---------------------------------------------------------
7.绘图代码整合:
将绘图的代码整合一下:
----------------------------------------------------------
import numpy as np
import cv2# zeros() 函数第一个参数是一个元组(高,宽,通道数(1,3或4的一个枚举值))
# 第二个参数是一个 DataType
img = np.zeros((512,512,3),np.uint8)# line() 函数第一个参数是画板,第二个第三个分别是起始点(左上角为(0,0))
# 第四个参数是线的颜色(BGR模式),最后一个是线的粗细。
img = cv2.line(img,(10,10),(501,501),(255,0,0),1)
img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),2)
img = cv2.circle(img,(255,255),63,(0,0,255),-1)# 画椭圆需要这么几个参数
# 画板、中心点坐标、长短轴的长度、椭圆的旋转角度、椭圆的起始角度、颜色、线的粗细
img = cv2.ellipse(img,(255,255),(100,50),0,30,360,(0,255,0),-1)pts = np.array([[15,15],[100,90],[210,70],[300,20]],np.int32)
pts = pts.reshape((-1,1,2))
img = cv2.polylines(img,[pts],True,(0,255,255))font = cv2.FONT_HERSHEY_SIMPLEX
img = cv2.putText(img,'Ryan',(10,450),font,6,(255,255,255),2,cv2.LINE_AA)cv2.imshow('img',img)
cv2.waitKey(0)cv2.destroyAllWindows()
-------------------------------------------------------------------