人脸识别之前通常需要做校准工作,使得标准人脸和待识别人脸均位于"统一规范化"的条件下做比对;这里校准工作用的是相似变换SimilarityTransform【注:与仿射变换不同】,即:等距变换+均匀尺度缩放,而等距变换则是平移+旋转变换。
对应的变换矩阵:
目前大部分的做法是:采用python库中的skimage.transform模块生成变换矩阵,再利用opencv中的仿射变换函数cv2.warpAffine,将img生成"标准人脸"dst;过程如下:
from skimage import transform as trans
import numpy as np
import cv2
src = np.array([
[38.2946, 51.6963],
[73.5318, 51.5014],
[56.0252, 71.7366],
[41.5493, 92.3655],
[70.7299, 92.2041] ], dtype=np.float32)
dst = np.array([
[30, 50],
[72, 51],
[56, 72],
[41, 92],
[71, 92] ], dtype=np.float32)
tform = trans.SimilarityTransform()
res =tform.estimate(dst, src)
M = tform.params
dst = cv2.warpAffine(img, M, (img_im.shape[1], img_im.shape[0]))
最近在工程化过程中,需要把opencv库移植到硬件上,但由于生成的相似矩阵是调用skimage库生成的,所以工程需要移植两个库,比较麻烦。现在需求是直接用opencv库生成相似矩阵,这样就只需一个库就行了。
网上查看了不少资料,发现cv2中求变换矩阵的函数太多了,最终发现了对应的相似变换函数:
python2中的opencv库对应的生成相似矩阵函数是cv2.estimateRigidTransform,但该函数只能输入3个点用于生成相似矩阵,而且鲁棒性差,误差值大的点,容易生成失败。猜想主要是这个原因导致大家一直都用skimage库,而不用opencv库。
python3中opencv库对应的函数是estimateAffinePartial2D,但该函数直接使用有坑。需要指定迭代的方法,否则采用默认的cv2.RANSAC方法只会用到两组对应点用于迭代,估计的得到的结果与skimage库几乎完全不一致,仔细看了estimateAffinePartial2D介绍,并尝试发现,设定cv2.LMEND为评估方法,则结果和skimage库几乎完全一致,(小数点后好好好好好几位都一致).具体使用
M_cv=cv2.estimateAffinePartial2D(dst,src,method=cv2.LMEND)
M=M[0]
另外,附一个网友提供的c++版本,用opencv库直接搭出skimage.SimilarityTransform的实现:skimage-SimilarityTransform的C++实现
验证可用。