Skip to content

Commit e0debd1

Browse files
committed
Merge branch 'bugfix/overlap_priorities' into 'develop'
Fix application of overlap priorities when similar levels are present See merge request e040/e0404/pyRadPlan!95
2 parents cea0d11 + 183dd7b commit e0debd1

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

pyRadPlan/cst/_cst.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,22 @@ def apply_overlap_priorities(self) -> Self:
281281
# sort by overlap priority
282282
ix_sorted = np.argsort(overlaps)
283283

284-
overlap_mask = self.vois[ix_sorted[0]].mask
284+
overlap_mask = self.vois[ix_sorted[0]].mask # Will aggregate the overlap masks using OR
285+
last_priority_mask = sitk.Image(overlap_mask.GetSize(), overlap_mask.GetPixelID())
286+
last_priority_mask.CopyInformation(overlap_mask)
287+
285288
new_vois = [None] * len(self.vois)
286-
new_vois[ix_sorted[0]] = self.vois[ix_sorted[0]].copy()
289+
new_vois[ix_sorted[0]] = self.vois[ix_sorted[0]].model_copy()
287290

288291
for i, ix_voi in enumerate(ix_sorted[1:], 1):
289-
curr_voi = self.vois[ix_voi].copy()
292+
curr_voi = self.vois[ix_voi].model_copy()
290293
curr_mask = curr_voi.mask
291294

292295
# if the overlap prirority is higher than we need to apply overlap
293-
if curr_voi.overlap_priority > new_vois[ix_sorted[i - 1]].overlap_priority:
294-
curr_mask = sitk.MaskNegated(curr_mask, overlap_mask)
296+
if curr_voi.overlap_priority >= new_vois[ix_sorted[i - 1]].overlap_priority:
297+
if curr_voi.overlap_priority > new_vois[ix_sorted[i - 1]].overlap_priority:
298+
last_priority_mask = overlap_mask
299+
curr_mask = sitk.MaskNegated(curr_mask, last_priority_mask)
295300

296301
curr_voi.mask = curr_mask
297302

test/cst/test_cst.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,15 +224,16 @@ def generic_vois(generic_ct):
224224

225225
voi1 = Target(name="CTV", mask=mask_image1, ct_image=generic_ct, overlap_priority=1)
226226
voi2 = Target(name="PTV", mask=mask_image2, ct_image=generic_ct, overlap_priority=2)
227-
voi3 = OAR(name="OAR", mask=mask_image3, ct_image=generic_ct)
228-
voi4 = ExternalVOI(name="BODY", mask=mask_image4, ct_image=generic_ct)
229-
voi5 = HelperVOI(name="HELPER", mask=mask_image5, ct_image=generic_ct)
227+
voi3 = OAR(name="OAR", mask=mask_image3, ct_image=generic_ct, overlap_priority=5)
228+
voi4 = ExternalVOI(name="BODY", mask=mask_image4, ct_image=generic_ct, overlap_priority=10)
229+
voi5 = HelperVOI(name="HELPER", mask=mask_image5, ct_image=generic_ct, overlap_priority=5)
230230

231231
return [voi1, voi2, voi3, voi4, voi5]
232232

233233

234234
def test_apply_overlap_priorities(generic_ct, generic_vois):
235235
# Create a StructureSet with the VOIs
236+
236237
structure_set = StructureSet(ct_image=generic_ct, vois=generic_vois)
237238

238239
# Apply overlap priorities
@@ -250,19 +251,24 @@ def test_apply_overlap_priorities(generic_ct, generic_vois):
250251
expected_overlap_list = np.argsort(p)
251252

252253
ol_mask = np.zeros(voi_mask[0].shape, dtype=bool)
254+
or_mask = np.zeros(voi_mask[0].shape, dtype=bool)
255+
last_priority = -1
253256

254257
for expected in expected_overlap_list:
258+
if p[expected] > last_priority:
259+
ol_mask = or_mask.copy()
260+
last_priority = p[expected]
261+
255262
# the mask that the current voi should have
256263
assert (
257264
voi_mask_overlapped[expected][np.logical_and(voi_mask[expected] > 0, ~ol_mask)]
258265
).all()
259266

260267
# Accumulate the ol mask
261-
ol_mask = ol_mask | voi_mask[expected] > 0
268+
or_mask = or_mask | voi_mask[expected] > 0
262269

263270
# we currently should be zero where overlapped
264-
assert not (voi_mask_overlapped[expected][ol_mask] == 0).all()
265-
# the accumulated ol mask
271+
assert (voi_mask_overlapped[expected][ol_mask] == 0).all()
266272

267273

268274
def test_apply_overlap_priorities_same_priority(generic_ct, generic_vois):

0 commit comments

Comments
 (0)