介绍
您以前是否使用过图像数据?或许您想要建立自己的物体检测模型,或者只是想计算进入大楼的人数。使用计算机视觉技术处理图像的可能性是无穷无尽的。
但我最近观察数据科学发展的趋势,人们坚信,在处理非结构化数据(尤其是图像数据)时,深度学习模型是发展的方向。深度学习技术无疑表现得非常好,但这是处理图像的唯一方法吗?
并非所有人都拥有像Google和Facebook等技术巨头那样的无限资源。那么如果不使用深度学习,我们如何处理图像数据呢?

我们可以借助机器学习的力量!是的,我们可以使用简单的机器学习模型,例如决策树或支持向量机(SVM)。如果我们提供合适的数据和功能,这些机器学习模型可以充分发挥作用,甚至可以用作基准解决方案。
因此,在这篇适合初学者的文章中,我们将了解图像提取特征的不同方式。然后,您可以在自己喜欢的机器学习算法中使用这些方法!
目录
- 计算机如何保存图像?
- 使用Python读取图像数据
- 特征提取方法1:作为特征的灰度像素值
- 特征提取方法2:通道平均像素值
- 特征提取方法3:边缘提取
计算机如何保存图像?
在学习其他内容之前,了解如何在计算机上读取和存储图像非常重要。首先考虑pd.read_
函数读取图像。
来看一个简单的例子。看下图:

我们有一个数字8的图像。仔细观察图像,会发现它是由小方框组成的,称为像素。
但是我们是以视觉形式看到的图像,可以轻松区分边缘和颜色,识别图片中的内容。但是计算机很难做到这一点。它们是以数字的形式存储图像。看看下面的图片:

计算机以数字矩阵的形式存储图像。矩阵的大小取决于给定图像中的像素数。
假设矩阵的大小为 180 x 200 或 n x m,基本上就是图像的像素数量(高x宽)。
这些像素值表示像素的强度或亮度。较小的数字(接近零)表示黑色,较大的数字(接近于255)表示白色。
下图的尺寸为 22 x 16:

上面的例子是黑白图像。那彩色图像是什么样子?彩色图像也是以二维矩阵的形式存储的吗?
彩色图像通常由多种颜色组成,几乎所有的颜色都可以从三种基色(红色,绿色和蓝色)生成。
因此,在彩色图像中有三个矩阵(或称为通道),分别表示红色,绿色和蓝色。每个矩阵具有0-255之间的值,表示该像素的颜色强度。观察下面的图像:

左边有一个彩色图像,右边有三个颜色通道矩阵。通过叠加三个通道以形成彩色图像。
注意这里的矩阵并不是给定图像的原始像素值,因为给定图像的矩阵非常大并且难以可视化。另外,还有许多其他的存储图像的格式,其中RGB方式是最受欢迎的,也就是上面的例子。
用Python读取图像数据
把理论知识付诸实践。我们将使用Python加载图像并查看图像矩阵的内容:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from skimage.io import imread, imshow
image = imread('image_8_original.png', as_gray=True)
imshow(image)

#checking image shape
image.shape, image
(28,28)

矩阵一共有784个值,这里只是完整矩阵的一小部分。
特征提取方法1:像素值作为特征
从图像提取特征的最简单方法是将这些原始像素值作为单独的特征。
以上面图像为例(数字'8'),图像的大小是28 x 28。
你能猜出这张图片的特征数量吗?特征的数量与像素的数量相同!因此,特征数量是784。
那我们如何保存这784个特征?我们可以简单地累加每个像素值来生成特征向量。如下图所示:

使用Python读取图像并使用该方法提取特征:
image = imread('puppy.jpeg', as_gray=True)
image.shape, imshow(image)
(650,450)

这个图像大小是 650 x 450。因此,它的特征数量应该是 297000。通过使用NumPy中的reshape函数生成特征:
#像素特征
features = np.reshape(image, (660*450))
features.shape, features
(297000,)
数组([0.96470588,0.96470588,0.96470588,...,0.96862745,0.96470588, 0.96470588])
我们得到了该图像的特征,是一个长度为 297000的一维数组。
在该例子中,图像只有一个通道。可以将该方法应用在彩色图像上面吗?
特征提取方法 2:通道平均像素值
在上一节中,我们设置了参数 as_gray = True
,所以图像只有一个通道,可以很容易地累加像素值。接下来删除参数并再次加载图像:
image = imread('puppy.jpeg')
image.shape
(660,450,3)
该图像的大小是(660,450,3),其中的3是通道数量。我们可以使用上面的方法提取特征。在这种情况下,特征的数量将是660 * 450 * 3 = 891000。
或者,也可以使用另一种方法:
生成一个三个通道像素的平均值的新矩阵,而不是直接使用三个矩阵的像素值。
如下图所示:

这样处理之后特征的数量将保持不变,并且还考虑了图像的三个通道的像素值。在Python代码中,将创建一个大小为 660 x 450 的新矩阵,值初始化为0。这个矩阵会存储三个通道的平均像素值:
image = imread('puppy.jpeg')
feature_matrix = np.zeros((660,450))
feature_matrix.shape
(660,450)
有一个三维矩阵(660 x 450 x 3),其中660是高度,450是宽度,3是通道数。使用for循环获得平均像素值:
for i in range(0,iimage.shape[0]):
for j in range(0,image.shape[1]):
feature_matrix[i][j] = ((int(image[i,j,0]) + int(image[i,j,1]) + int(image[i,j,2]))/3)
新矩阵具有相同的高度和宽度,但只有1个通道。然后就可以按照上一节中的方法进行特征提取,累加像素值获得一维数组:
features = np.reshape(feature_matrix, (660*450))
features.shape
(297000,)
特征提取方法3:提取边缘特征
观察下面的图像,然后识别图像中的对象:

你可以马上分辨出物体,狗,汽车和猫。在分辨每个物体时你考虑了哪些特征?形状可能是一个重要因素,其次是颜色或大小。计算机可以像我们一样识别形状吗?
类似的想法是将边缘提取为特征作为模型的输入。我们是怎样识别图像的边缘的?边缘一般是颜色急剧变化的地方。如下图:

这里突出了两条边。我们之所以识别出边缘,是因为颜色从白色变为了棕色(右图),棕色变为了黑色(左侧)。正如我们所知,图像是以数字的形式表示,因此可以寻找像素值发生剧烈变化的地方。
假设图像有以下矩阵:

为了识别某个像素是否是边缘,我们可以简单地减去像素相邻的值。对于这个例子,考虑值85,找到值89和78之间的差异,这个差异不是很大,可以认为该像素周围没有边缘。
现在考虑像素125:

由于该像素两侧的值之间的差异很大,因此可以得出结论,在该像素处存在显着的转变,所以它应该是边缘的一部分。
有各种卷积核可以提取图像的边缘。上面的方法可以使用Prewitt核(x轴方向)实现。下面是Prewitt核:

首先获取该像素周围的值,和卷积核(Prewitt核)相乘,获得最终值。由于一列是-1而另一列是1,因此这些值相当于获取差异。

还有其他类型的卷积核,下面是四种最常用的:

接下来使用代码提取图像的边缘特征:
#导入包
import numpy as np
from skimage.io import imread, imshow
from skimage.filters import prewitt_h,prewitt_v
import matplotlib.pyplot as plt
%matplotlib inline
#读取图像
image = imread('puppy.jpeg',as_gray=True)
#使用prewitt提取水平边缘
edges_prewitt_horizontal = prewitt_h(image)
#使用prewitt提取垂直边缘
edges_prewitt_vertical = prewitt_v(image)
imshow(edges_prewitt_vertical, cmap='gray')

网友评论