HD-BET颅骨剥离处理打包成脱离平台的exe文件实操过程 弄HD-BET已经有一周多了最近也算出了点结果下面详细总结一下吧。1HD-BET及其他颅脑分割算法比较HD-BET 源码地址https://github.com/MIC-DKFZ/HD-BET因为日常使用了FSL-BET而早版本的3D Slicer自带了Swiss Skull Stripper扩展包所以我就比较关心这三个方法的不同总之为了升级我的颅脑分割输出的大脑边缘实现高质量脑边界提取我已经开展了基于HD-BET的研究及部署之路。2HD-BET处理与Swiss skull stripper 处理图像结果看看这个输出就是看到了传统方法与深度框架的差异作为影像处理工作者肯定忍不了吧。当然起初作为3D Slicer 的内置扩展包Swiss Skull Stripper可以兼容初级版本也是了不起先创贡献者。而且是为3D Slicer的颅脑分割兜底。只是随着发展我们在与时俱进。3关于HD-BET 颅脑分割的部署想在初级的3D slicer 中部署HD-BET一开始并不顺利。因为里面自带的python还是2.7跟pytorch 和unet 好像挨不着。于是乎想了很多办法去整。自带HD-BET 需要的所有后台python环境和模型文件是一种方法但为了简便不搞那么多可怕的环境包我还是决定打包成exe.也就是在python工程中将HD-BET和他需要运行的环境打包成一个windows 可执行软件文件。这样我只需要调用这个exe就可以完成处理还要确保在没有python 没有网络的设备平台都可以运行。这次我还真干成了。下面记录一下步骤1)准备好要处理的影像文件并在python环境下安装相关的包开始运用HD-BET使得可以成功处理影像这里要自行科普先完成好真的不难2)把权重文件拷贝到工程路径下开始准备打包成exe文件**打包前测试一下运行环境是否可靠有问题及时修复test.pyimportsys print(当前使用的 Python 路径:, sys.executable)# 1. 尝试导入 HD_BET 主包try:importHD_BET print(成功HD_BET 模块已找到路径为:, HD_BET.__file__)except Exception as e: print(f失败导入 HD_BET 时发生错误: {type(e).__name__} - {e})# 2. 检查 PyTorch 和 CUDA 状态try:importtorch print(fPyTorch 版本: {torch.__version__})print(fCUDA 是否可用: {torch.cuda.is_available()})iftorch.cuda.is_available(): print(f当前显卡: {torch.cuda.get_device_name(0)})except Exception as e: print(f失败导入 torch 时发生错误: {type(e).__name__} - {e})查看下载的权重文件这个权重文件没有直接提供网址下载在第一次处理影像的时候会自动下载到本地其文件夹的名字是hd-bet_params在C盘用户名下里面有checkpoint_final.pth文件就是权重文件大概120MB大小。准备程序打包时要用到的脚本文件因为我需要部署到没有python 且没有网络但是有GPU的windows平台我希望我的HD-BET可以快速运行好像大多数不走服务器的医学影像处理软件都是这个路子在反复调整了很多次发现下面的代码符合我的要求inference.pyimportargparseimportosimportsysimportshutilimporttorch from typingimportOptionalimportmultiprocessing# PyInstaller 打包后资源会被解压到 sys._MEIPASSdef is_frozen()-bool:returngetattr(sys,frozen, False)and hasattr(sys,_MEIPASS)def resource_path(relative: str)-str: basesys._MEIPASSifis_frozen()elseos.path.abspath(.)returnos.path.join(base, relative)# 模型文件缓存到用户目录确保只复制一次且路径可写def ensure_custom_model(bundled_model_dir_name: strmodel_files, cache_root: Optional[str]None, cache_subdir: strhd_bet)-str:ifcache_root is None: cache_rootos.path.expanduser(~)cache_diros.path.join(cache_root,.cache, cache_subdir,model)os.makedirs(cache_dir,exist_okTrue)# 标记文件用来判断是否已复制过copied_flagos.path.join(cache_dir,.copied_from_bundle)ifnot os.path.exists(copied_flag): src_dirresource_path(bundled_model_dir_name)ifnot os.path.isdir(src_dir): raise FileNotFoundError(f打包内未找到 bundled 模型目录: {src_dir}。请确保打包命令里有 --add-data\model_files;model_files\。)print(f[模型] 首次运行从打包资源复制模型到缓存目录: {src_dir} - {cache_dir})# 清理旧缓存避免残留文件foriteminos.listdir(cache_dir): item_pathos.path.join(cache_dir, item)ifos.path.isfile(item_path): os.remove(item_path)else: shutil.rmtree(item_path,ignore_errorsTrue)# 复制新文件fornameinos.listdir(src_dir): srcos.path.join(src_dir, name)dstos.path.join(cache_dir, name)ifos.path.isdir(src): shutil.copytree(src, dst,dirs_exist_okTrue)else: shutil.copy2(src, dst)with open(copied_flag,w,encodingutf-8)as f: f.write(bundled)print([模型] 首次复制完成。后续启动将直接使用缓存不再重复复制。)else: print(f[模型] 使用缓存模型目录: {cache_dir})returncache_dir def parse_args(): parserargparse.ArgumentParser(descriptionHDBet_Inference 打包版入口)parser.add_argument(input,help输入 NIfTI 文件路径.nii/.nii.gz)parser.add_argument(output,help输出 NIfTI 文件路径.nii.gz)parser.add_argument(--cpu,actionstore_true,help强制使用 CPU忽略 GPU)parser.add_argument(--disable_tta,actionstore_true,help禁用测试时增强TTA提速)parser.add_argument(--verbose,actionstore_true,help显示更详细日志)parser.add_argument(--keep_bet_mask,actionstore_true,help保留中间脑掩码文件*_bet.nii.gz)returnparser.parse_known_args()def main():ifis_frozen(): print([系统] 打包模式资源目录:, sys._MEIPASS)# 将 torch/lib 加入 DLL 搜索路径提升兼容性Windowsifsys.platformwin32:torch_lib_pathos.path.join(sys._MEIPASS,torch,lib)ifos.path.isdir(torch_lib_path): print([DLL] 添加路径:, torch_lib_path)os.add_dll_directory(torch_lib_path)#args parse_args()args, _parse_args()device_strcpuifargs.cpuelse(cudaiftorch.cuda.is_available()elsecpu)devicetorch.device(device_str)print(f[硬件] 使用 device: {device_str})# 把自定义模型路径指向缓存目录并在运行前 patch 掉 HD_BET.pathsfrom HD_BETimportpaths as hd_bet_paths custom_model_dirensure_custom_model()hd_bet_paths.folder_with_parameter_filescustom_model_dir print(f[模型] folder_with_parameter_files 已设置为: {custom_model_dir})# HD_BET 正确的导入与调用方式from HD_BET.hd_bet_predictionimportget_hdbet_predictor, hdbet_predict predictorget_hdbet_predictor(use_ttanot args.disable_tta,devicedevice,verboseargs.verbose,)print([任务] 开始推理...)hdbet_predict(args.input, args.output, predictor,keep_brain_maskargs.keep_bet_mask,compute_brain_extracted_imageTrue,)print([成功] 推理完成。输出文件:, args.output)if__name____main__:multiprocessing.freeze_support()main()运用pyinstaller打包 如下为在终端上运行的打包语句pyinstaller--onefile--nameHDBet_Inference--clean--add-datamodel_files;model_files--hidden-importHD_BET --hidden-importHD_BET.hd_bet_prediction --hidden-importHD_BET.entry_point --hidden-importHD_BET.paths --hidden-importHD_BET.checkpoint_download --hidden-importnibabel --hidden-importnnunetv2.inference.predict_from_raw_data --hidden-importbatchgenerators --hidden-importSimpleITK --collect-all torch --collect-all nibabel --collect-all nnunetv2 --exclude-moduletorch.distributed --exclude-moduletorch.distributions inference.pyHDBet_Inference.exe是我期望的输出model_files就是权重文件夹在我当前的工程路径下inference.py就是上面的脚本文件也在我当前的工程路径下。打包完成以后会在我当前的工程路径下生成exe文件不过打包需要一定时间这个exe可不小2.88GB, 它打包了HD-BET运行的所有依赖环境还有权重文件当然它大还是因为我要部署的设备GPU型号和驱动不确定为了兼容。3基于开发环境测试对打包的exe基于powershell测试为了测试exe能否运行winRpowershell开发机CPU 和GPU都还可以所以加载以后26s能够跑完速度可接受。4基于部署的设备环境测试将我生成的HDBet_Inference.exe 拷贝到没有python 没有网络但有GPU 的部署设备测试运行结果基于设备的powershell处理影像查看结果很有意思–disable_tta可以牺牲少许精度并加快处理。如果GPU很好的设备就不用这么纠结了。输出的结果用3D Slicer 可以打开看。总之步骤不多但可能过程不那么顺畅一路修复部署好验证了几个设备都是可以用的。相当于自己打包了一个HD-BET的颅脑分割软件一样离线脱离python随时用啊还是很爽的而且非常方便部署到自己的工程中正好我已经部署成功了。exe文件太大了我就不分享出来了感觉是不是可以举一反三到其他模型上试试呀哇喔又是很有意思的一天~