三维人脸(python):obj模型文件的常规操作

三维人脸(python):obj模型文件的常规操作

文章目录

  • 三维人脸(python):obj模型文件的常规操作
  • 前言
  • 一、OBJ格式模型结构介绍
  • 二、obj模型文件的基础操作
    • 1.读取obj
    • 2.保存obj
    • 3.模型预处理
      • 核心代码
      • 完整实例代码
    • 4.缩放操作
      • 核心代码
      • 完整实例代码
    • 5.平移操作
      • 核心代码
      • 完整实例代码
    • 6.旋转操作
      • 核心代码
      • 完整实例代码
    • 7.混合操作完整实例代码
  • 总结


前言

3D模型的格式种类繁多:常见的格式包括OBJ、STL、U3D等等,其中最简单当属OBJ文件。OBJ文件是Alias | Wavefront公司为它的一套基于工作站的3D建模和动画软件“AdvancedVisualizer”开发的一种标准3D模型文件格式,适合3D软件模型之间的互导。应用OBJ文件一般包括三个子文件,分别是.obj(模型文件)、.mtl(材料库文件)、.jpg(纹理文件)。该博文的重点是讲解obj模型文件的基础操作。


一、OBJ格式模型结构介绍

用txt打开obj文件,开头是一系列的特征标签,提示存储的是什么样的数据。了解常用的标签f,v,vt,vn的含义即可。

1.面(符号f)【f v/vt/vn v/vt/vn v/vt/vn】: 每个三角面片由三部分组成,每部分分别由顶点索引v 以及对应的纹理索引和法向量索引vn组成。
obj文件不包括纹理坐标和法向量:f v v v
obj文件有纹理坐标,没有法向量:f v/vt v/vt v/vt
obj文件没有纹理坐标,有法向量:f v//vn v//vn v//vn
三维人脸(python):obj模型文件的常规操作_第1张图片
2.顶点(符号v)【v x y z 】: 每个顶点的xyz三个坐标。
三维人脸(python):obj模型文件的常规操作_第2张图片

3.顶点纹理(符号vt)【vt u v w】: 每个顶点的纹理是取纹理图片上(u,v)坐标的像素值,w形容三维纹理。
三维人脸(python):obj模型文件的常规操作_第3张图片

4.顶点法向量(符号vn)【vn x y z】: 三角面片的朝向由构成顶点对应的法向量做矢量和决定,即三个法向量分别对xyz坐标相加再除以3。
三维人脸(python):obj模型文件的常规操作_第4张图片

总结:
顶点数、顶点法向量数和顶点纹理数三者数量一致,面数与其他数据无关,多个面可能公用一个顶点,面的颜色是由三个顶点的纹理插值计算而来。


二、obj模型文件的基础操作

1.读取obj

def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

2.保存obj

def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

3.模型预处理

任何平移、旋转、缩放及其混合操作前,通常根据模型中心先将模型位移到空间坐标系的正中心区域,即模型中心位应该与空间坐标系原点重合,具体做法就是将模型所有点xyz坐标与模型中心点xyz坐标对应相减,然后再将模型放回原位复原,即模型所有点xyz坐标与模型中心点xyz坐标对应相减。

核心代码

def get_Preprocessmatrix(centroid): 
	#centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix,form_origin_matrix

完整实例代码

import numpy as np
#加载模型
def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

#保存模型
def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

# 计算模型中心点xyz
def core_point(points):
    centroid = np.mean(points, axis=0)
    return centroid
# 预处理矩阵
def get_Preprocessmatrix(centroid):
    # centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix, form_origin_matrix

# 改变模型的空间位置
def transform_model(matrix, points):
    # 增加point矩阵维度
    ones_data = np.ones(points.shape[0])
    points = np.insert(points, 3, values=ones_data, axis=1)
    new_xyz_data = np.dot(matrix, points.T)
    points = new_xyz_data[:3].T
    return points

if __name__ == "__main__":
    readModelpath = r"faceModel/face-s.obj"
    save_model_to_origin_path = r"csdn/face-s-to-origin.obj"
    save_model_form_origin_path = r"csdn/face-s-form-origin.obj"

    obj_mesh = read_objPoint(readModelpath)
    # 获得所有点坐标
    points = np.array(obj_mesh["v"])
    # 获得所有店的法向量
    normalvector = np.array(obj_mesh["vn"])
    # 计算模型中心点xyz
    centroid = core_point(points)

    to_origin_matrix, form_origin_matrix = get_Preprocessmatrix(centroid)

    to_origin_points = transform_model(to_origin_matrix, points)
    to_origin_normalvector = transform_model(to_origin_matrix, normalvector)
    obj_mesh["v"] = to_origin_points.tolist()
    obj_mesh["vn"] = to_origin_normalvector.tolist()
    save_objpoint(save_model_to_origin_path, obj_mesh)

    form_origin_points = transform_model(form_origin_matrix, to_origin_points)
    form_origin_normalvector = transform_model(form_origin_matrix, to_origin_normalvector)
    obj_mesh["v"] = form_origin_points.tolist()
    obj_mesh["vn"] = form_origin_normalvector.tolist()
    save_objpoint(save_model_form_origin_path, obj_mesh)

红框是原始模型,绿框是位移到原点的模型:
三维人脸(python):obj模型文件的常规操作_第5张图片
绿框是位移到原点的模型,黑框是复原后的模型:
三维人脸(python):obj模型文件的常规操作_第6张图片

4.缩放操作

核心代码

def get_scalematrix(alpha): 
    # 缩放参数
    scale = 1/alpha
    # 缩放矩阵
    scale_matrix = np.array([
        [scale, 0, 0, 0],
        [0, scale, 0, 0],
        [0, 0, scale, 0],
        [0, 0, 0, 1]
    ])
    return scale_matrix

完整实例代码

import numpy as np
#加载模型
def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

#保存模型
def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

# 计算模型中心点xyz
def core_point(points):
    centroid = np.mean(points, axis=0)
    return centroid
# 预处理矩阵
def get_Preprocessmatrix(centroid):
    # centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix, form_origin_matrix

def get_scalematrix(alpha):
    # 缩放参数
    scale = 1/alpha
    # 缩放矩阵
    scale_matrix = np.array([
        [scale, 0, 0, 0],
        [0, scale, 0, 0],
        [0, 0, scale, 0],
        [0, 0, 0, 1]
    ])
    return scale_matrix

# 改变模型的空间位置
def transform_model(matrix, points):
    # 增加point矩阵维度
    ones_data = np.ones(points.shape[0])
    points = np.insert(points, 3, values=ones_data, axis=1)
    new_xyz_data = np.dot(matrix, points.T)
    points = new_xyz_data[:3].T
    return points

if __name__ == "__main__":
    readModelpath = r"faceModel/face-s.obj"
    save_model_path = r"csdn/face-s-scale.obj"

    # 缩放因子
    alpha = 10

    obj_mesh = read_objPoint(readModelpath)
    # 获得所有点坐标
    points = np.array(obj_mesh["v"])
    # 获得所有店的法向量
    normalvector = np.array(obj_mesh["vn"])
    # 计算模型中心点xyz
    centroid = core_point(points)

    to_origin_matrix, form_origin_matrix = get_Preprocessmatrix(centroid)
    scale_matrix = get_scalematrix(alpha)
    # 移到原点-->缩放-->复原
    change_matrix = form_origin_matrix.dot(scale_matrix).dot(to_origin_matrix)

    scale_points = transform_model(change_matrix, points)
    scale_normalvector = transform_model(change_matrix, normalvector)
    obj_mesh["v"] = scale_points.tolist()
    obj_mesh["vn"] = scale_normalvector.tolist()
    save_objpoint(save_model_path, obj_mesh)

三维人脸(python):obj模型文件的常规操作_第7张图片

5.平移操作

核心代码

def get_changematrix(x_tra, y_tra, z_tra):
    # 偏移参数
    x_translation = x_tra
    y_translation = y_tra
    z_translation = z_tra
    # 平移矩阵
    translation_matrix = np.array([
        [1, 0, 0, -x_translation],
        [0, 1, 0, -y_translation],
        [0, 0, 1, -z_translation],
        [0, 0, 0, 1]
    ])
    return translation_matrix

完整实例代码

import numpy as np
#加载模型
def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

#保存模型
def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

# 计算模型中心点xyz
def core_point(points):
    centroid = np.mean(points, axis=0)
    return centroid
# 预处理矩阵
def get_Preprocessmatrix(centroid):
    # centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix, form_origin_matrix

def get_translationmatrix(x_tra, y_tra, z_tra):
    # 偏移参数
    x_translation = x_tra
    y_translation = y_tra
    z_translation = z_tra
    # 平移矩阵
    translation_matrix = np.array([
        [1, 0, 0, -x_translation],
        [0, 1, 0, -y_translation],
        [0, 0, 1, -z_translation],
        [0, 0, 0, 1]
    ])
    return translation_matrix

# 改变模型的空间位置
def transform_model(matrix, points):
    # 增加point矩阵维度
    ones_data = np.ones(points.shape[0])
    points = np.insert(points, 3, values=ones_data, axis=1)
    new_xyz_data = np.dot(matrix, points.T)
    points = new_xyz_data[:3].T
    return points

if __name__ == "__main__":
    readModelpath = r"faceModel/face-s.obj"
    save_model_to_origin_path = r"csdn/face-s-translation.obj"
    x_tra, y_tra, z_tra =800,700,600

    obj_mesh = read_objPoint(readModelpath)
    # 获得所有点坐标
    points = np.array(obj_mesh["v"])
    # 获得所有店的法向量
    normalvector = np.array(obj_mesh["vn"])
    # 计算模型中心点xyz
    centroid = core_point(points)

    to_origin_matrix, form_origin_matrix = get_Preprocessmatrix(centroid)
    translation_matrix = get_translationmatrix(x_tra, y_tra, z_tra)
    # 移到原点-->平移-->复原
    change_matrix = form_origin_matrix.dot(translation_matrix).dot(to_origin_matrix)

    translation_points = transform_model(change_matrix, points)
    translation_normalvector = transform_model(change_matrix, normalvector)
    obj_mesh["v"] = translation_points.tolist()
    obj_mesh["vn"] = translation_normalvector.tolist()
    save_objpoint(save_model_to_origin_path, obj_mesh)

三维人脸(python):obj模型文件的常规操作_第8张图片

6.旋转操作

核心代码

def get_roatematrix(x_r, y_r, z_r):
    # 旋转参数
    x_roate = x_r
    y_roate = y_r
    z_roate = z_r
    # 旋转矩阵
    x_roate_matrix = np.array([
        [1, 0, 0, 0],
        [0, np.cos(x_roate), -np.sin(x_roate), 0],
        [0, np.sin(x_roate), np.cos(x_roate), 0],
        [0, 0, 0, 1]
    ])
    y_roate_matrix = np.array([
        [np.cos(y_roate), 0, np.sin(y_roate), 0],
        [0, 1, 0, 0],
        [-np.sin(y_roate), 0, np.cos(y_roate), 0],
        [0, 0, 0, 1]
    ])
    z_roate_matrix = np.array([
        [np.cos(z_roate), -np.sin(z_roate), 0, 0],
        [np.sin(z_roate), np.cos(z_roate), 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ])
    roate_matrix = z_roate_matrix.dot(y_roate_matrix).dot(x_roate_matrix)
    return roate_matrix

完整实例代码

import numpy as np
#加载模型
def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

#保存模型
def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

# 计算模型中心点xyz
def core_point(points):
    centroid = np.mean(points, axis=0)
    return centroid
# 预处理矩阵
def get_Preprocessmatrix(centroid):
    # centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix, form_origin_matrix

def get_roatematrix(x_r, y_r, z_r):
    # 旋转参数
    x_roate = x_r
    y_roate = y_r
    z_roate = z_r
    # 旋转矩阵
    x_roate_matrix = np.array([
        [1, 0, 0, 0],
        [0, np.cos(x_roate), -np.sin(x_roate), 0],
        [0, np.sin(x_roate), np.cos(x_roate), 0],
        [0, 0, 0, 1]
    ])
    y_roate_matrix = np.array([
        [np.cos(y_roate), 0, np.sin(y_roate), 0],
        [0, 1, 0, 0],
        [-np.sin(y_roate), 0, np.cos(y_roate), 0],
        [0, 0, 0, 1]
    ])
    z_roate_matrix = np.array([
        [np.cos(z_roate), -np.sin(z_roate), 0, 0],
        [np.sin(z_roate), np.cos(z_roate), 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ])
    roate_matrix = z_roate_matrix.dot(y_roate_matrix).dot(x_roate_matrix)
    return roate_matrix

# 改变模型的空间位置
def transform_model(matrix, points):
    # 增加point矩阵维度
    ones_data = np.ones(points.shape[0])
    points = np.insert(points, 3, values=ones_data, axis=1)
    new_xyz_data = np.dot(matrix, points.T)
    points = new_xyz_data[:3].T
    return points

if __name__ == "__main__":
    readModelpath = r"faceModel/face-s.obj"
    save_model_to_origin_path = r"csdn/face-s-roate.obj"
    # 旋转角度 弧度制
    x_r, y_r, z_r = -1, 1, 2

    obj_mesh = read_objPoint(readModelpath)
    # 获得所有点坐标
    points = np.array(obj_mesh["v"])
    # 获得所有店的法向量
    normalvector = np.array(obj_mesh["vn"])
    # 计算模型中心点xyz
    centroid = core_point(points)

    to_origin_matrix, form_origin_matrix = get_Preprocessmatrix(centroid)
    roate_matrix = get_roatematrix(x_r, y_r, z_r)
    # 移到原点-->旋转-->复原
    change_matrix = form_origin_matrix.dot(roate_matrix).dot(to_origin_matrix)

    roate_points = transform_model(change_matrix, points)
    roate_normalvector = transform_model(change_matrix, normalvector)
    obj_mesh["v"] = roate_points.tolist()
    obj_mesh["vn"] = roate_normalvector.tolist()
    save_objpoint(save_model_to_origin_path, obj_mesh)

三维人脸(python):obj模型文件的常规操作_第9张图片
三维人脸(python):obj模型文件的常规操作_第10张图片

7.混合操作完整实例代码

import numpy as np
#加载模型
def read_objPoint(model_path):
    obj_mesh = {'v': [], 'vt': [], 'vn': [], 'f': []}
    with open(model_path, 'r') as f:
        for line in f.readlines():
            values = line.strip().split()
            if values == []:
                continue
            if values[0] == 'v':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vt':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'vn':
                obj_mesh[values[0]].append(list(map(float, values[1:])))
            if values[0] == 'f':
                obj_mesh[values[0]].append(
                    [list(map(lambda x: int('0' + x), value.split('/'))) for value in values[1:]])
    return obj_mesh

#保存模型
def save_objpoint(new_model_savepath, obj_mesh):
    with open(new_model_savepath, 'w') as f:
        for obj_key in obj_mesh:
            if obj_key == 'v':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key]+values + ['\n']])
            if obj_key == 'vt':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == 'vn':
                f.writelines([str(value) + ' ' for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])
            if obj_key == "f":
                f.writelines([''.join(list(map(lambda x: (str(x) + "/"), value))).replace('0', '').strip('/')for values in obj_mesh[obj_key] for value in [obj_key] + values + ['\n']])

# 计算模型中心点xyz
def core_point(points):
    centroid = np.mean(points, axis=0)
    return centroid
# 预处理矩阵
def get_Preprocessmatrix(centroid):
    # centroid是模型中心点xyz坐标
    # 中心位移到原点
    to_origin_matrix = np.array([
        [1, 0, 0, -centroid[0]],
        [0, 1, 0, -centroid[1]],
        [0, 0, 1, -centroid[2]],
        [0, 0, 0, 1]
    ])
    # 位置复原
    form_origin_matrix = np.array([
        [1, 0, 0, centroid[0]],
        [0, 1, 0, centroid[1]],
        [0, 0, 1, centroid[2]],
        [0, 0, 0, 1]
    ])
    return to_origin_matrix, form_origin_matrix

def get_changematrix(x_translation, y_translation, z_translation, roate_x, roate_y, roate_z, scale):
    # 旋转矩阵
    roate_x_matrix = np.array([
        [1, 0, 0, 0],
        [0, np.cos(roate_x), -np.sin(roate_x), 0],
        [0, np.sin(roate_x), np.cos(roate_x), 0],
        [0, 0, 0, 1]
    ])

    roate_y_matrix = np.array([
        [np.cos(roate_y), 0, np.sin(roate_y), 0],
        [0, 1, 0, 0],
        [-np.sin(roate_y), 0, np.cos(roate_y), 0],
        [0, 0, 0, 1]
    ])
    roate_z_matrix = np.array([
        [np.cos(roate_z), -np.sin(roate_z), 0, 0],
        [np.sin(roate_z), np.cos(roate_z), 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ])

    # 平移矩阵
    translation_matrix = np.array([
        [1, 0, 0, -x_translation],
        [0, 1, 0, -y_translation],
        [0, 0, 1, -z_translation],
        [0, 0, 0, 1]
    ])

    # 缩放矩阵
    scale_matrix = np.array([
        [scale, 0, 0, 0],
        [0, scale, 0, 0],
        [0, 0, scale, 0],
        [0, 0, 0, 1]
    ])
    change_matrix =scale_matrix.dot(roate_z_matrix).dot(roate_y_matrix).dot(roate_x_matrix).dot(translation_matrix)
    return change_matrix

# 改变模型的空间位置
def transform_model(matrix, points):
    # 增加point矩阵维度
    ones_data = np.ones(points.shape[0])
    points = np.insert(points, 3, values=ones_data, axis=1)
    new_xyz_data = np.dot(matrix, points.T)
    points = new_xyz_data[:3].T
    return points

if __name__ == "__main__":
    readModelpath = r"faceModel/face-s.obj"
    save_model_to_origin_path = r"csdn/face-s-change.obj"
    x_r, y_r, z_r = -1, 1, 2
    x_tra, y_tra, z_tra = 200,300,200
    scale = 5
    obj_mesh = read_objPoint(readModelpath)
    # 获得所有点坐标
    points = np.array(obj_mesh["v"])
    # 获得所有店的法向量
    normalvector = np.array(obj_mesh["vn"])
    # 计算模型中心点xyz
    centroid = core_point(points)

    to_origin_matrix, form_origin_matrix = get_Preprocessmatrix(centroid)
    change_matrix = get_changematrix(x_tra, y_tra, z_tra, x_r, y_r, z_r,scale)
    # 移到原点-->转换-->复原
    change_matrix = form_origin_matrix.dot(change_matrix).dot(to_origin_matrix)

    change_points = transform_model(change_matrix, points)
    change_normalvector = transform_model(change_matrix, normalvector)
    obj_mesh["v"] = change_points.tolist()
    obj_mesh["vn"] = change_normalvector.tolist()
    save_objpoint(save_model_to_origin_path, obj_mesh)

三维人脸(python):obj模型文件的常规操作_第11张图片


总结

CSDN大部分博文关于obj的基本操作都比较简单粗糙,所以自己写了版比较简洁的代码方便自己复习以及提供大家参考。

你可能感兴趣的:(三维深度学习,python)