计算机视觉是一门研究如何使机器“看”的科学,让计算机学会处理和理解图像。这门学问有时需要借助机器学习。本文介绍一些机器学习在计算机视觉领域应用的基础技术。
通过像素值提取特征
数字图像通常是一张光栅图或像素图,将颜色映射到网格坐标里。一张图片可以看成是一个每个元素都是颜色值的矩阵。表示图像基本特征就是将矩阵每行连起来变成一个行向量。光学文字识别(Optical character recognition,OCR)是机器学习的经典问题。下面我们用这个技术来识别手写数字。
scikit-learn的digits数字集包括至少1700种0-9的手写数字图像。每个图像都有8x8像像素构成。每个像素的值是0-16,白色是0,黑色是16。如下图所示:
%matplotlib inline
from sklearn import datasets
import matplotlib.pyplot as plt
digits = datasets.load_digits()
print('Digit:', digits.target[0])
print(digits.images[0])
plt.figure()
plt.axis('off')
plt.imshow(digits.images[0], cmap=plt.cm.gray_r, interpolation='nearest')
plt.show()
Digit: 0
[[ 0. 0. 5. 13. 9. 1. 0. 0.]
[ 0. 0. 13. 15. 10. 15. 5. 0.]
[ 0. 3. 15. 2. 0. 11. 8. 0.]
[ 0. 4. 12. 0. 0. 8. 8. 0.]
[ 0. 5. 8. 0. 0. 9. 8. 0.]
[ 0. 4. 11. 0. 1. 12. 7. 0.]
[ 0. 2. 14. 5. 10. 12. 0. 0.]
[ 0. 0. 6. 13. 10. 0. 0. 0.]]
我们将8x8矩阵转换成64维向量来创建一个特征向量:
digits = datasets.load_digits()
print('Feature vector:\n', digits.images[0].reshape(-1, 64))
Feature vector:
[[ 0. 0. 5. 13. 9. 1. 0. 0. 0. 0. 13. 15. 10. 15.
5. 0. 0. 3. 15. 2. 0. 11. 8. 0. 0. 4. 12. 0.
0. 8. 8. 0. 0. 5. 8. 0. 0. 9. 8. 0. 0. 4.
11. 0. 1. 12. 7. 0. 0. 2. 14. 5. 10. 12. 0. 0.
0. 0. 6. 13. 10. 0. 0. 0.]]
这样表示可以有效的处理一些基本任务,比如识别手写字母等。但是,记录每个像素的数值在大图像处理时不太好用。一个100x100像素的图像其灰度图产生的特征向量是10000维度,而1920x1080像素的图像是2073600。和TF-IDF特征向量不同,大部分图像都不是稀疏的。这种表示法的缺点不只是特征向量的维度灾难,还有就是某个位置的学习结果在经过对图像的放缩,旋转或变换之后可能就不对了,非常敏感,缺乏稳定性。另外,这种方法对图像的亮度也十分敏感。所以这种方法在处理照片和其他自然景色图像时不怎么有用。现代计算机视觉应用通常手工实现特征提取,或者用深度学习自动化解决无监督问题。后面我们会详细介绍。
对感兴趣的点进行特征提取
前面创建的特征矢量包含了图像的每个像素,既包含了图像特征的有用信息,也包含了一堆噪声。查看图像后,我们会发现所有的图像都有一个白边,这些像素是没用的。人们不需要观察物体的每个属性就可以很快的识别出很多物体。我们可以根据轮廓识别出汽车,并不需要观察后视镜,我们也可以通过一个鼻子或嘴巴判断图像是一个人。这些直觉就可以用来建立一种表示图像大多数信息属性的方法。这些有信息量的属性,称为兴趣点(points of interest),是由丰富的纹理包围,基本可以重建图像。边缘(edges)和角点(corners)是两种常用的兴趣点类型。边是像素快速变化的分界线(boundary),角是两条边的交集。我们用scikit-image库抽取下图的兴趣点:
%matplotlib inline
import numpy as np
from skimage.feature import corner_harris, corner_peaks
from skimage.color import rgb2gray
import matplotlib.pyplot as plt
import skimage.io as io
from skimage.exposure import equalize_hist
def show_corners(corners, image):
fig = plt.figure()
plt.gray()
plt.imshow(image)
y_corner, x_corner = zip(*corners)
plt.plot(x_corner, y_corner, 'or')
plt.xlim(0, image.shape[1])
plt.ylim(image.shape[0], 0)
fig.set_size_inches(np.array(fig.get_size_inches()) * 1.5)
plt.show()
mandrill = io.imread('mlslpic/3.1 mandrill.png')
mandrill = equalize_hist(rgb2gray(mandrill))
corners = corner_peaks(corner_harris(mandrill), min_distance=2)
show_corners(corners, mandrill)
上图就是兴趣点的提取结果。图片的230400个像素中,466个兴趣点被提取。这种提取方式更紧凑,而且当图片的亮度发生统一变化时,这些兴趣点依然存在。
SIFT和SURF
尺度不变特征转换(Scale-Invariant Feature Transform,SIFT)是一种特征提取方法,相比前面使用的方法,SIFT对图像的尺寸,旋转,亮度变化更不敏感。每个SIFT特征都是一个描述图片上某个区域边缘和角点的向量。和兴趣点不同,SIFT还可以获取每个兴趣点和它周围点的综合信息。加速稳健特征(Speeded-Up Robust Features,SURF)是另一个抽取图像兴趣点的方法,其特征向量对图像的尺寸,旋转,亮度变化是不变的。SURF的算法可以比SIFT更快,更有效的识别出兴趣点。
两种方法的具体理论解释在数字图像处理类的教材中都有介绍,感兴趣的同学可以研究。这样用mahotas库来应用SURF方法处理下面的图片。
和兴趣点抽取类似,抽取SURF只是机器学习中创建特征向量的第一步。训练集的每个实例都会抽取不同的SURF。第六章的,K-Means聚类,我们会介绍聚类方法抽取SURF来学习特征,可以作为一种图像分类方法。mahotas代码如下:
import mahotas as mh
from mahotas.features import surf
image = mh.imread('mlslpic/3.2 xiaobao.png', as_grey=True)
print('第一个SURF描述符:\n{}\n'.format(surf.surf(image)[0]))
print('抽取了%s个SURF描述符' % len(surf.surf(image)))
第一个SURF描述符:
[ 1.15299134e+02 2.56185453e+02 3.51230841e+00 3.32786485e+02
1.00000000e+00 1.75644866e+00 -2.94268692e-03 3.30736379e-03
2.94268692e-03 3.30736379e-03 -2.58778609e-02 3.25587066e-02
2.58778609e-02 3.25587066e-02 -3.03768176e-02 4.18212640e-02
3.03768176e-02 4.18212640e-02 -5.75169209e-03 7.66422266e-03
5.75169209e-03 7.66422266e-03 -1.85200481e-02 3.10523761e-02
1.85200481e-02 3.10523761e-02 -9.61023554e-02 2.59842816e-01
1.12794174e-01 2.59842816e-01 -6.66368114e-02 2.72006376e-01
1.40583321e-01 2.72006376e-01 -1.91014197e-02 5.28250599e-02
2.03376276e-02 5.28250599e-02 -2.24247135e-02 3.35105185e-02
2.24247135e-02 3.35105185e-02 -2.36547964e-01 3.18867366e-01
2.36547964e-01 3.18867366e-01 -2.49737941e-01 3.00644512e-01
2.50125503e-01 3.03596724e-01 -1.69936886e-02 3.82398567e-02
2.00617910e-02 3.82398567e-02 -3.72417955e-03 5.53246035e-03
3.72417955e-03 5.53246035e-03 -2.99748321e-02 4.76884368e-02
2.99748321e-02 4.76884368e-02 -5.12157923e-02 7.42619311e-02
5.12284796e-02 7.42619311e-02 -1.02035696e-02 1.19729640e-02
1.02035696e-02 1.19729640e-02]
抽取了588个SURF描述符
数据标准化
许多评估方法在处理标准化数据集时可以获得更好的效果。标准化数据均值为0,单位方差(Unit Variance)。均值为0的解释变量是关于原点对称的,特征向量的单位方差表示其特征值全身统一单位,统一量级的数据。例如,假设特征向量由两个解释变量构成,第一个变量值范围[0,1],第二个变量值范围[0,1000000],这时就要把第二个变量的值调整为[0,1],这样才能保证数据是单位方差。如果变量特征值的量级比其他特征值的方差还大,这个特征值就会主导学习算法的方向,导致其他变量的影响被忽略。有些机器学习算法会在数据不标准时引入很小的优化参数值。解释变量的值可以通过正态分布进行标准化,减去均值后除以标准差。scikit-learn的scale函数可以实现:
from sklearn import preprocessing
import numpy as np
X = np.array([
[0., 0., 5., 13., 9., 1.],
[0., 0., 13., 15., 10., 15.],
[0., 3., 15., 2., 0., 11.]
])
print(preprocessing.scale(X))
[[ 0. -0.70710678 -1.38873015 0.52489066 0.59299945 -1.35873244]
[ 0. -0.70710678 0.46291005 0.87481777 0.81537425 1.01904933]
[ 0. 1.41421356 0.9258201 -1.39970842 -1.4083737 0.33968311]]
来源:CSDN
作者:网络一线牵 珍惜这份缘
链接:https://blog.csdn.net/weixin_43838785/article/details/104055780