// A is the user object associated with each mask (aka a "label"). persistable sclass G22HashedMasks is IG22SimpleMasksHolder { !include early #1035854 // Masks holder Include record noeq Mask(Image2B image) is IG22Mask { settable A label; int hash; public bool equals(O o) { if (o cast G22HashedMasks.Mask) ret hashCode() == o.hashCode() && binaryImagesIdentical(image, o.image); false; } public int hashCode() { if (hash == 0) hash = (int) hashImage2B(image); ret hash; } public Image2B image() { ret image; } } new CompactHashSet masks; // creating a sub-holder *(L> masks) { assertNempty(masks); maskSize(imageSize(first(masks).image())); fOr (mask : masks) this.masks.add(mask); } // same with pre-calculated ghost *(L> masks, G22GhostImage ghost) { this(masks); ghost_cache = ghost; } void addRegion(IImageRegion region, A label) { addMask(regionToMaskImage(region), label); } void addMask(IBinaryImage maskImage, A label default null) { var mask = new Mask(toImage2B(maskImage)); var existingMask = masks.find(mask); if (existingMask != null) { mask = existingMask; mask.label = combineLabels(mask.label, label); } else { mask.label = label; masks.add(mask); } ghost_cache = null; certainty_cache = null; //this.labels.addAll(labels); } public L masks() { ret asList(masks); } /*public LPair maskImagesWithLabels() { ret map(masks(), mask -> pair(mask.image, mask.labels)); }*/ A combineLabels(A label1, A label2) { if (eq(label1, label2)) ret label1; if (label1 == null) ret label2; if (label2 == null) ret label1; if (label1 cast MultiSet) { if (label2 cast MultiSet) { label1.addAll(label2); ret (A) label1; } } ret specialCombineLabels(label1, label2); } swappable A specialCombineLabels(A label1, A label2) { fail("Can't combine labels: " + label1 + " + " + label2); } public IG22MasksHolder cloneTreeWithLabelTransform(IF1 f) { new G22HashedMasks clone; for (mask : masks) { G22HashedMasks.Mask clonedMask = clone.new Mask; clonedMask.image = mask.image; clonedMask.hash = mask.hash; clonedMask.label = f.get(mask.label); clone.masks.add(clonedMask); } ret clone; } }