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 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 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 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 cut(self, blob, lines): """ Given a curve specified as a set of points and a selected blob, the operation cuts it in several separed new blobs """ points = blob.lineToPoints(lines, snap=False) mask = blob.getMask() original = mask.copy() box = blob.bbox #box is y, x, w, h Mask.paintPoints(mask, box, points, 0) label_image = measure.label(mask, connectivity=1) for point in points: x = point[0] - box[1] y = point[1] - box[0] if x <= 0 or y <= 0 or x >= box[2] - 1 or y >= box[3] - 1: continue if original[y][x] == 0: continue largest = 0 largest = max(label_image[y + 1][x], largest) largest = max(label_image[y - 1][x], largest) largest = max(label_image[y][x + 1], largest) largest = max(label_image[y][x - 1], largest) label_image[y][x] = largest area_th = 30 created_blobs = [] first = True for region in measure.regionprops(label_image): if region.area > area_th: b = Blob(region, box[1], box[0], self.progressive_id) self.progressive_id += 1 b.class_color = blob.class_color b.class_name = blob.class_name created_blobs.append(b) return created_blobs
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
def cut(self, blob, lines): """ Given a curve specified as a set of points and a selected blob, the operation cuts it in several separed new blobs """ points = blob.lineToPoints(lines) mask = blob.getMask() box = blob.bbox Mask.paintPoints(mask, box, points, 0) label_image = measure.label(mask) area_th = 30 created_blobs = [] for region in measure.regionprops(label_image): if region.area > area_th: id = len(self.seg_blobs) b = Blob(region, box[1], box[0], id + 1) b.class_color = blob.class_color b.class_name = blob.class_name created_blobs.append(b) return created_blobs