正在阅读一本机器学习书,并了解到边缘是机器的重要特征输入,用于了解图片中是否有物体,在这种情况下是面部。看看左边只有边缘的图,可以很容易地说出它是人眼所面孔的,不是吗?这有助于机器以同样的方式。
最初认为寻找边缘本身需要一些“人工智能”。但是记得Python PIL库有find_edges过滤器,它肯定不是机器学习功能。然后开始考虑如何找到边缘并最终找到一种非常简单的方法,只需要从头开始构建大约20行Python代码。
逻辑
逻辑非常简单如下。
履行
用Python代码实现了这个,但算法本身与语言无关。
以下是需要的库:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import math
如果是Python 新手,请先安装Python3,然后使用pip安装所需的库。
pip install -U Pillow numpy matplotlib
首先,将图像读取为2D像素阵列。每个像素是3个值的数组[红色,绿色,蓝色],并且每个颜色值是0到255,例如像素值[0,0,0]是黑色。
filename = 'old.jpg'
im = Image.open(filename)
im_array = np.asarray(im)
如果图像太大,可以先调整图像大小。
n = 2 # resize times
im = im.resize( (int(im.size[0]/n), int(im.size[1]/n)) )
其次,定义了一个函数来测量两个像素之间的差异。使用像素值之间的平方差之和的平方根。
# square root difference between two pixels.
def sqrt_diff(a,b):
return math.sqrt( sum((int(a[i])-int(b[i]))**2 for i in range(3)) /3 )
例如,黑色像素A为[0,0,0],白色像素B为[255,255,255],因此A和B之间的平方根差异为:
sqrt(([255–0]**2 + [255–0]**2 + [255–0]**2)/3) = sqrt(255**2) = 255
注意:x ** 2表示x * x。
这里有一个技巧。需要首先将像素值转换为int类型,即int(a[i])减法,因为像素值是ubyte [0-255],减法可能会变为负值并导致类型溢出问题。
在平方根之前将和除以3,因此理解像素差异更直观。它变得像三个颜色值的平均差异。
然后从上到下,从左到右迭代图像阵列。如果像素与其右侧或底部相邻像素之间的平方根差异大于预定义阈值,请将其标记为边缘像素并将其设置为黑色[0,0,0],否则将其设置为白色[255,255,255] ]为背景。
diff_threshold = 10
new_array = np.copy(im_array)
for row in range(im_array.shape[0]-1):
for col in range(im_array.shape[1]-1):
# change an edge pixel to black if it is much different from neighbours (right and below)
# otherwise change it to white as background
if ( sqrt_diff(im_array[row,col],im_array[row,col+1]) > diff_threshold
or sqrt_diff(im_array[row,col],im_array[row+1,col]) > diff_threshold):
new_array[row,col] = [0,0,0] # black
else:
new_array[row,col] = [255,255,255] # white
可以diff_threshold为图像微调阈值。10是我用来创建上面图像的值。增加更少边缘的阈值。例如,通过将其增加到20,得到了如下的新图像。
最后,使用matplotlib将新的边缘图像保存到本地。
plt.imshow(new_array)
plt.savefig('new.jpg')
如果要在弹出窗口中显示新图像,请改用以下代码。
plt.imshow(new_array)
plt.show()
可以在此处找到合并的完整代码。
https://gist.github.com/peterjpxie/01595d4beb04e39ed97e6937d4424e7f
笔记
请注意,此算法并非特定于面部检测。它可以找到所有图像的边缘。亲自尝试一下。