美文网首页
一个实时的人脸检测系统——Part2

一个实时的人脸检测系统——Part2

作者: Old_Artist | 来源:发表于2017-06-23 02:02 被阅读0次

    上一章节我们得到了一张人脸五个关键点——左眼中心,右眼中心,鼻子尖端,左嘴中心,右嘴中心。
    这一章节用python来实现下人脸的重构工作。
    我们先定义一个二维数组 landmark,它的五个元素分别是:
    左眼(landmark[0][0], landmark[0][1])
    右眼(landmark[1][0], landmark[0][1])
    鼻子(landmark[2][0], landmark[2][1])
    左嘴(landmark[3][0], landmark[3][1])
    右嘴(landmark[4][0], landmark[4][1])
    再定义两个函数:

    def imrotate(img, angle):
    imgh = img.shape[0]
    imgw = img.shape[1]
    center = (imgw/2.0, imgh/2.0)
    rot = cv2.getRotationMatrix2D(center, angle, 1.0)
    newh = imgh*math.cos(angle/180.0*math.pi) + imgw*abs(math.sin(angle/180.0*math.pi))
    neww = imgw*math.cos(angle/180.0*math.pi) + imgh*abs(math.sin(angle/180.0*math.pi))
    rot[0][2] += (neww/2.0 - center[0])
    rot[1][2] += (newh/2.0 - center[1])
    img_rot = cv2.warpAffine(img, rot, ((int)(neww),(int)(newh)))
    return img_rot
    

    rot = cv2.getRotationMatrix2D(center, angle, 1.0)的作用是取得图像绕图像的中心逆时针旋转angle角度并且缩放比列为1.0时的旋转矩阵。至于什么是旋转矩阵大家可以看看www.myexception.cn/image/1958561.html
    得到的旋转矩阵rot是一个2*3的矩阵。newh 和 neww表示的是旋转后新生成的图片的高和宽。
    rot[0][2] += (neww/2.0 - center[0])
    rot[1][2] += (newh/2.0 - center[1])
    这是一个平移的过程,所以整个过程将会是图像先绕着中心旋转angle角,然后我们通过计算得到新图像的高和宽。为了使原来的图像的中心和原图像的中心重合,我们又做了一次平移的操作。

    def transform(x, y,angle, src_shape, dst_shape):
    x0 = x - src_shape[1]/2.0
    y0 = y - src_shape[0]/2.0
    xx = x0*math.cos(angle) - y0*math.sin(angle) + dst_shape[1]/2.0
    xx = round(xx)
    yy = x0*math.sin(angle) + y0*math.cos(angle) + dst_shape[0]/2.0
    yy = round(yy)
    return (xx, yy)
    

    transform的操作其实和imrotate中的图片中心的变化过程是一样的。transform是使用getRotationMatrix2D得到了旋转矩阵再平移,imrotate则是自己构建了整个过程。
    输入(x,y)为原始的输入点,(xx,yy)为旋转后的点。
    有了这两个函数,我们就可以进行重构了。

    #获取左眼和右眼的正切值ang_tan和夹角angle
    ang_tan = (landmark[0][1]-landmark[1][1])/(landmark[0][0]-landmark[1][0])
    angle = math.atan(ang_tan) / math.pi * 180.0  
    #根据角度旋转照片,并计算旋转后眼睛和嘴巴的中点。
    img_rot = imrotate(img, angle)
    x = (landmark[0][0]+landmark[1][0]) / 2
    y = (landmark[0][1]+landmark[1][1]) / 2
    angle = - angle / 180.0 * math.pi
    eyec = transform(x, y, angle, img.shape, img_rot.shape)
    x = (landmark[3][0]+landmark[4][0]) / 2
    y = (landmark[3][1]+landmark[4][1]) / 2
    mouthc = transform(x, y, angle, img.shape, img_rot.shape)
    
    resize_scale = ec_mc_y / (mouthc[1]-eyec[1])
    resize_shape = [img_rot.shape[0],img_rot.shape[1]]
    resize_shape[0] = max(size, math.ceil(resize_shape[0] * resize_scale))
    resize_shape[1] = max(size, math.ceil(resize_shape[1] * resize_scale))
    resize_shape = ((int)(resize_shape[1]),(int)(resize_shape[0]))
    

    ec_mc_y是我们手动设置的眼睛和嘴巴之间的垂直距离,设置的依据是最后图片输出时的size大小,而下面出现的ec_y则是眼睛中点的y轴坐标,这也是通过size来调整的。通过计算ec_mc_y和旋转后图片的垂直距离的比值,可以得到一个缩放比例resize_scale,如果缩放后的图片大小为:resize_shape[0] *resize_scale,resize_shape[1] * resize_scale,如果此时二者中任一个小于size,都将把它替换成size,都大于就保持不变。

    img_resize = cv2.resize(img_rot, resize_shape)
    eyec2 = [(eyec[0]-(img_rot.shape[1]/2.0))*resize_scale + (img_resize.shape[1]/2.0),
    (eyec[1]-(img_rot.shape[0]/2.0))*resize_scale + (img_resize.shape[0]/2.0)]
    eyec2 = ((int)(round(eyec2[0])), (int)(round(eyec2[1])))
    img_crop = np.zeros((size, size, img_rot.shape[2]))
    crop_y = eyec2[1] - ec_y  #计算此时眼睛中点和设置中点差值
    crop_y_end = crop_y + size - 1 #计算裁剪窗口的移动距离。
    crop_y = min(img_resize.shape[0],max(1, crop_y))
    crop_y_end = min(img_resize.shape[0],max(1, crop_y_end))
    crop_x = eyec2[0] - (int)(math.floor(size/2.0))
    crop_x_end = crop_x + size - 1
    crop_x = min(img_resize.shape[1],max(1, crop_x))
    crop_x_end = min(img_resize.shape[1],max(1, crop_x_end))
    

    用计算得到的resize_shape把对图像进行缩放,cv2.resize的功能是对图像进行缩放。接着我们需要重新计算缩放后图像眼睛的中点。先把eyec平移到原点,之后进行缩放,然后再平移。接下来需要计算裁剪的范围,计算eyec的y值和ec_y的差值,来计算y轴的裁剪范围,通过计算eyec的x值和图片中点的差值,来计算x轴的裁剪范围。定义一个img_crop为了接收最后裁剪得到的图像。之后我们计算裁剪的范围 x方向为 crop_x ~ crop_x_end y方向为 crop_y ~ crop_y_end

    box = np.array([crop_x, crop_x_end, crop_y, crop_y_end])
    img_crop[(box[2]-crop_y+1):(box[3]-crop_y+1), (box[0]-crop_x+1):(box[1]-crop_x+1), :] = img_resize[box[2]:box[3],box[0]:box[1],:]
    cropped = img_crop/255.0
    img_final = cv2.resize(cropped, (size, size))
    img_final = np.uint8(img_final*255.0)
    

    img_resize中的 crop_y ~ crop_y_end , crop_x ~ crop_x_end区域复制到 img_crop中的 1~crop_y_end - crop_y+1 1~crop_x_end - crop_x + 1的区域
    cropped = img_crop/255.0是将像素做归一化,得到的cropped做最后一次缩放得到img_final,img_final*255.0为恢复原来的像素值,得到的img_final为最终的调整结果。

    相关文章

      网友评论

          本文标题: 一个实时的人脸检测系统——Part2

          本文链接:https://www.haomeiwen.com/subject/sxmqcxtx.html