Hidden Surface Removel Algorithms----Occlusion Culling一种高效的基于大规模地形场景的OCCLUSION CULLING算法...

本文提出一种实时地形遮挡剔除算法,通过线段求交技术高效剔除被遮挡的地形块,有效提升渲染效率。

对于通用场景来说我以前介绍的区间扫描线Z缓冲器算法可以剔除大部分的不可见物

体,但是在基于heightmap的大规模地形场景下会发现作用不是太大,区间扫描线Z

缓冲器算法需要在场景中手工指定occluder,occluder必须为规则物体,而在地形

场景中这种occluder非常少,也就是场景中的建筑物之类的物体。实际上地形场景

中最适合作为occluder的是连绵起伏的丘陵、山脉,它遮挡住了场景中的大部分物

体,但是区间扫描线Z缓冲器算法对这种情况下的OC就无能为力了,需要使用其它算

法进行OC计算,现在网上完全公开的适用于地形场景的OC技术主要有以下几种:
Voxel column culling、Hierarchical visibility、incremental horizon。这些

算法都需要进行一些预处理,其中最流行是incremental horizon(增量地平线)技

术,这种技术要求在渲染前对每一个地形块计算一个潜在轮廓线,在渲染时将这些

潜在轮廓线合并为地平线进行OC处理。由于这种算法需要进行预处理因此也不太适

用游戏开发,此后我自己又开发了一个realtime计算的incremental horizon算法,

但是发现开销太大,根本无法用于realtime rendering(和Pascal Junod在论文
《Implementation of a O(na(n)log(n)) Point
Visibility Algorithm on Digital Terrain Models》中使用的算法相同,这篇论

文我也是后来才发现的,有兴趣的可以翻看一下我以前在gameres发表的文章)。
下面列出的是网上相关的论文,有兴趣可以自己看一下。
Lloyd B, Egbert P. Horizon occlusion culling for real-time rendering of

hierarchical terrains. In: Gross M, Joy KI, Moorhead RJ, eds. Proc. of

the IEEE Visualization. Boston: IEEE Computer Society Press, 2002. 403-

410.
Stewart J. Hierarchical visibility in terrains. In: Dorsey J, Slusallek

P, eds. Eurographics Workshop on Rendering. Vienna: Springer-Verlag,

1997. 217-228.
Zaugg B, Egbert P. Voxel column culling: Occlusion culling for large

terrain models. In: Ebert D, Favre JM, Peikert R, eds. Proc. of the Joint

Eurographics-IEEE TCVG Symp. on Visualization. Vienna: Springer-Verlag,

2001. 85-93.
Stewart J. Fast horizon computation at all points of a terrain with

visibility and shading application. IEEE Trans. on Visualization and

Computer Graphics, 1998,4(1):82-93.
Daniel Archambault. All the Distant Horizon Edges of a Terrain. B.Sc.

(Hons.) in Computing Science, Queen’s University (Kingston), 2001
Pascal Junod. Implementation of a O(na(n)log(n)) Point
Visibility Algorithm on Digital Terrain Models. October 1999

后来我仔细观察farcry的editor sandbox,经过差不多两个多月的试验终于开发出

一个可以realtime运行的用于地形环境的OC算法,这个算法的开销非常小,经过我

在OGRE平台上的试验,此算法可以做到非常精确的剔除,FPS提升明显。由于这个算

法的核心是线段求交,因此我暂时称其为线段求交OC算法。
在介绍这个算法前先明确一下坐标系,一张heightmap的行为X,列为Y,高度方向为

Z。
先考虑单点OC的情况,如下图所示:
         P
         |
         |C
A-------------------B
         |
         |
         O
假设plane AB为一个occluder,O为camera位置,如果要判断点P是否被AB遮挡,只

需要简单的判断线段OP是否和occluder AB相交即可,如果存在相交点C则点P即被遮

挡,问题被简化为线段和平面的求交。下面继续考虑在地形环境下如何简化这个问

题,在地形环境下heightmap的每一行和列都可以看作一个occluder,这里假设AB为

行或列相临两个顶点组成的线段,如果要判断点P是否被AB遮挡,可以通过比较交点

C在线段OP和线段AB上的z值来确定:
Zc_op > Zc_ab   点P没有被线段AB遮挡
Zc_op <= Zc_ab  点P被线段AB遮挡
现在检查点P是否被遮挡在地形环境下简化为一个简单的2D线段求交问题,这也是本

算法之所以高效的原因。
下面继续来看一下如何将算法由一个点推广到整个地形。在基于heightmap的地形系

统中通常将地形分成一块块小的tile,根据LOD算法的不同tile大小可以为17*17或

者33*33不等,这里假设使用17*17的tile。
首先来看如何剔除场景中被遮挡的tile。对于tile来说如果所有的顶点都位于其前

方行和列的下方,那么它一定被遮挡。换句更精确的定义,对于tile的每一个顶点

,如果与camera所在位置所形成的线段,全部与位于tile和camera之间的行或列中

任意一条线段相交,那么可以确认tile被完全遮挡。
按照上面的定义,一个tile如果被检查到完全遮挡需要检查17*17=289次,虽然2D线

段求交运算开销非常小,但是一个tile就需要进行289次运算仍然是不可接受的,需

要更简化的算法。考虑一下区间扫描线Z缓冲器算法,occludee使用都是物体的AABB

,是否可以使用tile的AABB进行运算呢?由于地形环境的性质可以不用考虑AABB最

下面的四个顶点,但是直接使用AABB最上面的四个顶点进行运算绝对不行,如图所

示:

四个顶点虽然被完全遮挡,但是occludee并没有被完全遮挡,如果解决这个问题需

要将AABB的up表面分割成16*16的格子,这样的话运算次数并没有发生变化。
这里可以使用一个取巧的方法,如下图所示:


将AABB投影到camera空间,直接获得线段AB,将AB线段16等分,获得17个新的顶点

,注意这些顶点z值全部相等,现在ocludee是否可见只需要检查17次就可以了。
下面看一下算法复杂度,对于一个完全遮挡的tile只需要进行17个顶点的计算,完全未遮挡的tile只需要计算一个顶点,部分遮挡的tile大约是2-16个顶点左右,由于tile在进行OC运算之前首先要做frustum culling,剔除被frustum culling的tile,然后剔除那些没有被遮挡的tile,实际上的运算量非常少。
注意这里的每个顶点的计算不是指简单的17次线段求教运算,根据tile距离camera位置的远近每一个顶点求交的数量是不一样的,例如下图所示:


图中线段OA需要检查三条行和列,一共是六个交点,需要进行六次线段求交运算.
对于场景中的模型进行OC运算时,也需要按照上面的方法将模型的AABB变换到camera空间,获取一条occludee线段,然后根据地形相临顶点之间的距离确定顶点数。
使用这个算法和区间扫描线Z缓冲器算法相配合可以获得在室外场景中最大限度的剔除被遮挡物体,先用线段相交OC算法剔除被地表遮挡的tile和模型,然后用区间扫描线Z缓冲器算法剔除被建筑物遮挡的tile和模型,完美的室外场景OC解决方案,very nice!!!!

原创文章,转载请注明出处!!!!!!!

线段相交OC算法演示程序下载(使用OGRE平台,运行前先看readme文件):
/Files/dreams/ogrenew.part01.rar
/Files/dreams/ogrenew.part02.rar
/Files/dreams/ogrenew.part03.rar

/Files/dreams/ogrenew.part04.rar
/Files/dreams/ogrenew.part05.rar

/Files/dreams/ogrenew.part06.rar
由于cnblog上传文件大小限制,因此文件被分割成1M大小上传,抱歉!!!!

转载于:https://www.cnblogs.com/dreams/archive/2007/03/26/688650.html

``` import numpy as np import pandas as pd from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import MinMaxScaler, StandardScaler from sklearn.svm import SVR from sklearn.metrics import mean_squared_error, r2_score df = pd.read_excel('集胞藻-Cd.xlsx') # 加载数据 df.columns = df.columns.str.strip() # 清理列名 # 定义特征和目标变量 features =['T','Ph','Biomass','Time','Initial'] target_column = 'Removel' # 提取特征和目标数据 X = df[features] y = df[target_column] # 示例代码,直接使用 sklearn 的数据集 # from sklearn.datasets import load_boston # data = load_boston() # X = data.data # y = data.target # 分割数据为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 特征归一化 scaler_X = MinMaxScaler() X_train_scaled = scaler_X.fit_transform(X_train) X_test_scaled = scaler_X.transform(X_test) # 目标归一化(修改后) scaler_y = MinMaxScaler() y_train_scaled = scaler_y.fit_transform(y_train.values.reshape(-1, 1)).flatten() y_test_scaled = scaler_y.transform(y_test.values.reshape(-1, 1)).flatten() # # 定义 SVR 参数网格 # param_grid = { # 'kernel': ['linear', 'rbf', 'poly'], # 'C': [1e0, 1e1, 1e2], # 'gamma': [0.1, 0.01, 0.001], # 'epsilon': [0.1, 0.2, 0.3] # } # # # 创建 SVR 模型 # svr = SVR() # 优化后的参数网格示例 param_grid = { 'kernel': ['rbf', 'poly'], 'C': np.logspace(-2, 3, 6), # [0.01, 0.1, 1, 10, 100, 1000] 'gamma': np.logspace(-4, 0, 5), # [0.0001, 0.001, 0.01, 0.1, 1] 'epsilon': [0.05, 0.1, 0.2], 'degree': [2, 3] } # 添加早停机制 svr = SVR(max_iter=10000, tol=1e-4) # 使用网格搜索进行参数优化 grid_search = GridSearchCV(svr, param_grid, cv=5, scoring='neg_mean_squared_error', verbose=1) grid_search.fit(X_train_scaled, y_train_scaled) # 获取最佳参数和最优模型 best_params = grid_search.best_params_ best_svr = grid_search.best_estimator_ # 预测 y_train_pred = best_svr.predict(X_train_scaled) y_test_pred = best_svr.predict(X_test_scaled) # 反归一化预测结果(如果目标进行了归一化) y_train_pred_original = scaler_y.inverse_transform(y_train_pred.reshape(-1, 1)).flatten() y_test_pred_original = scaler_y.inverse_transform(y_test_pred.reshape(-1, 1)).flatten() # 计算性能指标 mse_train = mean_squared_error(y_train, y_train_pred_original) rmse_train = np.sqrt(mse_train) r2_train = r2_score(y_train, y_train_pred_original) mse_test = mean_squared_error(y_test, y_test_pred_original) rmse_test = np.sqrt(mse_test) r2_test = r2_score(y_test, y_test_pred_original) print(f"最佳参数: {best_params}") print(f"训练集 MSE: {mse_train}, RMSE: {rmse_train}, R^2: {r2_train}") print(f"测试集 MSE: {mse_test}, RMSE: {rmse_test}, R^2: {r2_test}") # 将结果保存到DataFrame results_df = pd.DataFrame({ '数据集': ['训练集', '测试集'], 'MSE': [mse_train, mse_test], 'RMSE': [rmse_train, rmse_test], 'R²': [r2_train, r2_test] }) # 保存到Excel文件(推荐使用) results_df.to_excel('支持向量机结果/集胞藻-Cd模型评估结果.xlsx', index=False)```根据上述代码生成一个遍历数据文件的代码,分别输出结果,并再最后输出一个汇总结果的文件
03-08
<think>嗯,用户让我根据提供的SVR模型代码,生成一个遍历数据文件的版本,分别输出结果,并最后生成汇总结果。我需要先理解原来的代码结构,然后考虑如何修改以实现遍历多个文件。 首先,原代码是针对单个Excel文件处理的,用户现在希望处理多个类似的文件。所以,我需要确定这些数据文件的存放位置和命名规律。比如,是否都在同一个目录下,或者有特定的文件名模式,比如都以“集胞藻-”开头,后面跟不同的金属名称,比如Cd、Pb等。假设用户的数据文件都放在同一个文件夹中,并且命名类似“集胞藻-XX.xlsx”,那么需要遍历该目录下的所有符合条件的文件。 接下来,代码需要为每个文件执行相同的处理流程:加载数据、分割训练测试集、归一化、网格搜索、预测、评估、保存结果。因此,可以将整个处理过程封装成一个函数,接收文件路径作为参数,返回评估结果和最佳参数等信息。 然后,汇总结果需要收集所有文件的评估指标,可能包括每个文件的训练集和测试集的MSE、RMSE、R²,以及最佳参数。最后将这些汇总数据保存到一个Excel文件中。 另外,需要考虑文件路径的处理。比如,原始代码中的结果保存路径是“支持向量机结果/”,需要确保这个目录存在,如果不存在的话,可能需要用os.makedirs来创建。 还需要处理可能出现的异常,比如文件无法读取,或者数据格式不正确,但用户可能希望代码尽量简单,暂时不加入异常处理,除非特别要求。 然后,关于参数网格,原代码中已经有一个优化后的param_grid,可能在遍历不同文件时,是否需要调整参数?但用户可能希望保持参数一致,所以直接复用原来的参数设置。 接下来,循环遍历所有数据文件,对每个文件调用处理函数,收集结果。每个文件处理完后,保存单独的评估结果和最佳参数到对应的文件夹中,比如每个金属单独一个子目录,或者统一放在支持向量机结果下,按文件名区分。 最后,汇总所有结果到一个DataFrame,并保存为Excel文件。 可能的步骤: 1. 确定数据文件的路径模式,比如使用glob模块查找所有符合模式的文件。 2. 将原代码的处理流程封装成函数,接收文件路径,返回评估结果和最佳参数。 3. 遍历每个文件,调用处理函数,收集结果。 4. 汇总所有结果,保存到汇总文件。 5. 确保输出目录存在,处理文件保存路径,避免覆盖。 需要注意的细节: - 每个文件的处理结果需要保存到不同的文件中,可能以数据文件名作为标识。例如,“集胞藻-Cd”的结果保存在“支持向量机结果/集胞藻-Cd/”下。 - 汇总文件应包含所有文件的评估指标,可能包括文件名、训练集和测试集的各个指标,以及最佳参数。 - 需要处理目标列名称是否一致,原代码中的target_column是'Removal',需要确认其他数据文件是否有相同的列名。如果不同,可能需要调整,但用户可能假设所有文件结构相同,所以暂时按原列名处理。 - 确保在每次循环中,归一化器(scaler_X和scaler_y)都是重新初始化的,避免数据泄露。 现在,开始编写代码结构: 首先导入必要的模块,包括glob来查找文件。 然后定义处理函数process_file(file_path),它负责读取数据,执行训练测试分割、归一化、网格搜索等步骤,并返回结果指标和最佳参数。 在主循环中,使用glob.glob获取所有数据文件,例如在“数据目录/”下的所有xlsx文件,或者特定模式的文件。 对于每个文件,调用process_file,将结果添加到汇总列表中。 处理函数内部,需要为每个文件创建独立的输出目录,比如在“支持向量机结果/文件名/”下保存结果和模型评估。 最后,将汇总列表转换为DataFrame,保存为汇总文件。 测试代码时,需要确保路径正确,尤其是跨平台兼容性,比如使用os.path来处理路径拼接。 可能的代码修改: 原代码中的特征列是['T','Ph','Biomass','Time','Initial'],需要确认所有数据文件都有相同的特征列。如果是,则没问题,否则可能需要动态获取特征,但用户可能假设结构一致。 综上,修改后的代码应该包括循环处理多个文件,保存各自结果,最后汇总。</think>以下是基于您的代码改造的自动化多文件处理版本,包含结果汇总功能: ```python import numpy as np import pandas as pd import os from glob import glob from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import MinMaxScaler from sklearn.svm import SVR from sklearn.metrics import mean_squared_error, r2_score def process_file(file_path): """处理单个数据文件的全流程""" # 创建结果目录 file_name = os.path.splitext(os.path.basename(file_path))[0] output_dir = f"支持向量机结果/{file_name}/" os.makedirs(output_dir, exist_ok=True) # 加载数据 df = pd.read_excel(file_path) df.columns = df.columns.str.strip() # 定义特征和目标 features = ['T','Ph','Biomass','Time','Initial'] target_column = 'Removel' X = df[features] y = df[target_column] # 数据分割 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 特征归一化 scaler_X = MinMaxScaler() X_train_scaled = scaler_X.fit_transform(X_train) X_test_scaled = scaler_X.transform(X_test) # 目标归一化 scaler_y = MinMaxScaler() y_train_scaled = scaler_y.fit_transform(y_train.values.reshape(-1, 1)).flatten() y_test_scaled = scaler_y.transform(y_test.values.reshape(-1, 1)).flatten() # 参数网格 param_grid = { 'kernel': ['rbf', 'poly'], 'C': np.logspace(-2, 3, 6), 'gamma': np.logspace(-4, 0, 5), 'epsilon': [0.05, 0.1, 0.2], 'degree': [2, 3] } # 模型训练 svr = SVR(max_iter=10000, tol=1e-4) grid_search = GridSearchCV(svr, param_grid, cv=5, scoring='neg_mean_squared_error', verbose=0) grid_search.fit(X_train_scaled, y_train_scaled) # 获取最佳模型 best_params = grid_search.best_params_ best_svr = grid_search.best_estimator_ # 预测与反归一化 y_train_pred = scaler_y.inverse_transform( best_svr.predict(X_train_scaled).reshape(-1, 1)).flatten() y_test_pred = scaler_y.inverse_transform( best_svr.predict(X_test_scaled).reshape(-1, 1)).flatten() # 计算指标 metrics = { '训练集': { 'MSE': mean_squared_error(y_train, y_train_pred), 'R²': r2_score(y_train, y_train_pred) }, '测试集': { 'MSE': mean_squared_error(y_test, y_test_pred), 'R²': r2_score(y_test, y_test_pred) } } # 保存结果 pd.DataFrame({ '数据集': ['训练集', '测试集'], 'MSE': [metrics['训练集']['MSE'], metrics['测试集']['MSE']], 'R²': [metrics['训练集']['R²'], metrics['测试集']['R²']] }).to_excel(f"{output_dir}评估结果.xlsx", index=False) pd.DataFrame([best_params]).to_excel(f"{output_dir}最佳参数.xlsx", index=False) return { '文件名': file_name, '训练集_MSE': metrics['训练集']['MSE'], '训练集_R2': metrics['训练集']['R²'], '测试集_MSE': metrics['测试集']['MSE'], '测试集_R2': metrics['测试集']['R²'], '最佳参数': str(best_params) } # 主程序 if __name__ == "__main__": # 获取所有数据文件(假设数据文件在data目录下) data_files = glob('*.xlsx') # 修改为实际路径模式 # 处理所有文件并收集结果 summary = [] for file in data_files: print(f"正在处理文件:{file}") result = process_file(file) summary.append(result) # 保存汇总结果 summary_df = pd.DataFrame(summary) summary_df.to_excel("支持向量机结果/汇总结果.xlsx", index=False) print("所有文件处理完成,汇总结果已保存") ``` 关键改进说明: 1. **自动化文件遍历**: - 使用`glob`模块自动查找所有.xlsx文件(可根据需要修改文件路径模式) - 示例中默认处理当前目录下所有xlsx文件,可通过修改`glob('路径/*.xlsx')`指定目录 2. **模块化处理流程**: - 将单个文件的处理流程封装到`process_file()`函数 - 每个文件独立创建结果目录(如:支持向量机结果/集胞藻-Cd/) 3. **结果存储**: - 每个文件单独保存: - 评估结果.xlsx:包含训练/测试集的MSE和R² - 最佳参数.xlsx:记录网格搜索得到的最佳参数组合 - 最终生成汇总结果.xlsx:包含所有文件的性能指标和参数 4. **路径管理**: - 使用`os.makedirs`自动创建所需目录 - 使用`os.path`相关函数处理路径,确保跨平台兼容性 5. **性能优化**: - 设置`verbose=0`关闭网格搜索的详细输出 - 保持与原始代码相同的参数设置和数据处理流程 使用建议: 1. 文件结构: ``` 项目目录/ ├── 集胞藻-Cd.xlsx ├── 集胞藻-Pb.xlsx ├── ...(其他数据文件) ├── SVR_auto.py(本脚本) └── 支持向量机结果/ ├── 集胞藻-Cd/ │ ├── 评估结果.xlsx │ └── 最佳参数.xlsx ├── 集胞藻-Pb/ │ ├── 评估结果.xlsx │ └── 最佳参数.xlsx └── 汇总结果.xlsx ``` 2. 扩展性: - 可通过修改`features`和`target_column`变量适配不同数据格式 - 调整`param_grid`可修改搜索的超参数空间 - 修改`test_size`和`random_state`可改变数据分割方式 3. 运行方式: ```bash python SVR_auto.py ``` 注意:请确保: 1. 所有数据文件具有相同的特征列结构 2. 已安装所需依赖库(pandas, sklearn, numpy) 3. 有写入权限到目标目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值