SphereFace 是今年CVPR的一篇论文, 理论直观优美, 作者的代码和调参功力也足够深厚. 已经有部分人用项目中release的20层模型在Megaface-challenge-1中刷到了70%以上的准确率. 例如Normface作者.
但目前看到的代码都是基于matlab的, 对python党来说不够友好. 下面说一下如何用纯python复现.
其中最关键的一步是如何用python做人脸对齐. 参照这里的方法, 对齐大概分以下几步:用MTCNN检测图片的人脸区域和关键点(5个,眼睛*2,鼻子,嘴角*2)
如果有多个人脸区域, 计算这些人脸区域与数据源标定区域的IoU, 取最大的.
如果未检测到任何人脸区域, 两种方案:对标定区域降低阈值强制检测人脸.
直接对图片取center crop.
MTCNN检测用Matlab或者python版本问题都不大. 重点是检测到关键点后如何对齐?
对齐在matlab中对应的函数是cp2tform和imtransform. cp2tform获取两组坐标之间的2D变换参数. imtransform利用参数转换图像并切割到固定大小.
先看一下例子, 以下是原图(取自facescrub, image_id:14680):
用MTCNN+matlab cp2tform+ imtransform对齐后:
可以看到效果不错.
然后我们试几个python实现,
1. 全仿射变换:
src = np.array([
[30.2946, 51.6963],
[65.5318, 51.5014],
[48.0252, 71.7366],
[33.5493, 92.3655],
[62.7299, 92.2041] ], dtype=np.float32 )
dst = mtcnn_landmark.astype(np.float32)
M = cv2.estimateRigidTransform( dst.reshape(1,5,2), src.reshape(1,5,2), True)
warped = cv2.warpAffine(img,M,(shape[1],shape[0]), borderValue = 0.0)
效果如下,有点失真:
2. 再来带约束的仿射变换:
M = cv2.estimateRigidTransform( dst.reshape(1,5,2), src.reshape(1,5,2), False)
warped = cv2.warpAffine(img,M,(shape[1],shape[0]), borderValue = 0.0)
效果如下,好一些, 也能用了, 但是和matlab的版本还是不一样(旋转角度有区别). 因为作者提供的模型是用matlab的对齐算法训练的, 所以我们必须和他保持一致.
3.继续, 相似变换, 用skimage的similarity transform:
from skimage import transform as trans
tform = trans.SimilarityTransform()
tform.estimate(dst, src)
M = tform.params[0:2,:]
warped = cv2.warpAffine(img,M,(shape[1],shape[0]), borderValue = 0.0)
效果, 基本和matlab一致, 除了缩放比例有一些细微的差别, 但应该不影响测试了.
对齐后的测试方法就比较简单了, 用对齐后的人脸及其翻转镜像送入caffe模型得到向量相加, 并归一化做为特征.
测试结果(Megaface challenge-1 Top-1 Accuracy):全仿射变换: 44%.
带约束的仿射变换: 47%.
skimage similarity transform: 69.5%.
检测及对齐部分还有提高空间.
ps: 如果训练时就用第一(?)或者第二种对齐方法的话, 可能最终准确率差不了多少.
下一步就是自己训练模型了.