def sym_bbox_from_point(point, bbox_size): """Given a size and a point, the symmetric bounding box around that point is returned. If there is ambiguity due to floats, the result is randomly rounded.""" bbox_size = cast_numpy(bbox_size) point = cast_numpy(point) bbox_coords = prob_round(point - bbox_size / 2.) bbox = _combine_bbox(bbox_coords, bbox_size) return bbox
def _combine_bbox(bbox_coords, bbox_size): """Combine coordinates and size into a bounding box. Parameters: bbox_coords : tuple or ndarray bbox_size : tuple or ndarray Returns ------- bounding box """ bbox_coords = cast_numpy(bbox_coords).astype(int) bbox_size = cast_numpy(bbox_size).astype(int) bbox = tuple(bbox_coords.tolist() + bbox_size.tolist()) return bbox
def _split_bbox(bbox): """Split bbox into coordinates and size Parameters ---------- bbox : tuple or ndarray. Given dimension n, first n coordinates are the starting point, the other n the size. Returns ------- coordinates and size, both ndarrays. """ bbox = cast_numpy(bbox) ndim = int(len(bbox) / 2) bbox_coords = bbox[:ndim] bbox_size = bbox[ndim:] return bbox_coords, bbox_size
def sample_from_mask(mask, avoid, num_tries=100): """A random index is sampled for a mask in the non-zero values. As a first try, num_tries iterations randomly select a point and if found, proceeds. This is more efficient than finding all possible non-zero values which is O(n x m). If this fails within num_tries iterators, we look through all non-positive indices. Otherwise, we look through all possible indexes. Parameters ---------- mask : str or ndarray Path to file containing mask or ndarray. Returns ------- An index sampled within the mask. """ if isinstance(mask, basestring): mask, _ = read_dcm(mask, window_leveling=False, dtype=int) bbox = bounding_box(mask) mask = extract_patch(mask, bbox) i = 0 rand_idx = None while i < num_tries: # We sample up to a part of the edge rand_idx = tuple([ np.random.randint(x, y) for x, y in zip(avoid, mask.shape - avoid) ]) if mask[rand_idx] != 0: break i += 1 # If that didn't work, we unfortunately have to do a full search. # Here we do not try to avoid the edge. if not rand_idx: rand_idx = random_mask_idx(mask) bbox_coords, _ = _split_bbox(bbox) rand_idx = cast_numpy(bbox_coords) idx = tuple(rand_idx + bbox_coords) return idx
def rebuild_bbox(bbox, new_size): """Given a bounding box and a requested size return the new bounding box around the center of the old. If the coordinate would be non-integer, the value is randomly rounded up or down. Parameters ---------- bbox : tuple, list or ndarray new_size : tuple or list Returns ------- New bounding box. """ new_size = cast_numpy(new_size) bbox_coords, bbox_size = _split_bbox(bbox) bbox_center = bbox_coords - bbox_size / 2. new_bbox_coords = prob_round(bbox_center - new_size / 2.) new_bbox = _combine_bbox(new_bbox_coords, new_size) return new_bbox