def test_binary_output_3d(): image = np.zeros((9, 9, 9), np.uint16) image[2:-2, 2:-2, 2:-2] = 2**14 image[3:-3, 3:-3, 3:-3] = 2**15 image[4, 4, 4] = 2**16-1 bin_opened = binary.binary_opening(image) bin_closed = binary.binary_closing(image) int_opened = np.empty_like(image, dtype=np.uint8) int_closed = np.empty_like(image, dtype=np.uint8) binary.binary_opening(image, out=int_opened) binary.binary_closing(image, out=int_closed) testing.assert_equal(bin_opened.dtype, bool) testing.assert_equal(bin_closed.dtype, bool) testing.assert_equal(int_opened.dtype, np.uint8) testing.assert_equal(int_closed.dtype, np.uint8)
def test_binary_output_3d(): image = np.zeros((9, 9, 9), np.uint16) image[2:-2, 2:-2, 2:-2] = 2**14 image[3:-3, 3:-3, 3:-3] = 2**15 image[4, 4, 4] = 2**16-1 bin_opened = binary.binary_opening(image) bin_closed = binary.binary_closing(image) int_opened = np.empty_like(image, dtype=np.uint8) int_closed = np.empty_like(image, dtype=np.uint8) binary.binary_opening(image, out=int_opened) binary.binary_closing(image, out=int_closed) testing.assert_equal(bin_opened.dtype, np.bool) testing.assert_equal(bin_closed.dtype, np.bool) testing.assert_equal(int_opened.dtype, np.uint8) testing.assert_equal(int_closed.dtype, np.uint8)
def test_3d_fallback_default_selem(): # 3x3x3 cube inside a 7x7x7 image: image = np.zeros((7, 7, 7), np.bool) image[2:-2, 2:-2, 2:-2] = 1 opened = binary.binary_opening(image) # expect a "hyper-cross" centered in the 5x5x5: image_expected = np.zeros((7, 7, 7), dtype=bool) image_expected[2:5, 2:5, 2:5] = ndi.generate_binary_structure(3, 1) testing.assert_array_equal(opened, image_expected)
def test_3d_fallback_default_selem(): # 3x3x3 cube inside a 7x7x7 image: image = np.zeros((7, 7, 7), bool) image[2:-2, 2:-2, 2:-2] = 1 opened = binary.binary_opening(image) # expect a "hyper-cross" centered in the 5x5x5: image_expected = np.zeros((7, 7, 7), dtype=bool) image_expected[2:5, 2:5, 2:5] = ndi.generate_binary_structure(3, 1) testing.assert_array_equal(opened, image_expected)
def test_2d_ndimage_equivalence(): image = np.zeros((9, 9), np.uint16) image[2:-2, 2:-2] = 2**14 image[3:-3, 3:-3] = 2**15 image[4, 4] = 2**16-1 bin_opened = binary.binary_opening(image) bin_closed = binary.binary_closing(image) selem = ndi.generate_binary_structure(2, 1) ndimage_opened = ndi.binary_opening(image, structure=selem) ndimage_closed = ndi.binary_closing(image, structure=selem) testing.assert_array_equal(bin_opened, ndimage_opened) testing.assert_array_equal(bin_closed, ndimage_closed)
def test_2d_ndimage_equivalence(): image = np.zeros((9, 9), np.uint16) image[2:-2, 2:-2] = 2**14 image[3:-3, 3:-3] = 2**15 image[4, 4] = 2**16-1 bin_opened = binary.binary_opening(image) bin_closed = binary.binary_closing(image) selem = ndi.generate_binary_structure(2, 1) ndimage_opened = ndi.binary_opening(image, structure=selem) ndimage_closed = ndi.binary_closing(image, structure=selem) testing.assert_array_equal(bin_opened, ndimage_opened) testing.assert_array_equal(bin_closed, ndimage_closed)
def test_binary_opening(): strel = selem.square(3) binary_res = binary.binary_opening(bw_img, strel) grey_res = img_as_bool(grey.opening(bw_img, strel)) testing.assert_array_equal(binary_res, grey_res)
def test_binary_opening(): strel = selem.square(3) binary_res = binary.binary_opening(bw_img, strel) gray_res = img_as_bool(gray.opening(bw_img, strel)) testing.assert_array_equal(binary_res, gray_res)
def threshold_channels(channels: List[np.ndarray], main_channel: int = 2, iterations: int = 5, mask_size: int = 7, percent_hmax: float = 0.05, local_threshold_multiplier: int = 8, maximum_size_multiplier: int = 2, size_factor: float = 1.0, analysis_settings: Dict = None) -> List[np.ndarray]: """ Method to threshold the channels to prepare for nuclei and foci detection :param channels: The channels of the image as list :param main_channel: Index of the channel associated with nuclei (usually blue -> 2) :param iterations: Number of maximum filtering to perform in a row :param mask_size: The diameter of the circular mask for the filtering :param percent_hmax: The percentage of the histogram maximum to add to the histogram minimum. Used to form the detection threshold :param local_threshold_multiplier: Multiplier used to increase mask_size for local thresholding :param maximum_size_multiplier: Multiplier used to increase mask_size for noise removal :param size_factor: Factor to accommodate for different image resolutions :param analysis_settings: Settings to use for thresholding :return: The thresholded channels """ if analysis_settings: main_channel = analysis_settings.get("main_channel", main_channel) iterations = analysis_settings.get("thresh_iterations", iterations) mask_size = analysis_settings.get("thresh_mask_size", mask_size) percent_hmax = analysis_settings.get("thresh_percent_hmax", percent_hmax) local_threshold_multiplier = analysis_settings.get("thresh_local_thresh_mult", local_threshold_multiplier) maximum_size_multiplier = analysis_settings.get("thresh_max_mult", maximum_size_multiplier) size_factor = analysis_settings.get("size_factor", size_factor) thresh: List[Union[None, np.ndarray]] = [None] * len(channels) # Calculate the circular mask to use for morphological operators selem = create_circular_mask(mask_size * size_factor, mask_size * size_factor) # Load image orig = channels[main_channel] # Get maximum value of main channel hmax = np.amax(orig) # Get minimum value of main channel hmin = np.amin(orig) # Calculate the used threshold threshold = hmin + round(percent_hmax * hmax) # Threshold channel globally and fill holes ch_main_bin = ndi.binary_fill_holes(orig > threshold) # Calculate the euclidean distance map edm = ndi.distance_transform_edt(ch_main_bin) # Normalize edm xmax, xmin = edm.max(), edm.min() x = img_as_ubyte((edm - xmin) / (xmax - xmin)) # Determine maxima of EDM maxi = maximum(x, selem=selem) # Iteratively determine maximum for _ in range(iterations): maxi = maximum(maxi, selem=selem) # Perform local thresholding thresh_ = threshold_local(maxi, block_size=(mask_size * local_threshold_multiplier + 1) * size_factor) # Threshold maximum EDM maxi = ndi.binary_fill_holes(maxi > thresh_) # Perform logical AND to remove areas that were not detected in ch_main_bin maxi = np.logical_and(maxi, ch_main_bin) # Open maxi to remove noise maxi = binary_opening(maxi, selem=create_circular_mask(mask_size * maximum_size_multiplier * size_factor, mask_size * maximum_size_multiplier * size_factor)) # Extract nuclei from map area, labels = ndi.label(maxi) nucs: List[List, List] = [None] * (labels + 1) for y in range(len(area)): for x in range(len(area[0])): pix = area[y][x] if nucs[pix] is None: nucs[pix] = [[], []] nucs[pix][0].append(y) nucs[pix][1].append(x) # Remove background del nucs[0] # Get nuclei centers centers = [(np.average(x[0]), np.average(x[1])) for x in nucs] # Create mask with marked nuclei centers -> Used as seed points for watershed cmask = np.zeros(shape=orig.shape) ind = 1 for c in centers: cmask[int(c[0])][int(c[1])] = ind ind += 1 # Create watershed segmentation based on centers ws = watershed(-edm, cmask, mask=ch_main_bin, watershed_line=True) # Check number of unique watershed labels unique = list(np.unique(ws)) relabel_array(ws) thresh[main_channel] = ws # Extract nuclei from watershed det: List[Tuple[int, int]] = [None] * len(unique) detpix = [] for y in range(len(ws)): for x in range(len(ws[0])): pix = ws[y][x] if pix not in detpix: detpix.append(pix) if det[pix] is None: det[pix] = [] det[pix].append((y, x)) # Delete background del det[0] # Extract foci from channels for ind in range(len(channels)): if ind != main_channel: thresh[ind] = Detector.calculate_local_region_threshold(det, channels[ind], analysis_settings["canny_sigma"], analysis_settings["canny_low_thresh"], analysis_settings["canny_up_thresh"]) return thresh
def test_binary_opening(): footprint = morphology.square(3) binary_res = binary.binary_opening(bw_img, footprint) gray_res = img_as_bool(gray.opening(bw_img, footprint)) assert_array_equal(binary_res, gray_res)
plt.plot(sum_by_rows) crop = binary_img[125:340, :] plt.figure(4) plt.imshow(crop, cmap='gray') sum_by_cols = np.sum(crop, axis=0) plt.figure(5) plt.plot(sum_by_cols) crop_in_crop1 = crop[:, 200:300] plt.figure(6) plt.imshow(crop_in_crop1, cmap='gray') crop_in_crop2 = crop[:, 400:500] crop_in_crop2 = binary.binary_opening(crop_in_crop2) plt.figure(7) plt.imshow(crop_in_crop2, cmap='gray') graph = [] rows, columns = crop_in_crop2.shape for row in range(rows): for column in range(columns): if crop_in_crop2[row, column] == 1: graph.append(column) break for row in range(rows): for column in range(columns - 1, 0, -1): if crop_in_crop2[row, column] == 1: graph.append(column)
def test_binary_opening(): strel = selem.square(3) binary_res = binary.binary_opening(bw_img, strel) with expected_warnings(['precision loss']): grey_res = img_as_bool(grey.opening(bw_img, strel)) testing.assert_array_equal(binary_res, grey_res)
def test_binary_opening(): strel = selem.square(3) binary_res = binary.binary_opening(bw_lena, strel) grey_res = grey.opening(bw_lena, strel) testing.assert_array_equal(binary_res, grey_res)