Beispiel #1
0
def binarize(image: np.ndarray, holes_threshold: float = 20) -> np.ndarray:
    """
    Binarize image using Sauvola algorithm.

    Parameters
    ----------
    image : np.ndarray
        RGB image to binarize.
    holes_threshold : float, optional
        Pixel areas covering less than the given number of pixels are removed in the process, by default 20.

    Returns
    -------
    binarized : np.ndarray
        Binarized and filtered image.
    """

    # Extract brightness channel from HSV-converted image
    image_gray = rgb2hsv(image)[:,:,2]

    # Enhance contrast
    image_gray = equalize_adapthist(image_gray, kernel_size=100)

    # Threshold using Sauvola algorithm
    thresh_sauvola = threshold_sauvola(image_gray, window_size=51, k=0.25)
    binary_sauvola = image_gray > thresh_sauvola

    # Remove small objects
    binary_cleaned = 1.0 * remove_small_holes(binary_sauvola, area_threshold=holes_threshold)

    # Remove thick black border (introduced during thresholding)
    binary_cleaned = flood_fill(binary_cleaned, (0, 0), 0)
    binary_cleaned = flood_fill(binary_cleaned, (0, 0), 1)
    
    return binary_cleaned.astype(np.bool)
Beispiel #2
0
def binarize(image: np.ndarray, holes_threshold: float = 20) -> np.ndarray:
    """
    Binarize image using Sauvola algorithm.

    Parameters
    ----------
    image : np.ndarray
        RGB image to binarize.
    holes_threshold : float, optional
        Pixel areas covering less than the given number of pixels are removed in the process, by default 20.

    Returns
    -------
    binarized : np.ndarray
        Binarized and filtered image.
    """

    # Extract brightness channel from HSV-converted image
    image_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    # Enhance contrast
    clahe = cv2.createCLAHE(clipLimit=0.01, tileGridSize=(256, 256))
    image_eq = clahe.apply(image_gray)

    # Threshold using Sauvola algorithm
    binary_sauvola = cv2.ximgproc.niBlackThreshold(image_eq, 255, k=0.25, blockSize=51, type=cv2.THRESH_BINARY, binarizationMethod=cv2.ximgproc.BINARIZATION_SAUVOLA)

    # Remove small objects
    #binary_cleaned = 1.0 * remove_small_holes(binary_sauvola, area_threshold=holes_threshold)

    # Remove thick black border (introduced during thresholding)
    binary_sauvola = flood_fill(binary_sauvola, (0, 0), 0)
    binary_sauvola = flood_fill(binary_sauvola, (0, 0), 1)

    return binary_sauvola.astype(np.bool)
Beispiel #3
0
def get_tumor_region(tumors, list_of_sequence):
    struct = disk(2)

    res = np.sum(tumors[..., list_of_sequence], axis=2)

    min_value = np.min(res)
    max_value = np.max(res)

    res = (((res - min_value) / (max_value - min_value)) * 255).astype(np.uint8)

    thresh = threshold_otsu(res)
    res_otsu = res > thresh

    #res_otsu = binary_opening(res_otsu, struct)

    label_image = label(res_otsu)
    regions = regionprops(label_image)

    for region in regions:
        if region.eccentricity > 0.9 or region.extent < 0.6 or region.area > 3000 or region.area < 150:
            centroid = tuple(int(x) for x in region.centroid)
            label_image = flood_fill(label_image, centroid, 0)

    label_image[label_image > 0] = 255
    res[label_image == 0] = 0

    l, num = label(label_image, return_num=True)
    if num < 1:
        label_image = label(res_otsu)
        regions = regionprops(label_image)

        for region in regions:
            if region.eccentricity > 0.9 or region.extent < 0.5 or region.area > 3000 or region.area < 150:
                centroid = tuple(int(x) for x in region.centroid)
                label_image = flood_fill(label_image, centroid, 0)

        label_image[label_image > 0] = 255
        res[label_image == 0] = 0

        l, num = label(label_image, return_num=True)

    regions = regionprops(l, intensity_image=res)
    mean_intensity = [x.mean_intensity for x in regions]
    max_intensity = np.max(mean_intensity)
    for index, region in enumerate(regions):
        if region.mean_intensity < max_intensity:
            centroid = tuple(int(x) for x in region.centroid)
            label_image = flood_fill(label_image, centroid, 0)

    area = regionprops(label_image)[0].area

    contour = find_contours(label_image, 0)[0]
    coords_region = approximate_polygon(contour, tolerance=0)

    return coords_region, area, label_image
Beispiel #4
0
def select_atom_starts(mgrid, G, radius):
    '''Given a single channel grid and the atomic radius for that type,
    select initial positions using a weight random selection that treats 
    each disconnected volume of density separately'''
    per_atom_volume = radius**3 * ((2 * np.pi)**1.5)

    mask = G.cpu().numpy().copy()

    #look for islands of density greater than 0.5 (todo: parameterize this threshold?)
    #label each island in mask
    THRESHOLD = 0.5
    values = G.cpu().numpy()
    mask[values >= THRESHOLD] = 1.0
    mask[values < THRESHOLD] = 0

    maxpos = np.unravel_index(mask.argmax(), mask.shape)
    masks = []
    which = -1
    while mask[maxpos] > 0:
        flood_fill(mask, maxpos, which,
                   in_place=True)  #identify and mark the connected region
        maxpos = np.unravel_index(mask.argmax(), mask.shape)
        which -= 1

    for selector in range(-1, which, -1):
        masks.append(mask == selector)

    retcoords = []

    #print("#masks",len(masks))
    for M in masks:
        maskedG = G.cpu().numpy()
        maskedG[~M] = 0
        flatG = maskedG.flatten()
        total = float(flatG.sum())

        if total < .1 * per_atom_volume:
            continue  #should be very conservative given a 0.5 THRESHOLD
        cnt = int(np.ceil(
            total / per_atom_volume))  #pretty sure this can only underestimate
        #counting this way is especially problematic for large molecules that go to the box edge
        if cnt == 0:
            continue

        flatG[flatG > 1.0] = 1.0
        rand = np.random.choice(range(len(flatG)), cnt, False,
                                flatG / flatG.sum())
        gcoords = np.array(np.unravel_index(rand, G.shape)).T
        ccoords = grid_to_xyz(gcoords, mgrid)

        retcoords += list(ccoords)

    #print("coords",len(retcoords))
    return retcoords
Beispiel #5
0
    def Highlight(self, e):
        if e.x() < 0 or e.x() > self.__img.shape[1] or e.y() < 0 or e.y() > self.__img.shape[0]:
            return

        self.__mask = flood_fill(self.__mask, (e.y(), e.x()), 255)

        self.__thirdChannelMask[:, :, 2] = flood_fill(self.__thirdChannelMask[:, :, 2], (e.y(), e.x()), self.__highlightcolor.red())
        self.__thirdChannelMask[:, :, 1] = flood_fill(self.__thirdChannelMask[:, :, 1], (e.y(), e.x()), self.__highlightcolor.green())
        self.__thirdChannelMask[:, :, 0] = flood_fill(self.__thirdChannelMask[:, :, 0], (e.y(), e.x()), self.__highlightcolor.blue())

        img = cv2.addWeighted(self.__img, 1, self.__thirdChannelMask, self.__transparency, 0)
        marc_img = mark_boundaries(img, self.__mask)
        self.open_image(marc_img)
Beispiel #6
0
def get_tumors(sub):
    tumors = np.zeros(sub.shape)
    struct = disk(4)
    for i in range(sub.shape[2]):
        if np.count_nonzero(sub[..., i]) == 0:
            continue
        
        test = binary_opening(sub[..., i], struct)
        label_image = label(test)

        list_of_data = []
        for region in regionprops(label_image):
            data = []
            centroid = tuple(int(x) for x in region.centroid)
            if region.eccentricity < 0.9 and region.extent > 0.5 and region.area < 3600 and region.area > 50:
                data.append(centroid)
                data.append(region.area)
                list_of_data.append(data)
        
        if not list_of_data:
            continue

        centroid = max(list_of_data, key=lambda item:item[1])[0]
        segmented_tumor = flood_fill(label_image, centroid, 255)
        segmented_tumor[segmented_tumor < 255] = 0
        tumors[..., i] = segmented_tumor
    tumors /= 255
    return tumors
Beispiel #7
0
def process_image(test_number, disk_size, bit_row, thresh, bit_row_mul,
                  small_objects_size, space_size, small_objects_size_second):
    struct = disk(disk_size)
    bit_row = test_number.shape[0] // bit_row
    bit_col = test_number.shape[1] // 3
    space = space_size
    struct_dilation = disk(1)

    mask = (test_number[..., 0] < thresh) | (test_number[..., 1] < thresh) | (
        test_number[..., 2] < thresh)
    test_number[mask, :] = 0
    mask = np.any(test_number > 0, axis=2)
    test_number[mask] = 1
    test_number = test_number[..., 0].astype(np.bool)
    test_number[bit_row:bit_row * bit_row_mul, :] = 0
    test_number[:, bit_col:bit_col * 2] = 0
    test_number = clear_border(test_number, space)

    test_number_dilated = binary_dilation(test_number, struct).astype(np.bool)
    test_number_dilated = binary_fill_holes(test_number_dilated).astype(
        np.bool)
    test_number_dilated = remove_small_objects(test_number_dilated,
                                               small_objects_size)

    l = label(test_number_dilated)
    for region in regionprops(l):
        if region.eccentricity < 0.95 or region.extent < 0.63:
            centroid = tuple([int(x) for x in region.centroid])
            l = flood_fill(l, tuple(region.coords[0, :]), 0)

    l[l > 0] = 1
    test_number[l == 0] = 0
    test_number = remove_small_objects(test_number, small_objects_size_second)
    test_number = binary_dilation(test_number, struct_dilation)
    return test_number, test_number_dilated
Beispiel #8
0
def count_ships(path, seg, date_mask):
    struct = disk(2)

    seg = binary_closing(seg, struct).astype(np.bool)
    im = imread(path)
    im = rgba2rgb(im)
    grayscale = rgb2gray(im)

    thresh = threshold_yen(grayscale)
    yen = grayscale > thresh

    eroded = binary_erosion(seg, struct).astype(np.bool)

    grayscale = grayscale > 0.6

    grayscale[(eroded == 0) | (date_mask == 1) | (yen == 0)] = 0

    grayscale[date_mask == 1] = 0
    grayscale = binary_fill_holes(grayscale)
    grayscale = clear_border(grayscale)
    l = label(grayscale)
    for region in regionprops(l):
        if region.area > 100 or region.extent < 0.2:
            grayscale = flood_fill(grayscale, tuple(region.coords[0, :]), 0)

    label_image, num = label(grayscale, return_num=True)
    return num, grayscale
Beispiel #9
0
def imfill(mask, seed_pt='default'):
    '''Fill holes within objects in a binary mask.
    
    Equivalent to matlab's imfill function. seed_pt needs to be a point in 
    the "background" area. All 0 or False pixels directly contiguous with 
    the seed are defined as background, all other pixels are declared foreground.
    Thus any "holes" (0 pixels that are not contiguous with background) are 
    filled in. Conceptually, this is like using the "fill" function in classic
    paint programs to fill the background, and taking all non-background as 
    foreground.
    
    Args:
        mask: ndarray
            Binary mask of n dimensions.
        seed_pt: tuple
            Pixel in mask to use for seeding "background". This is the equi-
            valent of the point you click when filling in paint. If left
            as 'default', uses find_background_point to select point.
    Returns:
        mask_filled: ndarray
            Binary mask filled    
    '''
    if (seed_pt == 'default'):
        # Get a random 0-valued background pixel.
        seed_pt = find_background_point(mask)
    # Flood background from seed point.
    mask_flooded = flood_fill(mask, seed_pt, 1)
    # Set whatever changed (from 0 to 1) from the filling to background;
    # all else is foreground.
    mask_filled = np.where(mask == mask_flooded, 1, 0)
    return mask_filled
Beispiel #10
0
 def __draw(self, pixmap, color):
     img = pixmap.toImage()
     pixels = [
         0 if 0 == img.pixel(x, y) else 1 for y in range(img.height())
         for x in range(img.width())
     ]
     pixels = numpy.array(pixels).reshape(img.height(), img.width())
     #        print(pixels)
     pixels = flood_fill(pixels, (self.Points[0][0], self.Points[0][1]),
                         1,
                         connectivity=1)
     #        print(pixels)
     painter = QtGui.QPainter(pixmap)
     painter.setCompositionMode(QtGui.QPainter.CompositionMode_Source)
     painter.fillRect(img.rect(), QtCore.Qt.transparent)
     painter.drawImage(
         0, 0,
         QtGui.QImage(pixels, img.width(), img.height(),
                      QtGui.QImage.Format_ARGB32))
     for y in range(pixmap.height()):
         for x in range(pixmap.width()):
             painter.setPen(
                 QtGui.QColor.fromRgba(0 if 0 ==
                                       pixels[y][x] else self.Color.rgba()))
             painter.drawPoint(x, y)
     painter.end()
Beispiel #11
0
def get_tumors_post(sub, coords, min_slice, max_slice):
    struct = disk(4)
    tumors = np.zeros(sub.shape)
    for i in range(min_slice - 10, max_slice + 10):
        if np.count_nonzero(sub[..., i]) == 0:
            continue

        test = binary_opening(sub[..., i], struct)
        label_image = label(test)

        list_of_data = []
        for region in regionprops(label_image):
            data = []
            centroid = tuple(int(x) for x in region.centroid)
            if (region.eccentricity < 0.95 and region.extent > 0.45 and region.area < 3600 and region.area > 50
            and np.sum(points_in_poly(region.coords, coords)) > region.area // 2):
                data.append(centroid)
                data.append(region.area)
                list_of_data.append(data)
        
        if not list_of_data:
            continue

        centroid = max(list_of_data, key=lambda item:item[1])[0]
        segmented_tumor = flood_fill(label_image, centroid, 255)
        segmented_tumor[segmented_tumor < 255] = 0
        tumors[..., i] = segmented_tumor
    tumors /= 255
    return tumors
Beispiel #12
0
def get_interior(sdf, i_point, qc=False):
    """
    A function to identify interior points given an interior point specified
    by the user.

    Parameters
    ----------
    sdf : Function
        The signed-distance function for the surface
    i_point : tuple of float
        The physical position of the interior point
    qc : bool
        Display a slice of the segmentation of quality checking purposes
    """

    point_index = get_point_index(i_point, sdf.grid.spacing, sdf.grid.origin)

    flooded = flood_fill(sdf.data, point_index, -np.amin(sdf.data))

    segmented = flooded > -_feps

    # Show a slice of the segmentation for qc
    if qc:
        center = segmented.shape[1]//2
        plt.imshow(segmented[:, center].T, origin='lower')
        plt.colorbar()
        plt.show()

    return np.array(segmented)
    def flood_fill(self, x, y):
        x, y = self.convert_to_limits(x, y)
        tmpmask = np.zeros_like(self.mask().copy()).astype("uint8")
        tmpmask[self.mask()] = 255
        mask = tmpmask.copy()

        mask = flood_fill(mask, (y, x), 255)
        self._set_mask(mask == 255)
        self._update_mask()
Beispiel #14
0
def select_atom_starts(mgrid, G, radius):
    '''Given a single channel grid and the atomic radius for that type,
    select initial positions using a weight random selection that treats 
    each disconnected volume of density separately'''
    per_atom_volume = get_per_atom_volume(radius)

    mask = G.cpu().numpy()
    mask[mask > 0] = 1.0
    maxpos = np.unravel_index(
        mask.argmax(),
        mask.shape)  #mtr22 - do we want to use the mask here or G?
    masks = []
    while mask[maxpos] > 0:  #mtr22 - the only positive values in mask are 1.0
        flood_fill(mask, maxpos, -1,
                   in_place=True)  #identify and mark the connected region
        masks.append(mask == -1)  # save the boolean selctor for this region
        mask[mask == -1] = 0  # remove it from the binary mask
        maxpos = np.unravel_index(mask.argmax(), mask.shape)

    retcoords = []

    for M in masks:
        maskedG = G.cpu().numpy()
        maskedG[~M] = 0
        flatG = maskedG.flatten()
        total = flatG.sum()
        #mtr22 - the next line places at least one atom on each contiguous region,
        # and for generated densities there can be thousands of these
        cnt = int(np.round(
            float(total) /
            per_atom_volume))  #pretty sure this can only underestimate
        #counting this way is especially problematic for large molecules that go to the box edge

        flatG[flatG > 1.0] = 1.0
        rand = np.random.choice(range(len(flatG)), cnt, False,
                                flatG / flatG.sum())
        gcoords = np.array(np.unravel_index(rand, G.shape)).T
        ccoords = grid_to_xyz(gcoords, mgrid)
        #print(total, per_atom_volume, cnt, ccoords.shape)

        retcoords += list(ccoords)

    return retcoords
Beispiel #15
0
    def is_inside(self):
        """去掉中点不在多边形内和太小的多边形.

        Returns
        -------
        type
            Description of returned object.

        """
        if len(self.points) < 30:
            return False
        label = np.zeros(self.shape, dtype="uint8")
        for p in self.points:
            label[p[0]][p[1]] = 1
        flood_fill(label, tuple(self.center), 1, selem=[[0, 1, 0], [1, 1, 1], [0, 1, 0]], in_place=True)

        if label.sum() > label.size / 2:
            return False
        return True
Beispiel #16
0
    def robust_segment_neuron(self,
                              channel: int = 0,
                              seg: float = 6.,
                              step: float = 1.,
                              all_chan_clicks: bool = False):
        """More robust segment routine to attempt to threshold a neuron with the clicks
        as seed positions. Will iteratively rerun until there are a number of pixels in
        the mask (tries to avoid an empty map). Does not use a local threshold. Will 
        instead get the max and min intensities and divide that way.
        
        Keyword Arguments:
            channel {int} -- Neuron channel to segement (default: {0})
            seg {float} -- Number of segments to divide (default: {6.})
            step {float} -- Step to move the segment sizes by (default: {1.})
            all_chan_clicks {bool} -- Use the clicks from all channels when flood filling (default: {False})
        """
        image = self.neurons[channel].copy()

        limage = np.log10(image)
        mmin, mmax = np.min(limage), np.max(limage)
        diff = mmax - mmin

        good = False
        while not good:
            thres = np.max(limage) - (diff / seg)
            mask = limage < thres

            image[mask] = 0
            image[~mask] = 1

            click_chans = [i for i in range(len(self.clicks))
                           ] if all_chan_clicks else [
                               channel,
                           ]

            img_flood = image.copy()
            for seed_chan in click_chans:
                for c in self.clicks[seed_chan]:
                    cc = tuple([int(c1) for c1 in c[::-1]])
                    if img_flood[cc[0], cc[1]] == 1:
                        img_flood = flood_fill(img_flood, cc, 0.5)

            mask = img_flood == 0.5
            img_flood[mask] = 1
            img_flood[~mask] = 0

            img_flood = binary_dilation(img_flood)
            img_flood = ndi.binary_fill_holes(img_flood)

            if np.sum(img_flood) < 20 and seg > 1:
                seg -= step
            else:
                good = True

        return img_flood
Beispiel #17
0
def get_foreground(im):
    im_processed = cv2.Laplacian(im,cv2.CV_8UC1)
    im_processed = denoise(im_processed, h=3)
    #im_processed = cv2.dilate(im_processed,ones((3,3)),iterations=1)
    im_processed = threshold_local(im_processed)
    
    h, w = im.shape[:2]
    seed = (int(h/2),int(w/2))
    #ImageDraw.floodfill(foreground, (h/2-2,w/2-8), 255, border=None, thresh=255)
    foreground = segmentation.flood_fill(im_processed, seed, 255, connectivity=0, tolerance=0, in_place=False)
    
    return foreground
Beispiel #18
0
def generate_sd_field(track_wall_pixels, contained_pixel_position):
    track_pixels = flood_fill(track_wall_pixels, contained_pixel_position, 1, connectivity=1) # fill in the pixels between the track walls

    occupied_pixels = np.where(track_wall_pixels == 1, 0, 1) # prepare pixels for distance transform by making occupied pixels 0 and uoccupied pixels 1
    d_field = np.array(distance_transform_edt(occupied_pixels))

    # negate distances outside of the track walls
    for y, row in enumerate(d_field):
        for x, distance in enumerate(row):
            if track_pixels[y][x] == 0:
                d_field[y][x] = -distance

    return d_field
    def set_nodes(self):
        ori_img = self._skel_img
        node_img = []

        for i, x in enumerate(self._skel_img):
            for j, y in enumerate(x):
                if self._skel_img[i][j] == 0:
                    node_img.append((i, j))
                    self._skel_img = flood_fill(self._skel_img, (i, j),
                                                127,
                                                connectivity=1)

        self._skel_img = ori_img
        self._nodes = node_img
def divide_figures(pic):
    import numpy as np
    from skimage.segmentation import flood, flood_fill

    coords = np.array(np.where(pic != 0))
    ans = []
    while coords.shape[1] != 0:
        seed_point = tuple(coords[:, 0])
        ans.append(flood(pic, seed_point))
        pic = flood_fill(pic, seed_point, 0)

        coords = np.array(np.where(pic != 0))

    return ans
Beispiel #21
0
def fill_inside_contour(cont_img,
                        left,
                        right,
                        dilate,
                        all_components=False):  # foolproof
    no_good_fill = lambda fill, cont: (fill[0, 0] == 255 or np.sum(fill - cont)
                                       < cont.shape[0] * 255)
    filled_cont_img = flood_fill(
        cont_img, (len(left) // 2, left[len(left) // 2] + 2 + dilate * 2), 255)

    # try to find inner points of the ship from the left contour
    y = 0
    while (all_components or no_good_fill(filled_cont_img,
                                          cont_img)) and y < cont_img.shape[0]:
        if not oob(cont_img, left[y] + 2 + dilate * 2, y):
            filled_cont_img = flood_fill(cont_img,
                                         (y, left[y] + 2 + dilate * 2), 255)
            if all_components and not no_good_fill(filled_cont_img, cont_img):
                cont_img = filled_cont_img
        y += 1

    # there is a whole in the outline or nothing has been filled at all
    if filled_cont_img[0,
                       0] == 255 or np.sum(filled_cont_img -
                                           cont_img) < cont_img.shape[0] * 255:
        # just draw line between left and right as an approximation
        lines = [
            draw.line(y, left[y], y, right[y])
            for y in range(cont_img.shape[0]) if right[y] > 0
        ]
        xs = np.concatenate([xs for xs, _ in lines])
        ys = np.concatenate([ys for _, ys in lines])
        cont_img[xs, ys] = 255
    else:
        cont_img = filled_cont_img

    return cont_img
Beispiel #22
0
 def flood_fill(self, event):
     """
     Fills a contour selected by the middle mouse button with the mask.
     """
     if event.widget is self.image_label:
         for i in range(3):
             self.mask[:, :, i] = flood_fill(self.mask[:, :, i],
                                             seed_point=(event.y, event.x),
                                             new_value=255,
                                             tolerance=1)
             self.display_image[:, :,
                                i] = np.where(self.mask[:, :, i] == 255,
                                              255, self.display_image[:, :,
                                                                      i])
         self.update_image()
Beispiel #23
0
def find_acs(kspace):
    '''Start at center of kspace and find largest hyper-rectangle.

    Parameters
    ----------
    kspace : N-D array
        Assume coil_axis is at -1 and currently unpadded.
    '''

    # import matplotlib.pyplot as plt

    # Flood fill from center
    mask = np.abs(kspace[..., 0]) > 0
    ctr = tuple([sh // 2 for sh in kspace.shape[:-1]])
    if mask[ctr] == 0:
        raise ValueError('There is no sample at the center!')
    ACS_val = 2
    region = flood_fill(mask.astype(int),
                        seed_point=ctr,
                        new_value=ACS_val,
                        connectivity=0) == ACS_val

    # plt.imshow(region)
    # plt.show()

    if region.ndim == 2:

        # Find a centered rectangle
        acs, top, bottom = findRectangle2d(region, mask, ctr)

        # plt.imshow(acs)
        # plt.show()

        nc = kspace.shape[-1]
        acs = np.tile(acs[..., None], (1, 1, nc))
        # I'm not sure what I'm doing wrong yet...
        for ii in range(3):
            try:
                calib = kspace[acs].reshape((bottom - top - ii, -1, nc))
                break
            except ValueError:
                pass
        else:
            raise ValueError()
    else:
        raise NotImplementedError()

    return calib
Beispiel #24
0
def fill(lung):
    struct = disk(5)
    test = lung.copy()
    for i in range(lung.shape[2]):
        test[..., i] = binary_fill_holes(lung[..., i])

        label_test, num = label(test[..., i], return_num=True)
        if num != 2:
            continue

        chull = convex_hull_object(test[..., i])
        coords = []
        for contour in find_contours(chull, 0):
            coords.append(approximate_polygon(contour, tolerance=0))
        
        if len(coords) < 2:
            continue

        inverted = np.invert(test[..., i])
        distance = ndi.distance_transform_edt(inverted)
        peaks = peak_local_max(distance, labels=inverted)

        left_peaks = points_in_poly(peaks, coords[0])
        right_peaks = points_in_poly(peaks, coords[1])
        peaks_mask = left_peaks | right_peaks
        peaks = peaks[peaks_mask]
        peak_image = np.zeros(lung[..., i].shape)
        peak_image[peaks[:, 0], peaks[:, 1]] = 1

        if len(peaks == 1):
            peak_image[0, 0] = 1

        markers = ndi.label(peak_image)[0]
        labels = watershed(-distance, markers, mask=inverted)
        labels[labels == 1] = 0

        for region in regionprops(labels):
            centroid = np.asarray([int(x) for x in region.centroid]).reshape(1, 2)
            if ((np.sum(points_in_poly(region.coords, coords[0])) < region.area and
            np.sum(points_in_poly(region.coords, coords[1])) < region.area) or 
            (not points_in_poly(centroid, coords[1]) and not points_in_poly(centroid, coords[1]))):
                centroid = tuple(int(x) for x in region.centroid)
                labels = flood_fill(labels, centroid, 0)

        labels[labels > 0] = 255
        test[..., i][labels > 0] = 255

    return test
Beispiel #25
0
 def fill(self, seed_point, fill_value=3):
     y, x = self.edges.shape
     mask = np.zeros((y, x))
     filled_mask = mask.copy()
     mask[:, :x - 1] = self.edges[:, 1:x]
     mask = mask + self.edges
     mask = mask[1:y - 1, 0:x - 1]
     k = 0
     while int(mask[seed_point]) != 0:
         j, i = seed_point
         i += 1
         k += 1
         if k == 6:
             raise ValueError
     filled_mask[1:y - 1, 0:x - 1] = flood_fill(mask, seed_point,
                                                fill_value)
     return filled_mask[filled_mask > 2]
Beispiel #26
0
    def segment_neuron(self,
                       channel: int = 0,
                       thres: float = 3.25,
                       step: float = 0.5):
        """Create a binary mask of the segmented regions within a neuron that contain the 
        object of interest. This requires clicking information that is used to isolate specific
        regions. 
        
        Keyword Arguments:
            channel {int} -- The neuron channel to perform segmenting against (default: {0})
            thres {float} -- Sigma threshold used for binary masking (default: {3.25})
            channel {int} -- Change in sigma threshold when to many pixels clipped (default: {0.5})
        """
        img = self.neurons[channel].copy()
        clicks = self.clicks[channel]

        d = np.log10(img.flatten())
        dmean = np.mean(d)
        dstd = np.std(d)
        thres = 3.25

        mask = np.log10(img) < (dmean + thres * dstd)
        while np.sum(mask == False) < 10:
            thres -= 0.5
            mask = np.log10(img) < (dmean + thres * dstd)

        img[mask] = 0
        img[~mask] = 1

        # Flood fill to find the appropriate segnents with clicks as seeds
        img_flood = img.copy()
        for c in clicks:
            # Clicks were saved in the (x,y) order. For images arrays they are (y, x)
            cc = tuple([int(c1) for c1 in c[::-1]])
            if img_flood[cc[0], cc[1]] == 1:
                img_flood = flood_fill(img_flood, cc, 0.5)

        mask = img_flood == 0.5
        img_flood[mask] = 1
        img_flood[~mask] = 0

        img_flood = binary_dilation(img_flood)

        img_flood = ndi.binary_fill_holes(img_flood)

        return img_flood
Beispiel #27
0
def fill_region(img, loc, val=None, threshold=0.1, dist='rmse', make_copy=False):
	
	px = img[loc]
	
	if val is None:
		val = px
	
	if dist == 'rmse':
		diff = np.sqrt(((img - px.reshape(1, 1, -1)) ** 2).sum(-1))
	else:
		diff = (np.abs(img - img[loc].reshape(1, 1, -1))).sum(-1)
	
	mask = flood_fill(diff, loc, -1, tolerance=threshold) < 0
	
	if make_copy:
		img = img.copy()
	img[mask] = val
	return img
Beispiel #28
0
def flood_outer_contour(img):

    # use all three channels, flood them separately, AND the results; repeat this for all 4 corners and OR them
    img = img.astype(
        int)  # so when flooding the value can be set to something unique
    corners = [(0, 0), (img.shape[0] - 1, img.shape[1] - 1),
               (0, img.shape[1] - 1), (img.shape[0] - 1, 0)]

    floods = [
        np.bitwise_and.reduce(np.bitwise_and.reduce([
            flood_fill(img, corner + (chan, ), -1) == -1 for chan in range(3)
        ]),
                              axis=-1) for corner in corners
    ]
    cont_img = np.invert(np.bitwise_or.reduce(floods)).astype(np.uint8) * 255

    # TODO return left, right, top, bottom as in outer_contour
    return cont_img, None, None, None, None
Beispiel #29
0
def remove_blobs(lung):
    col = lung.shape[1]
    out_image = np.copy(lung)
    for i in range(lung.shape[2]):

        if np.count_nonzero(lung[..., i]) == 0:
            continue

        filled = (binary_fill_holes(lung[..., i])).astype(np.uint8) * 255
        label_image, num = label(filled, return_num=True)

        if num == 1:
            continue

        max_region_area = 0
        max_region = 0
        second_max_region_area = 0
        second_max_region = 0
        j = 0
        regions = regionprops(label_image)
        for index, region in enumerate(regions):
            if region.area > max_region_area:
                max_region_area = region.area
                max_region = region.coords
                j = index

        del regions[j]

        for region in regions:
            if region.area > second_max_region_area:
                second_max_region_area = region.area
                second_max_region = region.coords

        left = min(np.min(max_region[:, 1]), np.min(second_max_region[:, 1]))
        right = max(np.max(max_region[:, 1]), np.max(second_max_region[:, 1]))
        top = min(np.min(max_region[:, 0]), np.min(second_max_region[:, 0]))
        bottom = max(np.max(max_region[:, 0]), np.max(second_max_region[:, 0]))

        for region in regionprops(label_image):
            if ((region.centroid[1] > (col // 2) - (col // 8) and region.centroid[1] < (col // 2) + (col // 8) and region.area < 1500) or                         region.centroid[0] < top or region.centroid[0] > bottom or region.centroid[1] > right or region.centroid[1] < left) :
                centroid = tuple(int(x) for x in region.centroid)
                label_image = flood_fill(label_image, centroid, 0)
        out_image[..., i][label_image == 0] = 0
    return out_image
Beispiel #30
0
def get_2d_mask_by_contour(img2d):
    mask_to_untouch_boarders = np.zeros(img2d.shape, dtype=int)
    mask_to_untouch_boarders[1:-1, 1:-1] = 1
    img2d = img2d * mask_to_untouch_boarders

    # Find contours at a constant value of 0.8
    contours = measure.find_contours(img2d, 0.8)
    contour = sorted(contours, key=lambda x: len(x))[-1]

    r_mask = np.zeros_like(img2d, dtype='bool')

    # Create a contour image by using the contour coordinates rounded to their nearest integer value
    r_mask[np.round(contour[:, 0]).astype('int'),
           np.round(contour[:, 1]).astype('int')] = 1

    #close contours
    r_mask = binary_dilation(r_mask)

    r_mask = r_mask.astype(int)
    mask = flood_fill(r_mask,
                      seed_point=tuple(np.asarray(r_mask.shape) // 2),
                      new_value=1)
    return mask