Python从0到100(六十三):Python OpenCV-入门基础知识
前言:
零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学习学习和学业的先行者!
欢迎大家订阅专栏:零基础学Python:Python从0到100最新最全教程!
说起OpenCV大家肯定也都很熟悉,它是我们目标检测(人脸识别)中,最常用的方法了,但你真的懂OpenCV,接下来我将带大家走进它的内心深处,听一听专属于它的秘密…
@[TOC](Python OpenCV史诗级入门:)
一、OpenCV简介
1.背景故事:
OpenCV
是计算机视觉中经典的专用库,其支持多语言、跨平台,功能强大。 OpenCV-Python为OpenCV提供了Python接口,使得使用者在Python中能够调用C/C++,在保证易读性和运行效率的前提下,实现所需的功能。
2.为啥要用Python实现OpenCV:
Python是由Guido van Rossum发起的通用编程语言,很快就非常流行,主要是因为它的简单性和代码可读性。它使程序员可以用较少的代码行表达想法,而不会降低可读性。
与C/C++之类的语言相比,Python速度较慢。也就是说,可以使用C/C++轻松扩展Python,这使我们能够用C/C++编写计算密集型代码并创建可用作Python模块的Python包装器。这给我们带来了两个好处:首先,代码与原始C/C++代码一样快(因为它是在后台运行的实际C++代码),其次,在Python中比C/C++编写代码更容易。OpenCV-Python是原始OpenCV C++实现的Python包装器。
OpenCV-Python利用了Numpy,这是一个高度优化的库,用于使用MATLAB样式的语法进行数值运算。所有OpenCV数组结构都与Numpy数组相互转换。这也使与使用Numpy的其他库(例如SciPy和Matplotlib)的集成变得更加容易。
二、Win10 下 Pycharm 配置OpenCV-Python
1. 安装 解释器(Python or Anaconda)和Pycharm(Professional or Community)
如何安装Python和Pycharm以及怎样去配置他们的环境呢,大家可以参考我的这篇文章,里面有非常详细的教学:全网首发,一篇文章带你走进pycharm的世界,在这里我就不再赘述了~~~😜😜😜
2.在Pycharm中添加openCV-Python 和CV2
1.首先在设置中找到Python解释器:
2.然后点击右侧加号,进入Manage Repositories:
3.再次点击右侧加号,配置更多的下载网址给Manage Repositories,以避免无法成功下载的问题:
这里基本上所有的下载网址了~
https://pypi.python.org/simple
https://pypi.tuna.tsinghua.edu.cn/simple/
http://mirrors.aliyun.com/pypi/simple/
http://pypi.hustunique.com/
http://pypi.sdutlinux.org/
http://pypi.douban.com/simple/
http://pypi.mirrors.ustc.edu.cn/
5.然后回到前面的界面中,输入openCV-python 查找,并点击“Install Package”安装,并在出现Package ‘opencv-python’安装成功后完成。
6. 继续安装cv2或cv2-extra,直到成功。
7.回到Settings窗口,可以看到安装完成的插件
经过这样一系列的操作过后,相信你已经成功安装了编译器及所需要的OpenCV模块,那么接下来进入我们的实战模块!
三、图像入门
1.读取图像
在这里我们使用cv.imread()函数读取图像,图像应该在工作目录或图像的完整路径应给出。
img = cv.imread('messi5.jpg',0)
第二个参数是一个标志,它指定了读取图像的方式:
-
cv.IMREAD_COLOR: 加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。
-
cv.IMREAD_GRAYSCALE:以灰度模式加载图片
-
cv.IMREAD_UNCHANGED:加载图像,包括alpha通道
注意: 除了这三个标志,可以分别简单地b表示为整数1、0或-1
import numpy as np
import cv2 as cv
#加载彩色灰度图像
img = cv.imread('messi5.jpg',0)
警告:
即使图像路径错误,它也不会引发任何错误,但是print(img)会给出None
2.OpenCV常见报错处理
有时候我们在运行上面的程序时,经常会报错,但是代码一模一样,却就是会报错,这是为啥呢?
其实img = cv.imread("jike.jpg", 1)
这个代码只支持英文路径,什么意思呢:就是我们的文件夹或者所要读取的照片,因为为了方便记录,我们通常会将其进行中文命名,但是这样就导致了imread
函数不能进行识别。
有的小伙伴说了,这好办,我全都把它命名为中文呗~~其实,大可不必这样,我们还有别的函数为我们解决这一问题!
img = cv.imdecode(np.fromfile("哈哈.jpg", dtype = np.uint8),0)
这个函数便可以帮助我们进行中文的识别。
这里用到的是Numpy.Fromfile(file,dtype=float,count=1)
,处理矩阵的一个函数。
功能: 根据文件中的数据来构造一个数组。该函数从已知文件格式的文本中读取数据是相当有效的。PS:用于向文件中写数据可用tofile函数
参数:
- File:打开文件的对象或者文件名
- Dtype:返回的数组类型,因为我们是要去生成一个矩阵,所以说矩阵中每个元素的类型必须是dtype=np.uint8
- 参数0和上文中的imread函数中第二个参数的意义是完全一样的!
3.显示图像
使用函数 cv.imshow() 在窗口中显示图像。窗口自动适合图像尺寸。
第一个参数是窗口名称,它是一个字符串。第二个参数是我们的对象。你可以根据需要创建任意多个窗口,但可以使用不同的窗口名称。
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()
(1)图像操作
cv.waitKey() 是一个键盘绑定函数。其参数是以毫秒为单位的时间。该函数是在一个给定的时间内(单位ms)等待用户按键触发;
如果用户没有按下键,则继续等待 (循环)。常见 : 设置 waitKey(0) , 则表示程序会无限制的等待用户的按键事件。
一般在 imgshow 的时候 , 如果设置 waitKey(0) , 代表按任意键继续。
(2)视频操作
显示视频时,延迟时间需要设置为 大于0的参数
delay > 0时 , 延迟 ”delay”ms , 在显示视频时这个函数是有用的 ,
用于设置在显示完一帧图像后程序等待 ”delay”ms 再显示下一帧视频 ;
如果使用 waitKey(0) 则只会显示第一帧视频!
(3) 特定代码
if cv2.waitKey(100) == 27: # 特定的100ms
print('wait 100 ms')
等待用户触发事件 , 等待时间为 100ms , 如果在这个时间段内 , 用户按下 ESC(ASCII码为27) , 执行 if 体 ;如果没有按,if函数不做处理。
3.写入图像
使用函数cv.imwrite()保存图像。第一个参数是文件名,第二个参数是要保存的图像。 cv.imwrite(‘messigray.png’,img)
这会将图像以PNG格式保存在工作目录中。
import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27: # 等待ESC退出
cv.destroyAllWindows()
elif k == ord('s'): # 等待关键字,保存和退出
cv.imwrite('messigray.png',img)
cv.destroyAllWindows()
(1)保存JPEG类型的图片
cv.imwrite("jike7.jpg", img,[int(cv.IMWRITE_JPEG_QUALITY), 100])
第三个参数针对特定的格式: 对于JPEG,其表示的是图像的质量,用0-100的整数表示,默认为95。
(2)保存PNG类型的图片
cv.imwrite("./jike1.png", img,[int(cv.IMWRITE_PNG_COMPRESSION), 0])
对于PNG,第三个参数表示的是压缩级别。
cv2.IMWRITE_PNG_COMPRESSION,从0到9,压缩级别越高,图像尺寸越小。默认级别为3。cv.imwrite("./jike3.png", img)
4.使用Matplotlib
Matplotlib是Python的绘图库,可为你提供多种绘图方法,你可以使用Matplotlib缩放图像,保存图像等:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('jike.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 cv2 as cv
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
# 逐帧捕获
ret, frame = cap.read()
# 如果正确读取帧,ret为True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# 我们在框架上的操作到这里
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 显示结果帧e
cv.imshow('frame', gray)
if cv.waitKey(1) == ord('q'):
break
# 完成所有操作后,释放捕获器
cap.release()
cv.destroyAllWindows()
oh~~代码好像有点多诶,没事,我们详细的来看一下:
1.cap = cv.VideoCapture(0)
要捕获视频,你需要创建一个 VideoCapture 对象。它的参数可以是设备索引或视频文件的名称。
2.exit()
- exit(0):无错误退出
- exit(1):有错误退出
3.ret,frame= cap.read()
第一个参数ret
为True 或者False,代表有没有读取到图片,函数返回的第1个参数ret(return value缩写)是一个布尔值,表示当前这一帧是否获取正确;第二个参数frame
表示截取到一帧的图片。
4.cv.imshow(‘frame’, gray)
使用函数cv2.imshow(wname,img)显示图像,第一个参数是显示图像的窗口的名字,第二个参数是要显示的图像(imread读入的图像),窗口大小自动调整为图片大小。
5.gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
我们在框架上的操作到这里,平时处理图像的时候,很少用到彩色信息,一般都是直接转换为灰度图。
这里就是将我们的彩色图转化为COLOR_BGR2GRAY灰度图,但其实灰度图也不止cv.COLOR_BGR2GRAY
一个参数,还有COLOR_RGB2GRAY
另一个参数。
2.简单对比 COLOR_BGR2GRAY和COLOR_RGB2BGR
转换灰度图用的cvtColor的第三个参数中有两个参数,我一直没太注意区别,CV_RGB2GRAY与CV_BGR2GRAY,今天通过一个简单的测试区分一下:
(1)彩色图像
框选的左上角处(B = 157, G = 183, R = 220),右下角处(B = 163, G = 182, R = 203):
(2)CV_BGR2GRAY
利用CV_BGR2GRAY将原图src转换为灰度图bgr2grayImg,计算公式为Gray = 0.1140B + 0.5870G + 0.2989*R:
左上角:0.1140 * 157 + 0.5870 * 183 + 0.2989 * 220 ≈ 191
右下角:0.1140 * 163 + 0.5870 * 182 + 0.2989 * 203 ≈ 186
(3)CV_RGB2GRAY
利用CV_RGB2GRAY将原图src转换为灰度图rgb2gray,转换公式Gray = 0.1140R + 0.5870G + 0.2989*B:
左上角:0.1140 * 220 + 0.5870 * 183 + 0.2989 * 157 ≈ 179
右下角:0.1140 * 203 + 0.5870 * 182 + 0.2989 * 163 ≈ 179
可以看出:
两者相比,转换的系数一致,不同的是系数后紧跟的通道的顺序变化了,由BGB变为RGB。
3.知识延伸
(1)waitkey()函数
waitkey
控制着imshow
的持续时间,当imshow之后不跟waitkey时,相当于没有给imshow提供时间展示图像,所以只有一个空窗口一闪而过。添加了waitkey后,哪怕仅仅是cv2.waitkey(1)
,我们也能截取到一帧的图像。所以cv2.imshow后边是必须要跟cv2.waitkey的!
(2)对比cv.waitKey(1)和waitKey(1000) & 0xFF
cv2.waitKey()是一个键盘绑定函数。它的时间量度是毫秒ms。函数会等待(n)里面的n毫秒,看是否有键盘输入。若有键盘输入,则返回按键的ASCII值。没有键盘输入,则返回-1。一般设置为0,他将无线等待键盘的输入。
0xFF
是一个十六进制数,转换为二进制是11111111。waitKey返回值的范围为(0-255),刚好也是8个二进制位。那么我们将 cv2.waitKey(1) & 0xFF计算一下(不知怎么计算的可以百度位与运算)发现结果仍然是waitKey的返回值,那为何要多次一举呢?直接 cv2.waitKey(1) == ord(‘q’)不就好了吗。
实际上在linux上使用waitkey有时会出现waitkey返回值超过了(0-255)的范围的现象。通过cv2.waitKey(1) & 0xFF运算,当waitkey返回值正常时 cv2.waitKey(1) = cv2.waitKey(1000) & 0xFF,当返回值不正常时,cv2.waitKey(1000) & 0xFF的范围仍不超过(0-255),就避免了一些奇奇怪怪的BUG~
(3)cap.get(propId)函数
另外,通过cap.get(propId)可以获取摄像头的一些属性,比如捕获的分辨率,亮度和对比度等。propId是从0~18的数字,代表不同的属性:
# 获取捕获的分辨率
# propId可以直接写数字,也可以用OpenCV的符号表示
width, height = cap.get(1), cap.get(3)
print(width, height)
这里是propId属性表:
参数 | 说明 |
---|---|
VideoCapture.get(0) | 视频文件的当前位置(播放)以毫秒为单位 |
VideoCapture.get(1) | 基于以0开始的被捕获或解码的帧索引 |
VideoCapture.get(2) | 视频文件的相对位置(播放):0=电影开始,1=影片的结尾 |
VideoCapture.get(3) | 在视频流的帧的宽度 |
VideoCapture.get(4) | 在视频流的帧的高度 |
VideoCapture.get(5) | 帧速率/帧数/fps |
VideoCapture.get(6) | 编解码的4字-字符代码 |
VideoCapture.get(7) | 视频文件中的帧数 |
VideoCapture.get(8) | 返回对象的格式 |
VideoCapture.get(9) | 返回后端特定的值,该值指示当前捕获模式 |
VideoCapture.get(10) | 图像的亮度(仅适用于照相机) |
VideoCapture.get(11) | 图像的对比度(仅适用于照相机) |
VideoCapture.get(12) | 图像的饱和度(仅适用于照相机) |
VideoCapture.get(13) | 色调图像(仅适用于照相机) |
VideoCapture.get(14) | 图像增益(仅适用于照相机)(Gain在摄影中表示白平衡提升) |
VideoCapture.get(15) | 曝光(仅适用于照相机) |
VideoCapture.get(16) | 指示是否应将图像转换为RGB布尔标志 |
VideoCapture.get(17) | × 暂时不支持 |
VideoCapture.get(18) | 立体摄像机的矫正标注(目前只有DC1394 v.2.x后端支持这个功能) |
(4)cap.set(propId,value)函数
使用cap.set(propId,value)来修改属性值:
# 以原分辨率的一倍来捕获
cap.set(cv.CAP_PROP_FRAME_WIDTH, width * 2)
cap.set(cv.CAP_PROP_FRAME_HEIGHT, height * 2)
#经验之谈:某些摄像头设定分辨率等参数时会无效,因为它有固定的分辨率大小支持,一般可在摄像头的资料页中找到
4.从文件播放视频
它与从相机捕获相同,只是用视频文件名更改摄像机索引。另外,在显示框架时,请使用适当的时间cv.waitKey()。如果太小,则视频将非常快,而如果太大,则视频将变得很慢(嗯,这就是显示慢动作的方式)。正常情况下25毫秒就可以了。
import numpy as np
import cv2 as cv
cap = cv.VideoCapture('宝儿.mp4')
while cap.isOpened():
ret, frame = cap.read()
# 如果正确读取帧,ret为True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
cv.imshow('frame', frame)
if cv.waitKey(25) == ord('q'):
break
cap.release()
cv.destroyAllWindows()
5.保存视频
所以我们捕捉一个视频,一帧一帧地处理,我们想要保存这个视频。对于图像,它非常简单,只需使用 cv.imwrite()。
这里保存的视频格式可选择:DIVX,XVID,MJPG,X264,WMV1,WMV2。(最好使用XVID。MJPG会生成大尺寸的视频。X264会生成非常小的尺寸的视频)
import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
# 定义编解码器并创建VideoWriter对象
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
frame = cv.flip(frame, 0)
# 写翻转的框架
out.write(frame)
cv.imshow('frame', frame)
if cv.waitKey(1) == ord('q'):
break
# 完成工作后释放所有内容
cap.release()
out.release()
cv.destroyAllWindows()
函数须知
1.out = cv.VideoWriter(‘output.avi’, fourcc, 20.0, (640, 480),True) 函数:
- 第一个参数是要保存的文件的路径
- fourcc 指定编码器
- fps 要保存的视频的帧率
- frameSize 要保存的文件的画面尺寸
- isColor 指示是黑白画面还是彩色的画面,默认是False
2.flip()的作用是使图像进行翻转
cv2.flip(filename, flipcode)
filename:需要操作的图像
flipcode:翻转方式
flipcode参数意义:
- 1 水平翻转
- 0 垂直翻转
- -1 水平垂直翻转
3.cap.release()和cv2.destroyAllWindows() 是用来停止捕获视频和关闭相应的显示窗口的。
- 点赞
- 收藏
- 关注作者
评论(0)