Python从0到100(六十三):Python OpenCV-入门基础知识

举报
是Dream呀 发表于 2024/10/21 21:29:55 2024/10/21
【摘要】 前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学习学习和学业的先行者!欢迎大家订阅专栏:零基础学Python:Python从0...

在这里插入图片描述

前言: 零基础学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)

第二个参数是一个标志,它指定了读取图像的方式:

  1. cv.IMREAD_COLOR: 加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。

  2. cv.IMREAD_GRAYSCALE:以灰度模式加载图片

  3. 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函数
参数:

  1. File:打开文件的对象或者文件名
  2. Dtype:返回的数组类型,因为我们是要去生成一个矩阵,所以说矩阵中每个元素的类型必须是dtype=np.uint8
  3. 参数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()

  1. exit(0):无错误退出
  2. 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) 函数:

  1. 第一个参数是要保存的文件的路径
  2. fourcc 指定编码器
  3. fps 要保存的视频的帧率
  4. frameSize 要保存的文件的画面尺寸
  5. isColor 指示是黑白画面还是彩色的画面,默认是False

2.flip()的作用是使图像进行翻转
cv2.flip(filename, flipcode)
filename:需要操作的图像
flipcode:翻转方式

flipcode参数意义:

  1. 1 水平翻转
  2. 0 垂直翻转
  3. -1 水平垂直翻转

3.cap.release()和cv2.destroyAllWindows() 是用来停止捕获视频和关闭相应的显示窗口的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。