长话短说,相机标定过程,上次用了相机内参数,这次主要是用相机外参数(见图1)。即求出旋转矩阵的部分。所以现在有两个策略分开介绍。

图1:相机内外参数
dlib库的作用
这个库简单来说就是就是可以检测图片里人脸的特征点,一共有68个。具体的应用方法可以看官方的库(http://dlib.net/)

方法1. 先求相机内参数
这个方法大致说下,因为不方便。
先做计算相机内参数,我们假设你脸部的几个特征点相对位置,然后用相机标定的方法,做出完整求解,得到内参数,然后很自然的就知道相机外参数,旋转矩阵,求旋转矩阵在xyz方向的旋转,就是人脸的朝向或是人头部的姿态。
下面是个简单的方法:
方法2.图像的中心逼近光学中心
这里我们需要出入两个默认值:
1). 图片中,人脸部特征点的相对位置(像素点位置image_points),由dlib库计算。
2). 人脸部的六个默认尺寸。实际3D点的位置(以鼻子尖为零点model_points),单位是厘米,毫米,米都行。

图片来自[1],脸部六个特征点的相对位置
这两个参数的获取可以很简单。用相机正对着人脸,拍一张照片,在[1](其翻译版本看[2])里,他默认相机内参数是图片的宽度。就是要我们假设没有镜头畸变,一个特别特别省事的做法,通过图像的中心逼近光学中心(Approximate Focal Length for Webcams and Cell Phone Cameras 参考[3]),在[2]中也说明了,而且特别清楚。看下面代码:
im = cv2.imread("headPose.jpg"); # 图片“headPose.jpg”是拍好的图
size = im.shape # 图片的 [列,行,3(rgb层)]
focal_lengthc = size[0] # 竖直方向的有效焦距
focal_lengthr = size[1] # 水平方向的有效焦距
center = (size[1]/2, size[0]/2) # 中心的偏移量,因为像素索引是从左上角开始的
camera_matrix = np.array( # 相机的内参数
[[focal_lengthr, 0, center[0]],
[0, focal_lengthc, center[1]],
[0, 0, 1]], dtype = "double"
)
注意:我们不用刚体变换里的平移变换,因为上边我们设置世界坐标系原点是鼻子尖。所以只有旋转矩阵。
剩下就是数学计算了:

求出旋转矩阵
关于伪逆矩阵:

SVD方法
其实上边的计算可以用OpenCV的一个公式,直接得到结果。cv2.solvePnP()。
关于完整版的程序,可以仔细看[4]。
关于角度的计算昨天没写完(抱歉了),具体看下面两张图:

关于非固定轴旋转的三个旋转矩阵

浅蓝背景字意:对于固定轴旋转和非固定轴的旋转会产生相同的结果(左右乘的区别)
当我们求出旋转矩阵后,跟上边的矩阵比较,我们可以逆向求出三个旋转角,具体如下:

Atan2是求俯角的函数
求出三个角之后,对应旋转的每个角,
alpha ---- yaw
beta ---- pitch
gamma ---- roll

之后用OpenCv的一两个函数,就可以画出脸部朝向的线。在[4]里边有了说明。
到此,我用过的相机标定算法就结束。后边的可能会有关于机器人Pepper的东西,就是下边这个人工智障。很烦很烦的一个东西。

reference:
[1]. https://www.learnopencv.com/head-pose-estimation-using-opencv-and-dlib/
[2]. https://blog.csdn.net/u012525096/article/details/78348765
[3]. https://www.learnopencv.com/approximate-focal-length-for-webcams-and-cell-phone-cameras/
[4]. https://blog.csdn.net/yuanlulu/article/details/82763170