3D人脸旋转

 

sinx/x

https://blog.csdn.net/jacke121/article/details/79846442

这个也能旋转:

https://github.com/Hangz-nju-cuhk/Rotate-and-Render

 

3D人脸旋转

吴尚哲的 CVPR 最佳论文:无需任何监督,即可重建三维图像

 

Unsupervised Learning of Probably Symmetric Deformable 3D Objects from Images in the Wild.

对称可变形三维物体的无监督学习

 

论文链接:https://arxiv.org/abs/1911.11130

代码地址:https://github.com/elliottwu/unsup3d

项目地址:https://elliottwu.com/projects/unsup3d/

Demo 地址:http://www.robots.ox.ac.uk/~vgg/blog/unsupervised-learning-of-probably-symmetric-deformable-3d-objects-from-images-in-the-wild.html

 

 

https://blog.csdn.net/zb1165048017/article/details/104204035

博客源码

链接: https://pan.baidu.com/s/18z2b6Sut6qFecOpGqNc8YA

提取码: ad77

 

https://blog.csdn.net/muyouhang/article/details/103649301

 

自动化所作品, 解决极端姿态下(如侧脸),一些特征点变了不可见,不同姿态下的人脸表观也存在巨大差异使得关键点定位困难等问题,本文提出一种基于3D人脸形状的定位方法3DDFA,算法框架为:
(1) 输入为100x100的RGB图像和PNCC (Projected Normalized Coordinate Code) 特征,PNCC特征的计算与当前形状相关,可以反映当前形状的信息;算法的输出为3D人脸形状模型参数
(2) 使用卷积神经网络拟合从输入到输出的映射函数,网络包含4个卷积层,3个pooling层和2个全连接层
通过级联多个卷积神经网络直至在训练集上收敛,PNCC特征会根据当前预测的人脸形状更新,并作为下一级卷积神经网络的输入。
(3) 此外,卷积神经网络的损失函数也做了精心的设计,通过引入权重,让网络优先拟合重要的形状参数,如尺度、旋转和平移;当人脸形状接近ground truth时,再考虑拟合其他形状参数
实验证明该损失函数可以提升定位模型的精度。由于参数化形状模型会限制人脸形状变形的能力,作者在使用3DDFA拟合之后,抽取HOG特征作为输入,使用线性回归来进一步提升2D特征点的定位精度。

训练3DDFA模型,需要大量的多姿态人脸样本。为此,作者基于已有的数据集如300W,利用3D信息虚拟生成不同姿态下的人脸图像,核心思想为:先预测人脸图像的深度信息,通过3D旋转来生成不同姿态下的人脸图像
链接(含源码)

 

http://www.greenxf.com/soft/285868.html

执行比较慢

import numpy as np
import os
from skimage.transform import estimate_transform, warp
import cv2
from predictor import PosPrediction


## 预检测人脸框或者关键点,目的是裁剪人脸
cas = cv2.CascadeClassifier('./Data/cv-data/haarcascade_frontalface_alt2.xml')

img = cv2.imread('./images/zly.jpg')
img = cv2.imread('./images/000001.jpg')
img_gray= cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
faces = cas.detectMultiScale(img_gray,2,3,0,(30,30))
bbox = np.array([faces[0,0],faces[0,1],faces[0,0]+faces[0,2],faces[0,1]+faces[0,3]])


left = bbox[0]; top = bbox[1]; right = bbox[2]; bottom = bbox[3]
old_size = (right - left + bottom - top)/2
center = np.array([right - (right - left) / 2.0, bottom - (bottom - top) / 2.0])
size = int(old_size*1.6)


src_pts = np.array([[center[0]-size/2, center[1]-size/2],
                    [center[0] - size/2, center[1]+size/2],
                    [center[0]+size/2, center[1]-size/2]])
DST_PTS = np.array([[0,0], [0,255], [255, 0]])
tform = estimate_transform('similarity', src_pts, DST_PTS)

img = img/255.
cropped_img = warp(img, tform.inverse, output_shape=(256, 256))


pos_predictor = PosPrediction(256, 256)
pos_predictor.restore('./Data/net-data/256_256_resfcn256_weight')

cropped_pos = pos_predictor.predict(cropped_img) #网络推断

#将裁剪图的结果重新调整
cropped_vertices = np.reshape(cropped_pos, [-1, 3]).T
z = cropped_vertices[2,:].copy()/tform.params[0,0]
cropped_vertices[2,:] = 1
vertices = np.dot(np.linalg.inv(tform.params), cropped_vertices)
vertices = np.vstack((vertices[:2,:], z))
pos = np.reshape(vertices.T, [256, 256, 3])

## 人脸关键点

def draw_kps(img,kps,point_size=2):
    img = np.array(img*255,np.uint8)
    for i in range(kps.shape[0]):
        cv2.circle(img,(int(kps[i,0]),int(kps[i,1])),point_size,(0,255,0),-1)
    return img

uv_kpt_ind = np.loadtxt('./Data/uv-data/uv_kpt_ind.txt').astype(np.int32)
face_kps = pos[uv_kpt_ind[1,:],uv_kpt_ind[0,:],:]

cv2.imshow('aaaa3',draw_kps(img.copy(),face_kps))
cv2.waitKey(1)


face_ind = np.loadtxt('./Data/uv-data/face_ind.txt').astype(np.int32)
all_vertices = np.reshape(pos, [256*256, -1])
vertices = all_vertices[face_ind, :]


cv2.imshow("xuan",draw_kps(img.copy(),vertices[:,:2],1))
cv2.waitKey(1)


texture = cv2.remap(img, pos[:,:,:2].astype(np.float32), None, interpolation=cv2.INTER_NEAREST, borderMode=cv2.BORDER_CONSTANT,borderValue=(0))

#找到每个三角形每个顶点的肤色
triangles = np.loadtxt('./Data/uv-data/triangles.txt').astype(np.int32)
all_colors = np.reshape(texture, [256*256, -1])
colors = all_colors[face_ind, :]

print(vertices.shape) # texutre每个像素对应的3D坐标
print(triangles.shape) #每个三角网格对应的像素索引
print(colors.shape) #每个三角形的颜色


#获取三角形每个顶点的depth,平均值作为三角形高度
tri_depth = (vertices[triangles[:,0],2 ] + vertices[triangles[:,1],2] + vertices[triangles[:,2],2])/3.
#获取三角形每个顶点的color,平均值作为三角形颜色
tri_tex = (colors[triangles[:,0] ,:] + colors[triangles[:,1],:] + colors[triangles[:,2],:])/3.
tri_tex = tri_tex*255

img_3D = np.zeros_like(img,dtype=np.uint8)
for i in range(triangles.shape[0]):
    cnt = np.array([(vertices[triangles[i,0],0],vertices[triangles[i,0],1]),
           (vertices[triangles[i,1],0],vertices[triangles[i,1],1]),
           (vertices[triangles[i,2],0],vertices[triangles[i,2],1])],dtype=np.int32)
    img_3D = cv2.drawContours(img_3D,[cnt],0,tri_tex[i],-1)

cv2.imshow("aaa1",img_3D/255.0)
cv2.waitKey(1)

# 找到旋转矩阵,参考https://github.com/YadiraF/face3d
def angle2matrix(angles):
    x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2])
    # x
    Rx=np.array([[1,              0,                0],
                 [0, np.math.cos(x),  -np.math.sin(x)],
                 [0, np.math.sin(x),   np.math.cos(x)]])
    # y
    Ry=np.array([[ np.math.cos(y), 0, np.math.sin(y)],
                 [0, 1,              0],
                 [-np.math.sin(y), 0, np.math.cos(y)]])
    # z
    Rz=np.array([[np.math.cos(z), -np.math.sin(z), 0],
                 [np.math.sin(z),  np.math.cos(z), 0],
                 [0,               0, 1]])

    R=Rz.dot(Ry.dot(Rx))
    return R.astype(np.float32)

trans_mat = angle2matrix((0,15,0))

# 旋转坐标
rotated_vertices = vertices.dot(trans_mat.T)
# 把图像拉到画布上
ori_x = np.min(vertices[:,0])
ori_y = np.min(vertices[:,1])
rot_x = np.min(rotated_vertices[:,0])
rot_y = np.min(rotated_vertices[:,1])
shift_x = ori_x-rot_x
shift_y = ori_y-rot_y
rotated_vertices[:,0]=rotated_vertices[:,0]+shift_x
rotated_vertices[:,1]=rotated_vertices[:,1]+shift_y


img_3D = np.zeros_like(img,dtype=np.uint8)
mask = np.zeros_like(img,dtype=np.uint8)
fill_area=0
for i in range(triangles.shape[0]):
    cnt = np.array([(rotated_vertices[triangles[i,0],0],rotated_vertices[triangles[i,0],1]),
           (rotated_vertices[triangles[i,1],0],rotated_vertices[triangles[i,1],1]),
           (rotated_vertices[triangles[i,2],0],rotated_vertices[triangles[i,2],1])],dtype=np.int32)
    mask = cv2.drawContours(mask,[cnt],0,(255,255,255),-1)
    if(np.sum(mask[...,0])>fill_area):
        fill_area = np.sum(mask[...,0])
        img_3D = cv2.drawContours(img_3D,[cnt],0,tri_tex[i],-1)

cv2.imshow('xuanzhuan',img_3D)
cv2.waitKey()
# plt.imshow(img_3D)

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值