OpenCV - Basics


OpenCV_Basics

with its python binding

 

 

0. Introduction

  • 这破玩意的在安装的时候叫opencv-python,但是在引用的时候叫cv2,至少现在还叫这个名字...

  • OpenCV的包有编号,一个cv1一个cv2,这不是版本号,而是用来指代opencv底层开发语言的版本,一开始的cv1是用C开发的,后来的cv2是用C++开发的

  • 引用OpenCV

 

 

 

1. 图片

1.1 图片格式

  • 一般的彩图是以RGB(Red-Green-Blue)模式储存的,但是OpenCV中彩图是以BGR(Blue-Green-Red)的通道顺序储存的

    颠倒通道顺序是哪个逆天人物想出来的啊kora

    bgr

    一般B, G, R channel values在不同图片类型下的取值范围:

  • Alpha Channel是除了BGR以外的第四通道——“非彩色通道”,能读取透明度

  • 灰度图则只有一个通道

 

1.2 导入图片 cv2.imread()

  • 参数1 - 图片路径

    • 与代码在同一文件夹下可直接写文件名'hao_kang_de.png'

    • 不在同一文件夹下则需要给出完整路径/home/user_name/hao_kang_de.png

    Tip:路径中不要有中文

  • 参数2 - 读取模式(Optional)

    • cv2.IMREAD_UNCHANGED - 4通道(BGR+Alpha)彩图(-1)

    • cv2.IMREAD_GRAYSCALE - 单通道灰度图(0)

    • cv2.IMREAD_COLOR - 3通道(BGR)彩图(1),默认值

  • 返回值 - BGR形式的图像对象,类型为numpy.ndarray

 

1.3 显示图片 cv2.imshow()

  • 参数1 - 窗口的名称

    • 如果定义窗口则需要二者的窗口名称保持一致

    • 不先定义窗口那么打开的就是不可调整的自适应大小的窗口

  • 参数2 - 导入的图片

  • 配套的辅助性代码:

    • cv2.waitKey() (Mandatory)

      参数 - 等待的时间(单位:ms),时间到(或者按下某个键)后会执行接下来的程序,若数值为0则意味着一直等下去

      1. waitKey控制着imshow的持续时间,所以二者必须配合食用:imshow后不跟waitKey相当于没有给imshow提供显示图像的时间

      2. waitKey不是time.sleep(),前者必须在必须在至少存在一个HighGUI窗口的时候才会起作用;后者则是无条件的延时机制,且对HighGUI窗口不起作用;所以time.sleep()代替不了waitKey!

      3. 一行常用的代码的解释:

        • cv2.waitKey(1000) - returns a 32-bit integer corresponding to a pressed key in 1000ms

        • 0xFF - hex,换成bin为11111111,换成dec是255

        waitKey返回值的范围是0-255,但是linux上的waitKey可能会返回比255更大的数值(毕竟总共有32位),拿0xFF来做位与运算的目的是通过它保留waitKey正常返回值(前8位),屏蔽掉不该有但可能出现的的后24位。

    • cv2.namedWindow() (Optional)

      参数1 - 窗口的名称

      参数2 - 窗口的类型

      • cv2.WINDOW_AUTOSIZE - 默认值,窗口大小自适应图片,不可调整(图片大的时候会很nasty)

      • cv2.WINDOW_NORMAL - 窗口大小可以调整

 

1.4 保存图片 cv2.imwrite()

  • 参数1 - 包含后缀名的文件名(.bmp, .png, .jpg, .webp等等)

  • 参数2 - 要保存的图片

 

1.5 读取属性信息

  • Shape of an imageimg.shape

    img是彩图,则返回一个三项的tuple:(rows, columns, channels)

    img是灰度图,则只有两项,不返回channel的数量

  • Sum of pixelsimg.size

    请注意,它返回的不是单一图层的pixel数量,而是三个图层所有pixel的数量,这点可以用img.shape的数据计算得来

  • Image data typeimg.dtype/astype

 

1.6 像素级修改

听起来很酷吧?其实并不(

需要始终记住:导入的图片是有图层的,而每个图层都是可以修改的

  • Access pixel

  • Modify pixel

  • 关于单一pixel的单一图层

    以上方式一般是用来选择图片的某个区域的,而对于某个pixel的某个图层,由于读取的图像是numpy数组,numpy内置的array.item()array.itemset()更合适

  • 图像截取

    数据类型是numpy数组,所以用最基本的slicing就可以截取了

 

1.7 通道拆分合并

彩图的BGR三个通道可以拆开,也可以合并

  • cv2.split() - 通道拆分

  • cv2.merge() - 通道合并

实际上split()比较耗时,用numpy索引效率更高

 

1.1.8 色彩空间转换

  • 色彩空间

    BGR和灰度图在图片格式里讲过了

    HSV色彩空间

    • OpenCV中用得最多的色彩空间,比BGR更容易区分颜色(S和V的改变只会导致变成同一颜色的变体)

    • Hue - Saturation - Value(色相 - 饱和度 - 明度)

    HSV饼图

    • 取值范围:

      • Hue - [0, 179]

      • Saturation - [0, 255]

      • Value - [0, 255]

      Hue的理论数值应当是[0, 360],然而8bit图像最大只有255,所以OpenCV中Hue的范围被除了2

  • 空间转换

    • 参数1 - 待转换的导入的图片

    • 参数2 - 转换模式,常用的两个:

      • BGR到灰度图 - cv2.COLOR_BGR2GRAY

      • BGR到HSV - cv2.COLOR_BGR2HSV

    色彩转换其实是数学运算,比如灰度化常用的公式是:gray = R * 0.299 + G * 0.587 + B * 0.114

 

1.1.9 图片混合

  • 直接相加

    叠加两张格式,高度,宽度,通道数都相同的图片时,可以用cv2.add(),也可以a + b(numpy数组相加),但原理不一样

    但是如果是Binary Image(只有0和255两种值,不是灰度图!),那么两种方法的结果是一样的

  • 加权混图

    cv2.addWeighted()允许将两张图片按照以下公式线性加权混合

    imgneo=αimg1+βimg2+γ

    image blending

 

 

2. 视频流

OpenCV提供了用于处理视频的类cv2.VideoCapture

2.1 捕获视频

cv2.VideoCapture() 既能处理相机视频流,也能处理视频文件

参数 - 可以是相机的设备索引号,也可以是到某个现成视频的path

返回值 - 捕获的cv2.VideoCapture对象

相机的设备索引号默认值为-1,表示随机选取一个摄像头

0代表第一个摄像头(一般是笔记本内置的那个),1代表第二个...以此类推

 

2.2 “确保”打开相机

cv2.VideoCapture.open() 用于打开相机

cv2.VideoCapture.isOpened() 用于检测相机是否正确打开,返回值为bool

 

2.3 读帧(播放)

  • cv2.VideoCapture.read()

    • 简单读帧

      这个函数能在视频流中捕获帧信息,会返回两个量:

      • 是否正确读取帧(bool)

      • 读取的帧的图像,如果没读到则该值为空

    • 播放视频

      我们可以通过控制waitKey()的时长来控制视频播放速度(相当于控制每一帧的时间)

      每读完一帧,cap.read()都会自动指向下一帧,所以视频会正常播放下去,read()的具体机制可以拆分为“解码已读帧”和“指向下一帧”两部分,详见下文的grab()retrieve()

  • cv2.VideoCapture.grab()

    这个函数用于指向下一帧,返回一个bool来表示是否成功

  • cv2.VideoCapture.retrieve()

    这个函数用于解码grab()捕获的视频帧,返回内容与read()一样

  • read()grab(), retrieve()的关系

    read()可以理解为grab()retrieve()的结合体:grab()指向下一帧,retrieve()解码并返回这一帧的图像

 

2.4 属性读取/修改

cv2.VideoCapture.get() 传入VideoCaptureProperties(propID)即可查看,可参考这个网址

cv2.VideoCapture.set() 传入propID和需要的数值就即可修改属性

propID可以是属性名称,也可以是代表它们的数字

常用的propID与其对应的数字如下:

 

2.5 保存视频

不是捕获!是保存

 

3. 善后工作(释放资源)

3.1 cv2.destroyAllWindows()

这个屑函数的功能如下:

  • close all the windows

  • de-allocate any associated memory usage

一般来说不涉及内存资源调用的简单程序不需要这一行,操作系统会take care of everything

然而它还是很重要啊啊啊啊啊!!!

 

3.2 cv2.destroyWindow()

可以定向关闭某个窗口,释放相关资源

 

3.3 cv2.VideoCapture.release()

如果说有一个cv2.VideoCapture()类的对象cap,那就能用典中典的cap.release()

这个屑函数的功能是在程序结束时候释放视频流,比如已经打开的视频文件/已经初始化的摄像头

 

 

4. 绘图函数

WARNING:绘图函数均会直接影响原图

4.1 空手搓图

如前文所言,OpenCV的图片数据是以numpy数组的形式储存的,所以...

 

4.2 直线&矩形&多边形

  • 直线cv2.line()

  • 矩形 cv2.rectangle()

  • 多边形 cv2.polylines()

 

4.3 圆形&椭圆形

OpenCV中的原点在左上角,坐标轴方向是正常的

  • 圆形cv2.circle()

  • 椭圆形cv2.ellipse

 

4.4 文字

cv2.putText() - 添加文字的函数