def detect_rough_cells(img, max_perc_contrast=97): def fill_holes(img): seed = np.copy(img) seed[1:-1, 1:-1] = img.max() strel = sk.morphology.square(3, dtype=bool) img_filled = sk.morphology.reconstruction(seed, img, selem=strel, method='erosion') img_filled = img_filled.astype(bool) return img_filled max_val = np.percentile(img, max_perc_contrast) img_contrast = sk.exposure.rescale_intensity(img, in_range=(0, max_val)) img_median = mh.median_filter(img_contrast, Bc=np.ones((2, 2))) img_edges = sk.filters.sobel(img_contrast) T_otsu = sk.filters.threshold_otsu(img_edges) img_otsu = img_edges > T_otsu img_close = morph.binary_closing(img_otsu, structure=np.ones((3, 3)), iterations=6) img_filled = fill_holes(img_close) img_open = morph.binary_opening(img_filled, structure=np.ones((3, 3)), iterations=2) cell_masks = morph.binary_dilation(img_open, structure=np.ones((9, 1))) return cell_masks
def optic_disk_detect_3(img): ''' Method that seems to work well with DIARETDB1 database. ''' hsi = rgb_to_hsi(img) intensity = hsi[:, :, 2].copy() #plt.axis('off'); show_image(intensity) #i_sp = add_salt_and_pepper(intensity, 0.005) i_med = mh.median_filter(intensity) # use Wiener filter instead? i_clahe = skimage.exposure.equalize_adapthist(i_med) #plt.axis('off'); show_image(i_clahe) seeds = (i_clahe > 0.85) seeds = skimage.morphology.remove_small_objects(seeds, min_size=300, connectivity=2) #plt.axis('off'); show_image(seeds) optic_disk_map = region_growing_1(i_clahe, radius=3, tol1=0.1, tol2=0.2, tol3=0.2, seeds=seeds) optic_disk_map += 1 #plt.axis('off'); show_image(optic_disk_map) _cl_areas = cl_areas(optic_disk_map) print _cl_areas optic_disk_map = leave_segments_by_mask(optic_disk_map, (8000 < _cl_areas) & (_cl_areas < 30000)) #optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=500, connectivity=2) optic_disk_map = mh.close_holes(mh.close(optic_disk_map, Bc=np.ones((10, 10)))) #optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=5000, connectivity=2) if np.all(optic_disk_map == 0): print 'Disk not found' return optic_disk_map
def optic_disk_detect_2(img): hsi = rgb_to_hsi(img) intensity = hsi[:, :, 2].copy() i_sp = add_salt_and_pepper(intensity, 0.005) i_med = mh.median_filter(i_sp) i_clahe = skimage.exposure.equalize_adapthist(i_med) optic_disk_map = (i_clahe > 0.6) & (hsi[:, :, 1] < 0.3) #show_image(optic_disk_map) optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=500, connectivity=2) optic_disk_map = mh.close_holes(mh.close(optic_disk_map, Bc=np.ones((30, 30)))) optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=10000, connectivity=2) if np.all(optic_disk_map == 0): print 'Disk not found' return optic_disk_map
def exudates_get_features_3(folder, elements_folder, fundus_mask, num_imgs=10, stride_width=6): thr_high = 189.0 / 255.0 y = [] pxl_df = pd.DataFrame(columns=['hue', 'intensity', 'mean intensity', 'std intensity', 'dist to optic disk']) for img_fn in image_names_in_folder(folder)[:num_imgs]: print 'Image filename:', img_fn img = load_image(img_fn) short_fn = os.path.split(img_fn)[-1] hard_exud = load_image(os.path.join(elements_folder, short_fn)) hsi = rgb_to_hsi(img) intensity = hsi[:, :, 2].copy() #i_sp = add_salt_and_pepper(intensity, 0.005) i_med = mh.median_filter(intensity) # use Wiener filter instead? i_clahe = skimage.exposure.equalize_adapthist(i_med) optic_disk_map = optic_disk_detect_3(img) mask, optic_disk_center = optic_disk_mask(optic_disk_map, return_center=True) print 'Disk center: ', optic_disk_center fundus_wo_disk_mask = fundus_mask & (~mask) pxl_mask = np.zeros_like(i_clahe, dtype=np.bool) pxl_mask[::stride_width, ::stride_width] = True pxl_mask[~fundus_wo_disk_mask] = False bbox = bounding_box(hard_exud >= thr_high, bbox_radius_ratio=2) pxl_mask &= bbox cur_pxl_df = pd.DataFrame(columns=['hue', 'intensity', 'mean intensity', 'std intensity', 'dist to optic disk']) cur_pxl_df['hue'] = hsi[:, :, 0][pxl_mask].ravel() cur_pxl_df['intensity'] = i_clahe[pxl_mask].ravel() cur_pxl_df['mean intensity'] = pf.pxls_mean_intensity(i_clahe, stride_width, neighbd_rad=7, mask=pxl_mask).ravel() cur_pxl_df['std intensity'] = pf.pxls_std_intensity(i_clahe, stride_width, neighbd_rad=3, mask=pxl_mask).ravel() cur_pxl_df['dist to optic disk'] = pf.pxls_dist_to_pnt(i_clahe.shape, optic_disk_center, stride_width, mask=pxl_mask).ravel() print 'Accounted pixels: ', len(cur_pxl_df) y.append(hard_exud[pxl_mask]) # we can use fraction of white points in a neighborhood instead, # but it becomes regression task then pxl_df = pd.concat((pxl_df, cur_pxl_df), axis=0, ignore_index=True) y = np.hstack(y) y = y >= thr_high return pxl_df, y
def hemorrhages_detect_2(img): moat = moat_operator(img, sigma=5.0) #show_image(moat); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/1.png') m_clahe = skimage.exposure.equalize_adapthist(moat) m_med = mh.median_filter(m_clahe, Bc=np.ones((5, 5))) #show_image(m_med); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/2.png') threshold_global_otsu = skimage.filters.threshold_otsu(m_med) print 'Otsu threshold:', threshold_global_otsu segmented = m_med <= 0.9 * threshold_global_otsu #show_image(segmented); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/3.png') segm_label = skimage.measure.label(segmented) segm_eccen = np.array(map(attrgetter('eccentricity'), skimage.measure.regionprops(segm_label + 1))) segm_area = cl_areas(segm_label) #segm_circ = cf.cl_circularity(segm_label) segm_filtered = leave_segments_by_mask(segm_label, (segm_eccen < 0.85) & (10 < segm_area) & (segm_area < 30000), replace_value=0) != 0 return segm_filtered
def hemorrhages_get_features_5(img, moat, fundus_mask): m_clahe = skimage.exposure.equalize_adapthist(moat) m_med = mh.median_filter(m_clahe, Bc=np.ones((5, 5))) #seeds_1 = m_med < threshold #minima = pf.local_minima(m_med, stride_width=5, neighbd_rad=20, mask=fundus_mask) #minima &= fundus_mask & (m_med < threshold) #show_image(seeds_2, fig_size=(7, 7)) #label = region_growing_1(m_med, radius=1, tol1=0.01, tol2=0.01, tol3=0.01, seeds=minima) + 1 threshold_global_otsu = skimage.filters.threshold_otsu(m_med) cand = m_med <= 0.95 * threshold_global_otsu # erase vessels label = skimage.measure.label(cand) n_clusters = label.max() + 1 features_df = pd.DataFrame(columns=['circularity', 'eccentricity', 'std intensity', 'mean red', 'mean green'], index=np.arange(n_clusters)) areas = cl_areas(label) features_df['area'] = areas.astype(np.float64) features_df['circularity'] = cl_circularity(label) #features_df['eccentricity'] = cl_eccentricity(label) features_df['eccentricity'] = map(attrgetter('eccentricity'), skimage.measure.regionprops(label + 1)) intensity = img.sum(axis=2) / 3.0 i_clahe = skimage.exposure.equalize_adapthist(intensity) r_clahe = skimage.exposure.equalize_adapthist(img[:, :, 0]) g_clahe = skimage.exposure.equalize_adapthist(img[:, :, 1]) # perform median filtering on i_clahe and r_clahe? for i in xrange(n_clusters): cl_map = (label == i) if cl_map.sum() == 0: features_df.ix[i, 'std intensity'] = 0 features_df.ix[i, 'mean red'] = 0 features_df.ix[i, 'mean green'] = 0 else: features_df.ix[i, 'std intensity'] = i_clahe[cl_map].std() features_df.ix[i, 'mean red'] = r_clahe[cl_map].mean() features_df.ix[i, 'mean green'] = g_clahe[cl_map].mean() features_df = features_df.loc[(areas != 0) & \ (areas < 80000), :] return label, features_df
def hemorrhages_detect(img): moat = moat_operator(img, sigma=5.0) show_image(moat); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/1.png') m_clahe = skimage.exposure.equalize_adapthist(moat) m_med = mh.median_filter(m_clahe, Bc=np.ones((5, 5))) show_image(m_med); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/2.png') threshold_global_otsu = skimage.filters.threshold_otsu(m_med) print 'Otsu threshold:', threshold_global_otsu segmented = m_med <= 0.9 * threshold_global_otsu show_image(segmented); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/3.png') #vessels = od.detect_vessels_3(img) vessels = detect_vessels_3(m_med, one_channel_img=True, gabor_perc=88.0) vessels = skimage.morphology.remove_small_objects(vessels, min_size=150) segmented[mh.dilate(vessels, Bc=np.ones((10, 10)))] = False show_image(segmented); plt.axis('off'); plt.savefig('../presentation/pics/hemorrhages/4.png') segm_label = skimage.measure.label(segmented) segm_eccen = np.array(map(attrgetter('eccentricity'), skimage.measure.regionprops(segm_label + 1))) segm_area = cl_areas(segm_label) #segm_circ = cf.cl_circularity(segm_label) segm_filtered = leave_segments_by_mask(segm_label, (segm_eccen < 0.85) & (segm_area < 30000), replace_value=0) != 0 return segm_filtered
def detect_vessels_3(img, sigma=16, gabor_perc=95.0, one_channel_img=False): # Preprocessing if one_channel_img: intensity = img.copy() else: intensity = img.mean(axis=2) / 256.0 show_image(intensity); plt.axis('off'); plt.savefig('../presentation/pics/vessels/1.png') intensity = skimage.exposure.equalize_adapthist(intensity) intensity -= mh.median_filter(intensity, Bc=np.ones((25, 25))) show_image(intensity); plt.axis('off'); plt.savefig('../presentation/pics/vessels/2.png') intensity = normalize_image(intensity) intensity_inv = 1.0 - intensity show_image(intensity_inv); plt.axis('off'); plt.savefig('../presentation/pics/vessels/3.png') vessels = modified_gabor_convolve(intensity_inv, sigma) show_image(vessels); plt.axis('off'); plt.savefig('../presentation/pics/vessels/4.png') # Thresholding result gabor_thresholded = vessels > np.percentile(vessels.ravel(), gabor_perc) gabor_thresholded = skimage.morphology.remove_small_objects(gabor_thresholded, min_size=200) show_image(gabor_thresholded); plt.axis('off'); plt.savefig('../presentation/pics/vessels/5.png') return gabor_thresholded
def hemorrhages_get_features_4(img, fundus_mask, threshold=0.25): green = img[:, :, 1] g_clahe = skimage.exposure.equalize_adapthist(green) g_med = mh.median_filter(g_clahe, Bc=np.ones((5, 5))) #cand = g_med < threshold #label = skimage.measure.label(cand) seeds_1 = g_med < threshold #seeds_2 = pf.local_minima(g_med, stride_width=5, neighbd_rad=4, mask=seeds_1 & fundus_mask) #show_image(seeds_2, fig_size=(7, 7)) #label = region_growing_1(g_med, radius=1, tol1=0.05, tol2=0.05, tol3=0.05, seeds=seeds_2) + 1 label = skimage.measure.label(seeds_1) n_clusters = label.max() + 1 features_df = pd.DataFrame(columns=['area', 'circularity', 'eccentricity', 'std intensity', 'mean red', 'mean green'], index=np.arange(n_clusters)) features_df['area'] = cl_areas(label) features_df['circularity'] = cl_circularity(label) features_df['eccentricity'] = cl_eccentricity(label) intensity = img.sum(axis=2) / 3.0 i_clahe = skimage.exposure.equalize_adapthist(intensity) r_clahe = skimage.exposure.equalize_adapthist(img[:, :, 0]) # perform median filtering on i_clahe and r_clahe? for i in xrange(n_clusters): cl_map = (label == i) if cl_map.sum() == 0: features_df.ix[i, 'std intensity'] = 0 features_df.ix[i, 'mean red'] = 0 features_df.ix[i, 'mean green'] = 0 else: features_df.ix[i, 'std intensity'] = i_clahe[cl_map].std() features_df.ix[i, 'mean red'] = r_clahe[cl_map].mean() features_df.ix[i, 'mean green'] = g_clahe[cl_map].mean() features_df = features_df.loc[(features_df.area != 0) & \ (features_df.area < 80000), :] return label, features_df
def modified_gabor_convolve(gb, sigma_0=10.0): gb2 = mh.median_filter(gb) gb2 = skimage.exposure.equalize_adapthist(gb2) # Computing response of Gabor filter (real part) at different angles resp = [] n_directions = 7 for theta in np.linspace(0.0, np.pi, num=n_directions): #for factor in [0.25, 0.5, 0.75, 1.0]: #sigma = sigma_0 * factor s = sigma_0 kernel = modified_gabor_kernel(radius=20, _lambda=np.sqrt(2 * np.log(2) / np.pi), theta=theta, phi=np.pi, s=s, alpha=1.25, beta=0.75, kappa=0.85, n_directions=n_directions) resp.append(ndi.convolve(gb2, kernel, mode='wrap')) resp = np.array(resp) resp_abs_argmax = np.argmax(np.abs(resp), axis=0) response = np.empty_like(gb2) for k in xrange(resp.shape[0]): response = np.where(resp_abs_argmax == k, resp[k], response) return response
def main(image, filter_name, filter_size, plot=False): '''Smoothes (blurs) `image`. Parameters ---------- image: numpy.ndarray grayscale image that should be smoothed filter_name: str name of the filter kernel that should be applied (options: ``{"avarage", "gaussian", "median", "bilateral"}``) filter_size: int size of the kernel plot: bool, optional whether a plot should be generated (default: ``False``) Returns ------- jtmodules.smooth.Output[Union[numpy.ndarray, str]] Raises ------ ValueError when `filter_name` is not ``"avarage"``, ``"gaussian"``, ``"median"`` or ``"bilateral"`` ''' se = np.ones((filter_size, filter_size)) if filter_name == 'average': logger.info('apply "average" filter') smoothed_image = mh.mean_filter(image, se) elif filter_name == 'gaussian': logger.info('apply "gaussian" filter') smoothed_image = mh.gaussian_filter(image, filter_size) elif filter_name == 'median': logger.info('apply "median" filter') smoothed_image = mh.median_filter(image, se) elif filter_name == 'bilateral': smoothed_image = cv2.bilateralFilter( image.astype(np.float32), d=0, sigmaColor=filter_size, sigmaSpace=filter_size ).astype(image.dtype) else: raise ValueError( 'Arugment "filter_name" can be one of the following:\n' '"average", "gaussian", "median" or "bilateral"' ) smoothed_image = smoothed_image.astype(image.dtype) if plot: logger.info('create plot') from jtlib import plotting clip_value = np.percentile(image, 99.99) data = [ plotting.create_intensity_image_plot( image, 'ul', clip=True, clip_value=clip_value ), plotting.create_intensity_image_plot( smoothed_image, 'ur', clip=True, clip_value=clip_value ), ] figure = plotting.create_figure( data, title='Smoothed with "{0}" filter (kernel size: {1})'.format( filter_name, filter_size ) ) else: figure = str() return Output(smoothed_image, figure)
def extract_connected_components_phase(img, cell_masks=[], flip_cells=False, cut_from_bottom=0, above_cell_pad=0, init_smooth_sigma=3, init_niblack_window_size=13, init_niblack_k=-0.35, maxima_smooth_sigma=2, maxima_niblack_window_size=13, maxima_niblack_k=-0.45, min_cell_size=30, max_perc_contrast=97, return_all=False): # makes it directly compatible with fluorescense visualizations (just inverts black and white) init_niblack_k = -1 * init_niblack_k maxima_niblack_k = -1 * maxima_niblack_k def perform_watershed(threshed, maxima): distances = mh.stretch(mh.distance(threshed)) spots, n_spots = mh.label(maxima, Bc=np.ones((3, 3))) surface = (distances.max() - distances) return sk.morphology.watershed(surface, spots, mask=threshed) def findCells(img, mask, sigma, window_size, niblack_k): img_smooth = img if sigma > 0: img_smooth = sk.filters.gaussian(img, sigma=sigma, preserve_range=True, mode='reflect') thresh_niblack = sk.filters.threshold_niblack(img_smooth, window_size=window_size, k=niblack_k) threshed = img > thresh_niblack threshed = sk.util.invert(threshed) threshed = threshed * mask return threshed def findWatershedMaxima(img, mask): maxima = findCells(img, mask, maxima_smooth_sigma, maxima_niblack_window_size, maxima_niblack_k) # maxima = mh.erode(maxima,Bc=np.ones((7,5))) #Initial # maxima = mh.erode(maxima,Bc=np.ones((5,3))) reg_props = sk.measure.regionprops( sk.measure.label(maxima, neighbors=4)) # make sure that in case there is more than one region, we grab the largest region rp_area = [r.area for r in reg_props] med_size = np.median(rp_area) std_size = np.std(rp_area) cutoff_size = int(max(0, med_size / 6)) maxima = sk.morphology.remove_small_objects(maxima, min_size=cutoff_size) return maxima def findWatershedMask(img, mask): img_mask = findCells(img, mask, init_smooth_sigma, init_niblack_window_size, init_niblack_k) img_mask = mh.dilate(mh.dilate(img_mask), Bc=np.ones((1, 3), dtype=np.bool)) img_mask = sk.morphology.remove_small_objects(img_mask, min_size=4) return img_mask if len(cell_masks) == 0: cell_masks = detect_cells(img, flip_cells=flip_cells, max_perc_contrast=max_perc_contrast, cut_from_bottom=cut_from_bottom, above_cell_pad=above_cell_pad) img_median = mh.median_filter(img, Bc=np.ones((3, 3))) img_mask = findWatershedMask(img_median, cell_masks) maxima = findWatershedMaxima(img_median, img_mask) conn_comp = perform_watershed(img_mask, maxima) # re-label in case regions are split during multiplication conn_comp = sk.measure.label(conn_comp, neighbors=4) conn_comp = sk.morphology.remove_small_objects(conn_comp, min_size=min_cell_size) if return_all: return conn_comp, cell_masks, img_mask, maxima else: return conn_comp
def hemorrhages_detect_3(img, fundus_mask, clf, stride_width=6): #thr_high = 189.0 / 255.0 #img = imh.load_image(img_fn) #short_fn = os.path.split(img_fn)[-1] #hard_exud = imh.load_image(os.path.join(hard_exud_folder, short_fn)) hsi = rgb_to_hsi(img) intensity = hsi[:, :, 2].copy() #i_sp = add_salt_and_pepper(intensity, 0.005) i_med = mh.median_filter(intensity) # use Wiener filter instead? i_clahe = skimage.exposure.equalize_adapthist(i_med) optic_disk_map = optic_disk_detect_3(img) mask, optic_disk_center = optic_disk_mask(optic_disk_map, return_center=True) #print 'Disk center: ', optic_disk_center fundus_wo_disk_mask = fundus_mask & (~mask) pxl_mask = np.zeros_like(i_clahe, dtype=np.bool) pxl_mask[::stride_width, ::stride_width] = True pxl_mask[~fundus_wo_disk_mask] = False cur_pxl_df = pd.DataFrame(columns=['hue', 'saturation', 'intensity', 'mean intensity', 'std intensity']) cur_pxl_df['hue'] = hsi[:, :, 0][::stride_width, ::stride_width].ravel() cur_pxl_df['saturation'] = hsi[:, :, 1][::stride_width, ::stride_width].ravel() cur_pxl_df['intensity'] = i_clahe[::stride_width, ::stride_width].ravel() cur_pxl_df['mean intensity'] = pf.pxls_mean_intensity(i_clahe, stride_width, neighbd_rad=3).ravel() cur_pxl_df['std intensity'] = pf.pxls_std_intensity(i_clahe, stride_width, neighbd_rad=7).ravel() print 'Accounted pixels: ', len(cur_pxl_df) scaler = sklearn.preprocessing.StandardScaler() cur_pxl_df_scaled = scaler.fit_transform(cur_pxl_df) pred = clf.predict(cur_pxl_df_scaled) ''' pred_map = np.zeros_like(pxl_mask, dtype=np.uint8) k = 0 for i in xrange(pred_map.shape[0]): for j in xrange(pred_map.shape[1]): if pxl_mask[i, j]: pred_map[i, j] = 255 * pred[k] if pred[k]: cv2.circle(pred_map, (i, j), 8, (255, 255, 255)) k += 1 ''' pred_map = pred.reshape(pxl_mask[::stride_width, ::stride_width].shape) show_image(pred_map) pred_map &= pxl_mask[::stride_width, ::stride_width] pred_map_full = np.zeros_like(pxl_mask, dtype=np.uint8) pred_map_full[::stride_width, ::stride_width] = pred_map pred_map_full_enl = np.zeros_like(pred_map_full, dtype=np.uint8) for i in xrange(pred_map_full.shape[0]): for j in xrange(pred_map_full.shape[1]): if pred_map_full[i, j]: #cv2.circle(pred_map_full_enl, (i, j), 3, (255, 255, 255)) sz = stride_width pred_map_full_enl[i - sz + 1:i + sz, j - sz + 1:j + sz] = 1 return pred_map_full_enl