def editBorder(self, blob, lines): points = [blob.drawLine(line) for line in lines] if points is None or len(points) == 0: return # compute the box for the outer contour intersected = False (mask, box, intersected) = self.editBorderContour(blob, blob.contour, points) pointIntersectsContours = intersected for contour in blob.inner_contours: (inner_mask, inner_box, intersected) = self.editBorderContour(blob, contour, points) pointIntersectsContours = pointIntersectsContours or intersected Mask.paintMask(mask, box, inner_mask, inner_box, 0) if not pointIntersectsContours: #probably a hole, draw the points fill the hole and subtract from mask allpoints = np.empty(shape=(0, 2), dtype=int) for arc in points: allpoints = np.append(allpoints, arc, axis=0) points_box = Mask.pointsBox(allpoints, 4) (points_mask, points_box) = Mask.jointMask(points_box, points_box) Mask.paintPoints(points_mask, points_box, allpoints, 1) origin = np.array([points_box[1], points_box[0]]) Mask.paintPoints(points_mask, points_box, allpoints - origin, 1) points_mask = ndi.binary_fill_holes(points_mask) points_mask = binary_erosion(points_mask) Mask.paintMask(mask, box, points_mask, points_box, 0) blob.updateUsingMask(box, mask)
def editBorderContour(self, blob, contour, points): snapped_points = np.empty(shape=(0, 2), dtype=int) for arc in points: snapped = blob.snapToContour(arc, contour) if snapped is not None: snapped_points = np.append(snapped_points, snapped, axis=0) contour_box = Mask.pointsBox(contour, 4) #if the countour did not intersect with the outer contour, get the mask of the outer contour if snapped_points is None or len(snapped_points) == 0: # not very elegant repeated code... (mask, box) = Mask.jointMask(contour_box, contour_box) origin = np.array([box[1], box[0]]) contour_points = contour.round().astype(int) fillPoly(mask, pts=[contour_points - origin], color=(1)) return (mask, box, False) points_box = Mask.pointsBox(snapped_points, 4) # create a mask large enough to accomodate the points and the contour and paint. (mask, box) = Mask.jointMask(contour_box, points_box) origin = np.array([box[1], box[0]]) contour_points = contour.round().astype(int) fillPoly(mask, pts=[contour_points - origin], color=(1, 1, 1)) Mask.paintPoints(mask, box, snapped_points, 1) mask = ndi.binary_fill_holes(mask) # now draw in black the part of the points inside the contour Mask.paintPoints(mask, box, snapped_points, 0) # now we label all the parts and keep the larges only regions = measure.regionprops(measure.label(mask, connectivity=1)) largest = max(regions, key=lambda region: region.area) # adjust the image bounding box (relative to the region mask) to directly use area.image mask box = np.array([ box[0] + largest.bbox[0], box[1] + largest.bbox[1], largest.bbox[3] - largest.bbox[1], largest.bbox[2] - largest.bbox[0] ]) return (largest.image, box, True)
def editBorder(self, blob, lines): #need padding #would be lovely to be able do edit holes too. #the main problem is snapping to the external contour points = blob.lineToPoints(lines, snap=True) if points is None: return if len(points) == 0: return pointsbox = Mask.pointsBox(points, 3) blobmask = blob.getMask() #add to mask painting the points as 1 and filling the holes. (mask, box) = Mask.jointMask(blob.bbox, pointsbox) Mask.paintMask(mask, box, blobmask, blob.bbox, 1) #save holes full = ndi.binary_fill_holes(mask.astype(int)) holes = full & ~mask #cut from mask Mask.paintPoints(mask, box, points, 1) mask = ndi.binary_fill_holes(mask.astype(int)) #erase the points to carve to remove the internal parts. Mask.paintPoints(mask, box, points, 0) #add back holes mask = mask & ~holes regions = measure.regionprops(measure.label(mask)) if len(regions): largest = regions[0] for region in regions: if region.area > largest.area: largest = region #adjust the image bounding box (relative to the region mask) to directly use area.image mask #image box is standard (minx, miny, maxx, maxy) box = np.array([ box[0] + largest.bbox[0], box[1] + largest.bbox[1], largest.bbox[3], largest.bbox[2] ]) blob.updateUsingMask(box, largest.image.astype(int))
def addingIntersection(self, blobA, blobB, blobC): """ Update the blobA by adding to it the intersection between the blobB and the blobC """ mask_intersect, bbox_intersect = Mask.intersectMask( blobB.getMask(), blobB.bbox, blobC.getMask(), blobC.bbox) bbox = Mask.jointBox([blobA.bbox, bbox_intersect]) (mask, bbox) = Mask.jointMask(bbox, bbox) Mask.paintMask(mask, bbox, blobA.getMask(), blobA.bbox, 1) Mask.paintMask(mask, bbox, mask_intersect, bbox_intersect, 1) if mask.any(): blobA.updateUsingMask(bbox, mask.astype(int))
def createFromClosedCurve(self, lines): """ It creates a blob starting from a closed curve. If the curve is not closed False is returned. If the curve intersect itself many times the first segmented region is created. """ points = self.lineToPoints(lines) box = Mask.pointsBox(points, 4) (mask, box) = Mask.jointMask(box, box) Mask.paintPoints(mask, box, points, 1) mask = ndi.binary_fill_holes(mask) mask = binary_erosion(mask) mask = binary_dilation(mask) self.updateUsingMask(box, mask) return True
def union(self, blobs): """ Create a new blob that is the union of the (two) blobs given """ #boxs are in image space, masks invert x and y. boxes = [] for blob in blobs: boxes.append(blob.bbox) box = Mask.jointBox(boxes) (mask, box) = Mask.jointMask(box, box) for blob in blobs: Mask.paintMask(mask, box, blob.getMask(), blob.bbox, 1) if mask.any(): # measure is brutally slower with non int types (factor 4), while byte&bool would be faster by 25%, conversion is fast. blob = blobs[0].copy() blob.updateUsingMask(box, mask.astype(int)) return blob return None
def createFromClosedCurve(self, lines): """ It creates a blob starting from a closed curve. If the curve is not closed False is returned. If the curve intersect itself many times the first segmented region is created. """ points = self.lineToPoints(lines) box = Mask.pointsBox(points, 4) (mask, box) = Mask.jointMask(box, box) Mask.paintPoints(mask, box, points, 1) before = np.count_nonzero(mask) mask = ndi.binary_fill_holes(mask) after = np.count_nonzero(mask) if before == after: return False selem = np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0]]) mask = binary_erosion(mask, selem) self.updateUsingMask(box, mask) return True