python实现obj模型的归一化

作者:石炜贤&曾翔钰

归一化,个人理解就是将数据范围映射到另一个更小的范围。比如,我们即将要说到的obj模型的归一化,原始的数据坐标范围是-100多到+100多,这里我要将它归一化到-1~1的范围。

具体步骤如下:

  1. 读取每个点的信息,计算这个模型的包围盒(好吧,其实就是找到这个模型最小的x,y,z和最大的x,y,z。注意,这里不是最小的点和最大的点的坐标。)
 def get_bounding_box(self, p):
        """
        获取物体的最小x,y,z和最大的x,y,z
        :param p:
        :return:
        """
        self.minP.x = p.x if p.x < self.minP.x else self.minP.x
        self.minP.y = p.y if p.y < self.minP.y else self.minP.y
        self.minP.z = p.z if p.z < self.minP.z else self.minP.z
        self.maxP.x = p.x if p.x > self.maxP.x else self.maxP.x
        self.maxP.y = p.y if p.y > self.maxP.y else self.maxP.y
        self.maxP.z = p.z if p.z > self.maxP.z else self.maxP.z
  1. 通过第一步的x,y,z我们得到(max_x-min_x),(max_y-min_y)和(max_z-min_z)三者中的最大值,取最大值作为包围盒的边长,构建一个正方体式的包围盒。现在,想象这个 obj模型被包围盒包着并处于包围盒的中心。
 def get_bounding_box_length(self):
        """
        获取包围盒的最大长度
        :return:
        """
        box_len = self.maxP.x - self.minP.x
        if box_len < (self.maxP.y - self.minP.y):
            box_len = self.maxP.y - self.minP.y
        if box_len < (self.maxP.z - self.minP.z):
            box_len = self.maxP.z - self.minP.z
        return box_len
  1. OK,我们剩下要做的就是简单的将坐标放缩一下而已了。
    def do_normalize(self, box_len, points):
        """
        归一化处理
        :param center_p: 物体的中心点
        :param box_len: 包围盒的一半
        :param points:要进行归一化处理的点
        :return:
        """
        new_points = []
        for point in points:
            x = (point.x - self.minP.x) * 2 / box_len - 1
            y = (point.y - self.minP.y) * 2 / box_len - 1
            z = (point.z - self.minP.z) * 2 / box_len - 1
            new_points.append(Point(x, y, z))
        return new_points

完整代码如下:
运行的话,只需写入存放obj文件的文件夹路径(或者父路径也行)。

# encoding:utf-8

import os


class Point(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z


class MyFile(object):
    folders = []
    outFolders = []
    count = 0

    def get_folder_paths(self, base_path):
        """
        获取文件夹下所有含有obj文件的文件夹路径
        :param base_path:
        :return:
        """
        self.folders.append(base_path)
        files = os.listdir(base_path)
        contain_obj = False
        for file in files:
            file_path = os.path.join(base_path, file)
            if os.path.isdir(file_path):
                self.get_folder_paths(file_path)
                print(file_path)
                self.folders.append(file_path)
            elif os.path.isfile(base_path + file):
                contain_obj = True
        if contain_obj is not True:
            self.folders.remove(base_path)

    def get_obj_filenames(self, folder_path):
        filenames = []
        files = os.listdir(folder_path)
        for file in files:
            file_path = os.path.join(folder_path, file)
            if os.path.isfile(file_path) and file[-3:] == "obj":
                print("file:", file)
                filenames.append(file)
                self.count += 1
        return filenames

    def get_out_folders(self):
        for folder in self.folders:
            new_folder = str(folder).replace("Budata\\BU_3DFE", "NEW_NormalizeDataWithoutRound")
            self.outFolders.append(new_folder)
            # print(new_folder)
            if not os.path.exists(new_folder):
                os.makedirs(new_folder)


class MyNormalize(object):
    minP = Point(1000, 10000, 10000)
    maxP = Point(0, 0, 0)

    def get_bounding_box(self, p):
        """
        获取物体的最小x,y,z和最大的x,y,z
        :param p:
        :return:
        """
        self.minP.x = p.x if p.x < self.minP.x else self.minP.x
        self.minP.y = p.y if p.y < self.minP.y else self.minP.y
        self.minP.z = p.z if p.z < self.minP.z else self.minP.z
        self.maxP.x = p.x if p.x > self.maxP.x else self.maxP.x
        self.maxP.y = p.y if p.y > self.maxP.y else self.maxP.y
        self.maxP.z = p.z if p.z > self.maxP.z else self.maxP.z

    def get_bounding_box_length(self):
        """
        获取包围盒的最大长度
        :return:
        """
        box_len = self.maxP.x - self.minP.x
        if box_len < (self.maxP.y - self.minP.y):
            box_len = self.maxP.y - self.minP.y
        if box_len < (self.maxP.z - self.minP.z):
            box_len = self.maxP.z - self.minP.z
        return box_len

    def do_normalize(self, box_len, points):
        """
        归一化处理
        :param center_p: 物体的中心点
        :param box_len: 包围盒的一半
        :param points:要进行归一化处理的点
        :return:
        """
        new_points = []
        for point in points:
            x = (point.x - self.minP.x) * 2 / box_len - 1
            y = (point.y - self.minP.y) * 2 / box_len - 1
            z = (point.z - self.minP.z) * 2 / box_len - 1
            new_points.append(Point(x, y, z))
        return new_points

    def read_points(self, filename):
        """
        读取一个obj文件里的点
        :param filename:
        :return:
        """
        with open(filename) as file:
            points = []
            while 1:
                line = file.readline()
                if not line:
                    break
                strs = line.split(" ")
                if strs[0] == "v":
                    points.append(Point(float(strs[1]), float(strs[2]), float(strs[3])))
                if strs[0] == "vt":
                    break
        return points

    def write_points(self, points, src_filename, des_filename):
        """
        将归一化好的点保存到另一个文件
        :param points:
        :param src_filename:
        :param des_filename:
        :return:
        """
        point_lines = []
        for point in points:
            point_line = "v " + str(point.x) + " " + str(point.y) + " " + str(point.z) + "\n"
            point_lines.append(point_line)
        with open(src_filename, "r") as file:
            outFile = open(des_filename, "a")
            for point in points:
                point_line = "v " + str(point.x) + " " + str(point.y) + " " + str(point.z) + "\n"
                outFile.write(point_line)
                outFile.flush()
            while 1:
                line = file.readline()
                if not line:
                    break
                strs = line.split(" ")
                if strs[0] == "f":
                    outFile.write(line)
            outFile.flush()
            outFile.close()


if __name__ == "__main__":
    myFile = MyFile()
    myNormalize = MyNormalize()
    basePath = "H:\\Budata\\BU_3DFE\\"

    myFile.get_folder_paths(basePath)
    myFile.get_out_folders()
    count = 0
    for folder in myFile.folders:
        outFolderPath = myFile.outFolders.pop(0)
        print(outFolderPath)
        objFilenames = myFile.get_obj_filenames(folder)
        for objFilename in objFilenames:
            # 读取obj文件的坐标点
            objFilePath = os.path.join(folder, objFilename)
            points = myNormalize.read_points(objFilePath)
            for point in points:
                myNormalize.get_bounding_box(point)
            # 包围盒长度
            boxLength = myNormalize.get_bounding_box_length()
            # 归一化
            points = myNormalize.do_normalize(boxLength, points)
            # 将归一化的坐标点写入目标文件
            myNormalize.write_points(points, os.path.join(folder, objFilePath),
                                     os.path.join(outFolderPath, objFilename))
            count += 1
            print("第", count, "个执行完毕")

    print("执行结束")
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
灰狼优化算法(Grey Wolf Optimizer,GWO)是一种基于自然界灰狼群体行为的优化算法,它模拟了灰狼在社会组织中的狩猎行为,通过仿真狼群在狩猎过程中的行为,来求解最优化问题。随机森林回归是一种机器学习算法,它是一种集成学习方法,通过组合多个决策树来提高预测精度,具有较高的准确率和鲁棒性。 下面是使用GWO对随机森林回归进行调参的Python实现: ```python import numpy as np from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error # 灰狼优化算法(Grey Wolf Optimizer,GWO) class GWO: def __init__(self, n_population, max_iter, dim, lb, ub, obj_func): self.n_population = n_population # 种群数量 self.max_iter = max_iter # 最大迭代次数 self.dim = dim # 搜索维度 self.lb = lb # 搜索空间下限 self.ub = ub # 搜索空间上限 self.obj_func = obj_func # 目标函数 self.positions = np.zeros((self.n_population, self.dim)) # 种群位置 self.betas = np.zeros(self.n_population) # Beta向量 self.deltas = np.zeros(self.n_population) # Delta向量 self.alphas = np.zeros(self.dim) # Alpha位置 self.beta = 2 # Beta常数 self.delta = 2 # Delta常数 self.alpha = np.zeros(self.dim) # 初始Alpha位置 # 初始化种群 def init_population(self): self.positions = np.random.uniform(self.lb, self.ub, (self.n_population, self.dim)) self.betas = np.random.uniform(0, 1, self.n_population) self.deltas = np.random.uniform(0, 1, self.n_population) # 更新Alpha, Beta, Delta位置 def update_positions(self, iter): a = 2 - 2 * iter / self.max_iter # alpha参数 for i in range(self.n_population): r1, r2, r3 = np.random.rand(3) A1 = 2 * a * r1 - a # Alpha狼位置 C1 = 2 * r2 # Alpha狼距离 D_alpha = abs(C1 * self.alpha - self.positions[i]) # Alpha狼距离向量 X1 = self.alpha - A1 * D_alpha # 新位置 r1, r2, r3 = np.random.rand(3) A2 = 2 * a * r1 - a # Beta狼位置 C2 = 2 * r2 # Beta狼距离 D_beta = abs(C2 * self.betas[i] - self.positions[i]) # Beta狼距离向量 X2 = self.betas[i] - A2 * D_beta # 新位置 r1, r2, r3 = np.random.rand(3) A3 = 2 * a * r1 - a # Delta狼位置 C3 = 2 * r2 # Delta狼距离 D_delta = abs(C3 * self.deltas[i] - self.positions[i]) # Delta狼距离向量 X3 = self.deltas[i] - A3 * D_delta # 新位置 self.positions[i] = (X1 + X2 + X3) / 3 # 更新位置 self.alpha = self.positions[np.argmin([self.obj_func(x) for x in self.positions])] # 更新Alpha位置 self.betas = sorted(self.betas) # 排序 self.delta = self.betas[-1] # 更新Delta常数 self.betas = (self.betas - self.betas.min()) / (self.betas.max() - self.betas.min()) # 归一化 self.deltas = (self.deltas - self.deltas.min()) / (self.deltas.max() - self.deltas.min()) # 归一化 # 灰狼优化算法求解最优解 def optimize(self): self.init_population() for i in range(self.max_iter): self.update_positions(i) return self.alpha # 随机森林回归模型 def random_forest_regressor(n_estimators, max_depth, min_samples_split, min_samples_leaf, max_features, X_train, y_train, X_test, y_test): model = RandomForestRegressor(n_estimators=n_estimators, max_depth=max_depth, min_samples_split=min_samples_split, min_samples_leaf=min_samples_leaf, max_features=max_features) model.fit(X_train, y_train) y_pred = model.predict(X_test) return mean_squared_error(y_test, y_pred) # 参数范围 bounds = [(50, 200), (2, 10), (2, 10), (1, 5), (0.1, 1.0)] # 目标函数 def objective(params): n_estimators, max_depth, min_samples_split, min_samples_leaf, max_features = params return random_forest_regressor(n_estimators=int(n_estimators), max_depth=int(max_depth), min_samples_split=int(min_samples_split), min_samples_leaf=int(min_samples_leaf), max_features=max_features, X_train=X_train, y_train=y_train, X_test=X_test, y_test=y_test) # 数据集 from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split data = load_boston() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2) # 灰狼优化算法求解最优解 gwo = GWO(n_population=30, max_iter=50, dim=5, lb=[50, 2, 2, 1, 0.1], ub=[200, 10, 10, 5, 1.0], obj_func=objective) best_params = gwo.optimize() # 输出最优解 print('best_params:', best_params) print('MSE:', objective(best_params)) ``` 上述代码中,我们使用sklearn中的RandomForestRegressor作为目标函数,使用均方误差(Mean Squared Error,MSE)作为优化目标。我们使用train_test_split将数据集分为训练集和测试集,并使用灰狼优化算法对随机森林回归模型的参数进行调优,得到最优参数和最小MSE。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值