QuPath高效内存脚本开发:获取肿瘤内外边缘区域
优化后的QuPath脚本:提取6类组织区域
核心思路
基于QuPath原生的GeometryTools和RegionTools高效处理形态学运算,先合并同类型注释减少运算量,复用中间结果避免重复计算,全程以几何形状为核心操作,大幅降低内存占用与运行时间。
完整可运行脚本
import qupath.lib.geom.GeometryTools import qupath.lib.objects.PathAnnotationObject import qupath.lib.objects.classes.PathClassFactory // 配置关键参数 def tumorClassName = "Tumor" def tissueClassName = "Tissue" def innerDistance = 60.0 // μm def outerDistance = 120.0 // μm // 获取并预处理注释:合并同类型所有注释为单个几何形状 def tumorAnnos = getAnnotationObjects().findAll { it.getPathClass()?.getName() == tumorClassName } def tissueAnnos = getAnnotationObjects().findAll { it.getPathClass()?.getName() == tissueClassName } if (tumorAnnos.isEmpty() || tissueAnnos.isEmpty()) { print("错误:缺少肿瘤或整体组织注释!") return } def tumorGeom = GeometryTools.union(tumorAnnos.collect { it.getROI().getGeometry() }) def tissueGeom = GeometryTools.union(tissueAnnos.collect { it.getROI().getGeometry() }) // 计算各类目标区域 def regionMap = [:] // 1. 非肿瘤非边缘组织 = 整体组织 - 肿瘤向外扩展120μm的区域 def tumorExpand120 = GeometryTools.buffer(tumorGeom, outerDistance, true) regionMap["非肿瘤非边缘组织"] = tissueGeom.difference(tumorExpand120) // 2. 肿瘤周边60-120μm区域 = 肿瘤120μm缓冲区 - 肿瘤60μm缓冲区,再与整体组织取交集 def tumorExpand60 = GeometryTools.buffer(tumorGeom, innerDistance, true) regionMap["肿瘤周边60-120μm区域"] = tumorExpand120.difference(tumorExpand60).intersection(tissueGeom) // 3. 肿瘤周边0-60μm区域 = 肿瘤60μm缓冲区 - 肿瘤区域,再与整体组织取交集 regionMap["肿瘤周边0-60μm区域"] = tumorExpand60.difference(tumorGeom).intersection(tissueGeom) // 4. 肿瘤内部0-60μm区域 = 肿瘤区域 - 肿瘤向内收缩60μm的区域 def tumorShrink60 = GeometryTools.buffer(tumorGeom, -innerDistance, true) regionMap["肿瘤内部0-60μm区域"] = tumorGeom.difference(tumorShrink60) // 5. 肿瘤内部60-120μm区域 = 肿瘤向内收缩60μm的区域 - 肿瘤向内收缩120μm的区域 def tumorShrink120 = GeometryTools.buffer(tumorGeom, -outerDistance, true) regionMap["肿瘤内部60-120μm区域"] = tumorShrink60.difference(tumorShrink120) // 6. 剩余肿瘤组织 = 肿瘤向内收缩120μm的区域 regionMap["剩余肿瘤组织"] = tumorShrink120 // 将计算结果转为注释添加到图像 regionMap.each { name, geom -> if (!geom.isEmpty()) { def roi = GeometryTools.geometryToROI(geom, getCurrentImageData().getServer().getPixelCalibration()) def anno = new PathAnnotationObject(roi) anno.setPathClass(PathClassFactory.getPathClass(name)) addObject(anno) } else { print("警告:区域「$name」为空,跳过创建注释") } } print("所有区域提取完成!")
效率优化细节
- 合并注释预处理:将同类型的分散注释合并为单个几何形状,减少后续运算的循环次数
- 复用中间结果:比如
tumorExpand60同时用于计算周边0-60μm和内部0-60μm区域,避免重复执行缓冲运算 - 原生几何运算:依赖QuPath底层的JTS几何库,比自定义像素级遍历效率高数十倍
- 空值拦截:提前检查注释是否存在,跳过空区域的注释创建,避免无效操作
注意事项
- 确保图像已正确设置像素校准(单位为μm),否则距离计算会出现偏差
- 若肿瘤存在多个不连通区域,
union方法会自动合并为单个几何形状,不影响区域计算逻辑 - 若肿瘤尺寸过小导致某类区域为空(比如肿瘤直径小于120μm时,内部60-120μm区域不存在),脚本会打印警告并跳过该区域
内容的提问来源于stack exchange,提问作者fgootkind
相关产品推荐
相关产品推荐

