Python OpenCV 使用介绍

王 茂南 2021年8月18日07:23:36
评论
1 5360字阅读17分52秒
摘要本文是对 Python OpenCV 的一个介绍。包含 opencv 的基础操作(读入图像,显示图像)等。

简介

在本文中,我们将会介绍 Python 中的 OpenCV 库来介绍计算机视觉的各个方面。OpenCV 是一个旨在解决计算机视觉问题的 Python 库。

OpenCV 最初由 Intel 在 1999 年开发,但是后来由 Willow Garage 资助。它支持很多编程语言,如C++,Python,Java 等等。它也支持多种平台,包括 Windows,Linux 和 MacOS。

OpenCV Python 只是一个与 Python 一起使用的原始 C++ 库的包装类。通过使用它,所有OpenCV 数组结构都能被转化为 NumPy 数组或从 NumPy 数组转化而来。这样就可以轻松地将其与其他使用 NumPy 的库集成。例如,SciPy 和 Matplotlib 等库。

 

计算机如何读取图像

在详细介绍 Python OpenCV 之前,我们首先看一下「计算机是如何读取图片」的。下面是一张「纽约天际线」的图像:

Python OpenCV 使用介绍

对于计算机来说,他将任何图片都读取为一组 0 到 255 之间的值。对于任何一张彩色图片,有三个主通道——红色(R),绿色(G)和蓝色(B)。对于黑白照片就只有一个通道了。

计算机对每个原色(R,G,B)创建一个矩阵;然后,组合这些矩阵以提供 R, G 和 B 各个颜色的像素值。每一个矩阵的元素提供与像素的亮度强度有关的数据。

下图是计算机读取上面「纽约天际线」的过程,会分别创建三个矩阵,分别表示每个像素 R,G,B的强度:

Python OpenCV 使用介绍

 

参考资料

 

OpenCV 基础操作

我们首先需要按照下面的方式安装 opencv-python 的库:

  1. pip install opencv-python

后面就可以按照下面的方式导入 opencv-python 库了。

  1. import cv2

 

使用 OpenCV 加载图像-imread

我们使用下面的图像来作为例子:

Python OpenCV 使用介绍

我们使用 cv2.imread 来读取图像,后面的参数 1 表示「彩色图像」,最终是一个三维的矩阵,说明 RGB 三个通道都有值:

  1. import cv2
  2. img = cv2.imread("kenan.png", 1) # 彩色图像
  3. print(img.shape)
  4. # >> (188, 329, 3)

如果想要读取为黑白的图像,只需要将参数设置为 0 即可:

  1. import cv2
  2. img = cv2.imread("kenan.png", 0) # 黑白图像
  3. print(img.shape)
  4. # >> (188, 329)

 

使用 OpenCV 显示图像-imshow

在加载完毕之后,我们想要将图像显示出来,这里可以使用 cv2.imshow 来进行图像的显示:

  1. import cv2
  2. img = cv2.imread("kenan.png", 0) # 黑白图像
  3. cv2.imshow("KeNan", img)
  4. cv2.waitKey(20000) # 等待一段时间
  5. cv2.destroyAllWindows() # 关闭窗口

最后需要加上 waitkey,来使得图像可以显示一段时间。最终的效果如下所示:

Python OpenCV 使用介绍

 

创建图像

有的时候我们需要创建纯白色或是纯黑色的图像,可以使用 numpy 来定义一个矩阵即可:

  1. import numpy as np
  2. blank_image = np.zeros((height,width,3), np.uint8) # 纯黑色
  3. blank_image = np.zeros((height,width,3), np.uint8)*255 # 纯白色

上面是定义了纯黑色与纯白色的图像,当然我们也可以对图片颜色进行修改。修改为「左侧是蓝色」,「右侧是绿色」:

  1. blank_image[:,0:width//2] = (255,0,0)      # (B, G, R)
  2. blank_image[:,width//2:width] = (0,255,0)

最终的效果如下图所示:

Python OpenCV 使用介绍

参考资料,Create a new RGB OpenCV image using Python?

 

转换图像的颜色空间-cvtColor

颜色空间转换,例如将彩色的图片转换为灰度图。同时需要注意的是,opencv 的彩色图片是 BGR 颜色空间的,如果希望 matplotlib 可以正常显示,需要转换为 RGB 颜色空间(图像处理-matplotlib显示opencv图像)。我们使用 cv2.cvtColor 来转换颜色空间。

例如下面的例子,我们将彩色图像转换为灰度图,使用了 cv2.COLOR_BGR2GRAY

  1. img = cv2.imread("kenan.png", 1) # 彩色图像
  2. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图

关于 opencv 中 color space 的介绍可以参考,OpenCV Color Conversions

 

OpenCV 格式与 Pillow 格式互相转换

有一点需要牢记:

  • OpenCV 中图像的颜色空间是 BGR
  • Pillow 中的颜色空间是 RGB

OpenCV 格式到 Pillow 格式

图片通过 OpenCV 读取是 numpy 的格式,通过 Image.fromarray() 将其转换为 pillow 的格式:

  1. img = cv2.imread("./cat.png")
  2. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  3. print(type(img)) # <class 'numpy.ndarray'>
  4. im_pil = Image.fromarray(img) # 转换为 pillow 格式
  5. print(type(im_pil)) # <class 'PIL.Image.Image'>

参考资料Convert opencv image format to PIL image format?

 

Pillow 格式到 OpenCV 格式

将 pillow 格式转换为 OpenCV 格式其实就是转换为 numpy 的格式。我们只需要使用 np.array(或是 np.asarray,这个节约内存) 即可。注意下面进行了颜色空间的转换(转换到了 OpenCV 使用的 BGR 颜色空间)

  1. pil_image  = Image.open('./cat.png').convert('RGB')
  2. open_cv_image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) # 转换为 opencv 的格式

参考资料Convert image from PIL to openCV format

 

 

阈值处理

全局阈值处理-threshold

之前我们介绍了将图像转换为了「灰度图」,但是有时我们还希望可以将图像只保留「两种颜色」,即非黑即白,于是可以使用 cv2.threshold

  1. cv2.threshold (源图片, 阈值, 填充色, 阈值类型)

这里的「阈值」是「全局阈值」,也就是整个图片都会使用这个阈值。而「阈值类型」有以下的五种:

  • cv.THRESH_BINARY:当小于「阈值」则为 0,大于「阈值」为「填充色」;
  • cv.THRESH_BINARY_INV:当小于「阈值」则为「填充色」,大于「阈值」为 0;
  • cv.THRESH_TRUNC:当小于「阈值」则不变,大于「阈值」为「阈值」;
  • cv.THRESH_TOZERO:当小于「阈值」则为 0,大于「阈值」不变;
  • cv.THRESH_TOZERO_INV:当小于「阈值」则不变,大于「阈值」为 0;

下图是五种情况的效果图:

Python OpenCV 使用介绍

我们还是对上面柯南的图片进行二值化:

  1. img = cv2.imread("kenan.png", 1) # 彩色图像
  2. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
  3. ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) # 转换为「二值图」
Python OpenCV 使用介绍

关于 cv2.threshold 详细的介绍可以查看链接,OpenCV Thresholding。但是有的时候直接使用上面的方式进行全局的二值化效果不会很好,于是会出现自适应阈值

 

自适应阈值-adaptiveThreshold

在上面我们介绍了使用全局值作为阈值,但是这并非在所有情况都是好的。例如一副图像在不同的地区的照明条件是不一样的。于是在这种情况下自适应阈值是有作用的。

这里「自适应阈值」会根据一小个区域来确定阈值,相当于一个图片的不同区域的阈值是不同的。我们可以使用 adaptiveMethod 决定阈值是如何计算的(有两种方式):

  • cv.ADAPTIVE_THRESH_MEAN_C:阈值是邻域面积的平均值减去常数C
  • cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域值减去常数C的高斯加权总和。

还有其他两个参数,分别是:

  • BLOCKSIZE,确定附近区域的大小和;
  • C,是从邻域像素的平均或加权总和中减去一个常数;

下面是一个例子,分别是不同的「阈值处理」的效果:

Python OpenCV 使用介绍

我们还是使用上面的柯南来作为例子,看一下「自适应阈值」的效果(注意我们将图片进行了平滑,在第三行代码):

  1. img = cv2.imread("kenan.png", 1) # 彩色图像
  2. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
  3. img_gray = cv2.medianBlur(img_gray, 3)
  4. thresh = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize=11, C=2)

最终的效果如下所示:

Python OpenCV 使用介绍

关于「自适应阈值」的方式可以查看链接,OpenCV Adaptive Thresholding

 

关于图像的轮廓

轮廓可以简单的理解为「链接所有连续点的曲线」,具有相同的颜色。为了获得更好的准确率。输入图像应该是「二进制图像」(即需要先使用阈值处理)

我们看下面的例子,将上面「柯南」的图像二值化之后,我们使用 cv2.findContours 来寻找轮廓(这里是寻找白色部分的轮廓),使用 cv2.drawContours 来绘制轮廓:

  1. img = cv2.imread("kenan.png", 1) # 彩色图像
  2. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
  3. img_gray = cv2.medianBlur(img_gray, 5) # 图像进行平滑
  4. thresh = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize=11, C=2) # 二值化
  5. contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 寻找区域
  6. thresh_draw = cv2.drawContours(img, contours, -1, (0,255,0), 1)

最终的效果如下所示:

Python OpenCV 使用介绍

上面返回的 contours 是轮廓的坐标。我们可以将 contours 与循环结合,逐步绘制轮廓。下面看一个例子:

  1. import cv2
  2. img = cv2.imread("kenan.png", 1) # 彩色图像
  3. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
  4. img_gray = cv2.medianBlur(img_gray, 5) # 图像进行平滑
  5. thresh = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize=11, C=2) # 二值化
  6. contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 寻找区域
  7. for i in contours:
  8.     thresh_draw = cv2.drawContours(img, i, -1, (0,255,0), 1)
  9.     cv2.imshow("1.jpg", thresh_draw)
  10.     cv2.waitKey(100) # 等待一段时间
  11. cv2.destroyAllWindows() # 关闭窗口

最终的结果如下所示,可以看到绿色的轮廓线逐渐出现:

Python OpenCV 使用介绍

我们把轮廓和上面阈值处理的结果放在一起:

Python OpenCV 使用介绍

关于图像的轮廓可以参考链接,OpenCV Contours

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南
  • 本文由 发表于 2021年8月18日07:23:36
  • 转载请务必保留本文链接:https://mathpretty.com/13927.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: