使用NumPy和OpenCV进行计算机视觉的入门指南

0f1f7448db055698a45f6877bd3a0c20.jpeg

动机

我们人类通过我们的视觉系统感知环境和周围的事物。人眼、大脑和肢体共同工作,以感知环境并相应地行动。一个智能系统可以执行那些需要一定智力水平的任务,如果由人类执行的话。因此,对于执行智能任务,人工视觉系统对于计算机来说是重要的事物之一。通常,摄像头和图像用于收集执行工作所需的信息。计算机视觉和图像处理技术帮助我们执行类似于人类完成的任务,如图像识别、目标跟踪等。

在计算机视觉中,摄像头充当人眼来捕捉图像,处理器充当大脑来处理捕捉的图像并生成重要的结果。但是人类和计算机之间存在基本差异。人脑自动工作,智力是天生获得的。相反,计算机没有智能,没有人类的指导(程序)就无法进行。计算机视觉是提供适当指令的方式,以便它可以与人类视觉系统兼容工作。但能力是有限的。

在接下来的部分中,我们将讨论图像是如何形成并如何使用Python进行操作的基本概念。

目录
  1. 图像是如何形成并显示的

  2. 计算机如何将图像存储在内存中

  3. 灰度和彩色图像

  4. 使用NumPy处理图像的基础知识

  5. OpenCV基础知识

  6. 与NumPy一起玩耍

图像是如何形成并显示的

图像只是由具有不同颜色强度的像素组合而成。术语“像素”和“颜色强度”可能对你来说是陌生的。别担心,阅读本文直到最后,一切将变得清晰。

像素是数字图像的最小单元/元素。详细信息请参见下图。

bc67a98a43d9544631582dea1b80ccbe.png

显示是由像素形成的。在上图中,有25列和25行。每个小正方形被认为是一个像素。该设置可以容纳625个像素。它代表一个具有625个像素的显示屏。如果我们用不同颜色强度(亮度)照亮像素,它将形成一幅数字图像。

计算机如何将图像存储在内存中?

如果我们仔细看图像,我们可以将其与2D矩阵进行比较。矩阵具有行和列,其元素可以通过其索引进行寻址。矩阵结构类似于数组。计算机将图像存储在计算机内存的数组中。

每个数组元素保存颜色的强度值。通常,强度值范围从0到255。出于演示目的,我已包含了图像的数组表示。

0270585c6e366459acc5d21e977ae054.png
灰度和彩色图像

灰度图像是一幅黑白图像。它只由一种颜色形成。接近0的像素值代表黑暗,随着强度值的增加变得更亮。最大值是255,代表白色。一个2D数组足以保存灰度图像,就像上图所示。

彩色图像不能只由一种颜色形成;可能有数十万种颜色组合。主要有三个主要的颜色通道红(R)、绿(G)和蓝(B)。每个颜色通道都存储在一个2D数组中,并保存其强度值,最终图像是这三个颜色通道的组合。

4cbd33f9d190dc4e897475583c2f8d4c.png

这种颜色模型有(256 x 256 x 256)= 16,777,216种可能的颜色组合。你可以在这里可视化组合。

但在计算机内存中,图像存储方式不同。

a5499b9a0e863fd7ea9bb18d6c041d1b.png

计算机不知道RGB通道。它知道强度值。红色通道存储在高强度中,绿色和蓝色通道分别存储在中等和低强度值中。

使用NumPy处理Python的基础知识

NumPy是进行科学计算的基本Python包。它主要作为一个数组对象工作,但它的操作不仅限于数组。然而,该库可以处理各种数字和逻辑运算[1]。你可以在这里找到NumPy的官方文档。

让我们开始我们的旅程。首要之事。

  • 导入NumPy库。

import numpy as np

现在是时候使用NumPy了。正如我们所知,NumPy与数组一起工作。因此,让我们尝试创建我们的第一个全零2D数组。

  • 创建NumPy数组

np.zeros((5,5))
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])

就是这么简单。我们也可以创建一个所有元素都是1的NumPy数组,就像下面这样。

b=np.ones((4,4))
print(b)
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]]

有趣的是,NumPy还提供了一种用任何值填充数组的方法。简单的语法array.fill(value)可以完成任务。

b.fill(3)
print(b)
[[3. 3. 3. 3.]
 [3. 3. 3. 3.]
 [3. 3. 3. 3.]
 [3. 3. 3. 3.]]

数组'b'中所有元素现在都填充为3。

  • 在随机数生成的情况下种子的功能

只需查看以下编码示例。

#with random seed 
np.random.seed(10)
sample_arr = np.random.randint(0,50,10)
sample_arr
array([ 9, 36, 15,  0, 49, 28, 25, 29, 48, 29])
#without random seed-1
no_rand_seed=np.random.randint(0,50,10)
no_rand_seed
array([49,  8,  9,  0, 42, 40, 36, 16, 36, 47])
#without random seed-2
no_rand_seed=np.random.randint(0,50,10)
no_rand_seed
array([11, 24, 43, 33,  8, 36, 14, 49, 13,  5])

在第一个代码单元格中,我们使用了np.random.seed(seed_value),但是对于另外两个代码单元格,我们没有使用任何种子。有一个在有种子和没有种子的情况下生成随机数的主要区别。在有种子的情况下,生成的随机数对于特定的种子值保持不变。另一方面,在没有种子值的情况下,每次执行都会产生不同的随机数。

  • NumPy的基本操作(max、min、mean、reshape等)

NumPy通过提供大量函数来执行数学运算,使我们的生活更加轻松。array_name.min()、array_name.max()、array_name.mean()这些语法帮助我们找到数组的最小值、最大值和平均值。编码示例 —

sample_arr.max()
49
sample_arr.min()
0
sample_arr.mean()
26.8

最小值和最大值的索引可以使用语法array_name.argmax()、array_name.argmin()提取。示例 —

sample_arr.argmin()
3
sample_arr.argmax()
4

数组重塑是NumPy的重要操作之一。array_name.reshape(row_no, column_no)是重塑数组的语法。在重塑数组时,我们必须注意重塑前后的数组元素数量。在两种情况下,总元素数量必须相同。

sample_arr.reshape(5,2)
array([[ 9, 36],
       [15,  0],
       [49, 28],
       [25, 29],
       [48, 29]])
  • 数组索引和切片

每个数组元素都可以通过其列和行号来寻址。让我们生成另一个具有10行和10列的数组。

new_array = np.arange(0,100).reshape(10,10)
print(new_array)
[[ 0  1  2  3  4  5  6  7  8  9]
 [10 11 12 13 14 15 16 17 18 19]
 [20 21 22 23 24 25 26 27 28 29]
 [30 31 32 33 34 35 36 37 38 39]
 [40 41 42 43 44 45 46 47 48 49]
 [50 51 52 53 54 55 56 57 58 59]
 [60 61 62 63 64 65 66 67 68 69]
 [70 71 72 73 74 75 76 77 78 79]
 [80 81 82 83 84 85 86 87 88 89]
 [90 91 92 93 94 95 96 97 98 99]]

假设我们想要找到数组的第一个值。可以通过传递行和列索引(0,0)来提取。

row=0
column=0
new_array[row,column]
0

特定行和列的值可以使用语法array_name[row_no,:]、array_name[:,column_no]进行切片。

# Column slicing
new_array[:,column]
array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
#Row slicing
new_array[row,:]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

让我们尝试切片数组的中心元素。

new_array[3:7,3:7]
array([[33, 34, 35, 36],
       [43, 44, 45, 46],
       [53, 54, 55, 56],
       [63, 64, 65, 66]])
OpenCV基础知识

OpenCV是由Intel开发的计算机视觉的开源Python库[2]。尽管其范围广泛,我将讨论一些OpvenCv的用法。你可以在这里找到官方文档。

我使用了以下图像进行演示。

ea90018d362eaf2d5b36b1d5774e1f6b.jpeg
  • 导入OpenCV和Matplotlib库

import cv2
import matplotlib.pyplot as plt

Matplotlib是一个可视化库,它帮助可视化图像。

  • 使用OpenCV读取图像并用Matplotlib可视化

image=cv2.imread('sunflower.jpg')
plt.imshow(image)
<matplotlib.image.AxesImage at 0x232abb93b50>
17364069af0176e4ea74416555cb8ec6.jpeg

我们用OpenCV读取了图像,并用Matplotlib库可视化了它。颜色发生变化,因为OpenCV以BGR格式读取图像,而Matplotlib期望以RGB格式读取图像。因此,我们需要将图像从BGR转换为RGB。

  • 将图像从BGR格式转换为RGB格式

RGB = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(RGB)
<matplotlib.image.AxesImage at 0x232ad2606d0>
b00aa19df83e8405bc1462ba5b9df10d.jpeg

现在,图像看起来正常了。

  • 将图像转换为灰度

我们可以使用cv2.COLOR_BGR2GRAY轻松将图像从BGR转换为灰度,如下所示。

gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
plt.imshow(gray)
<matplotlib.image.AxesImage at 0x232adc51370>
83e41b9066e78f200c0421286220e58f.jpeg

尽管已将其转换为灰度,但上述图像并不是真正的灰度图。它已在Matplotlib中进行了可视化。默认情况下,Matplotlib使用灰度以外的颜色映射。为了正确可视化它,我们需要在Matplotlib中指定灰度颜色映射。让我们来做这个。

plt.imshow(gray,cmap='gray')
<matplotlib.image.AxesImage at 0x232adf19850>
83f8011d87eaffe9f0e4088d717c69d9.jpeg
  • 旋转图像

使用OpenCV旋转也是一项简单的任务。cv2.rotate()函数帮助我们实现这一点。顺时针和逆时针90度和180度旋转如下所示。

rotate_90 = cv2.rotate(RGB,cv2.ROTATE_90_CLOCKWISE)
plt.imshow(rotate_90)
<matplotlib.image.AxesImage at 0x232ae9126d0>
c2d61f06bf58321270f7358ea72ef236.jpeg
rotate_90 = cv2.rotate(RGB,cv2.ROTATE_90_COUNTERCLOCKWISE)
plt.imshow(rotate_90)
<matplotlib.image.AxesImage at 0x232ae1d9460>
a9c2b4629c676534589a647ac1b962e5.jpeg
rotate_180 = cv2.rotate(RGB,cv2.ROTATE_180)
plt.imshow(rotate_180)
<matplotlib.image.AxesImage at 0x232ae244100>
022f8e334df2010493f31d86c392970e.jpeg
  • 调整图像大小

我们可以通过将宽度和高度像素值传递给cv2.resize()函数来调整图像的大小。

resized=cv2.resize(RGB, (800,1400))
plt.imshow(resized)
<matplotlib.image.AxesImage at 0x232ae5e2460>
cec14975093b767c76fe3776305e8974.jpeg
  • 在图像上绘制

有时我们需要在现有图像上绘制。例如,我们需要在图像对象上绘制一个边界框以识别它。让我们在花朵上绘制一个矩形。cv2.rectangle()函数帮助我们进行绘制。它接受一些参数,例如我们要在其上绘制矩形的图像、左上角的坐标点(pt1)和右下角的坐标点(pt2),以及边界线的厚度。以下是一个编码示例。

cv2.rectangle(RGB,pt1=(500,200),pt2=(1250,1000),color=(255,0,0),thickness=15)
plt.imshow(RGB)
<matplotlib.image.AxesImage at 0x232b1305f70>
e164a1b8c7226daba3cfc482ff7e018f.jpeg

还有其他的绘图函数,如cv.line()、cv.circle()、cv.ellipse()、cv.putText()等。完整的官方文档可以在这里找到[3]。

与NumPy一起玩耍

我们将更改图像的强度值。我将尽量保持简单。所以,请考虑前面显示的灰度图像。查找图像的形状。

gray.shape
(1280, 1920)

它显示为一个大小为1200 x 1920的2D数组。在基本的NumPy操作中,我们学习了如何切片一个数组。

gray[400:800,750:1350]=255
plt.imshow(gray,cmap='gray')
<matplotlib.image.AxesImage at 0x232aba7dc10>
e5c921334f9b1ca7475c8be8fbc24aae.jpeg

利用这个概念,我们取了灰度图像数组切片[400:800, 750:1350]并将强度值替换为255。最后,我们对其进行可视化并得到上述图像。

结论

计算机视觉是现代计算机科学技术中一个有前途的领域。我总是强调对任何领域的基本知识的重要性。我仅讨论了计算机视觉的基本知识并展示了一些实际编码。这些概念非常简单,但对于计算机视觉的初学者可能起着重要作用。

完整的代码可以在这里找到。

https://github.com/Zubair063/ML_articles/tree/main/Getting%20Started%20with%20NumPy%20and%20OpenCV

这是计算机视觉系列的第一篇文章。请关注以阅读即将发布的文章。

[注:教练Jose Portilla的课程帮助我收集知识。]

参考文献

https://numpy.org/devdocs/

https://en.wikipedia.org/wiki/OpenCV

https://docs.opencv.org/4.x/dc/da5/tutorial_py_drawing_functions.html

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

74490abbc14f2135c8eb9e64cbb85087.jpeg

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值