当前位置:   article > 正文

【三维视觉】三维人脸(python):obj模型文件的常规操作_pyopengl显示3d .obj文件

pyopengl显示3d .obj文件

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


前言

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

2.顶点(符号v)【v x y z 】: 每个顶点的xyz三个坐标。

3.顶点纹理(符号vt)【vt u v w】: 每个顶点的纹理是取纹理图片上(u,v)坐标的像素值,w形容三维纹理。

4.顶点法向量(符号vn)【vn x y z】: 三角面片的朝向由构成顶点对应的法向量做矢量和决定,即三个法向量分别对xyz坐标相加再除以3。

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


二、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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
'
运行

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']])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
'
运行

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
'
运行

完整实例代码

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

红框是原始模型,绿框是位移到原点的模型:

绿框是位移到原点的模型,黑框是复原后的模型:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
'
运行

完整实例代码

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
'
运行

完整实例代码

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
'
运行

完整实例代码

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116


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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129


总结

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

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号