cornerstone系列 - 定位功能
需求
假设界面上有四个影像序列窗口,S1 S2 S3 S4
S1为操作序列,视图内的其余三个序列为目标序列。在操作序列S1中点击想要定位的点P,3个目标序列自动匹配空间内距离点P最近的一层图像,并将定位点垂直投射到这层图像上显示。
思路
新增一个cornerstone-tools工具:ReferencePositionTool,业务的实现和官方提供的定位线差不多,利用synchronize机制,在打开3d定位功能开关时,将S1添加为sourceElement,将S2/3/4作为targetElement,实现目标序列对操作序列事件的响应。和定位线不一样的是,定位线是scroll触发的event,现在是操作序列点击后触发,并且操作序列也需要绘制定位的点,所以extends BaseAnnotationPlusTool。
render的时候,source和target使用不同的render方法,代码如下:
// 在view中disable enable cornerstone-tool的工具 会触发
async enabledCallback(element, {synchronizationContext, isSource, imageIds} = {}) {
const enabledElement = await waitForEnabledElementImageToLoad(element);
if (!enabledElement || !synchronizationContext) {
logger.warn(
`Unable to enable ${this.name}. Exiting enable callback. Tool will be enabled, but will not render.`
);
return;
}
this.isSource = isSource;
this.synchronizationContext = synchronizationContext;
this.imageIds = imageIds
if (isSource) {
this.renderer = this.renderPosition;
} else {
this.renderer = this.renderTargetPosition;
}
this.forceImageUpdate(element); // cornerstone update image
}
source只绘制定位点,target需要根据source的toolData的值,来计算需要翻到哪一层,要绘制在哪个位置
目标序列中位置点的计算
获取source image和target image,获得两者的image plane,为了转换空间坐标imagePointToPatientPoint,这样得到source图像上的点在空间中的位置,cornerstone-tools提供的方法,但是我用的版本好像没有加入pixelSpacing的计算,就自己重写了下,xcolumnPixelSpacing,yrowPixelSpacing就行。之前enable的时候记录了imageIds,imageIds长度作为层数进行遍历,计算操作点到目标面的距离,比较得出最小的距离
lodash.forEach(this.imageIds, (imageId, index) => {
// 每一层图像的plane
const imagePlane = cornerstone.metaData.get(
'imagePlaneModule',
imageId
);
// 保证图像的有效性
if (!imagePlane || !imagePlane.rowCosines || !imagePlane.columnCosines || !imagePlane.imagePositionPatient) {
return
}
// 操作点垂直映射到目标平面
const sourcePointInTargetPlane = projectPatientPointToImagePlane(sourcePointV3, imagePlane);
// 垂直点在空间的距离
const sourcePointInTargetPlaneV3 = imagePointToPatientPoint(sourcePointInTargetPlane, imagePlane);
// 距离计算
const distance = this.calcDistance(sourcePointV3, sourcePointInTargetPlaneV3);
if ((!min && (min !== 0)) || (distance < min)) {
min = distance;
targetImageIndex = index;
}
})
// view跳转到这层图像上
scrollToIndex(element, targetImageIndex);
// 绘制映射点在目标图像上....
......
last
很久没更新了,虽然这两年也穿插着做些影像相关的任务,但是对这块的了解还是比较片面,一些东西没及时写成笔记也有点忘记了,有错的地方欢迎指正,感谢~