def mask_to_geojson(img_mask, label=None, simplify_tol=1.5): """ Args: img_mask (numpy array): numpy data, with each object being assigned with a unique uint number label (str): like 'cell', 'nuclei' simplify_tol (float): give a higher number if you want less coordinates. """ # for img_mask, for cells on border, should make sure on border pixels are # set to 0 shape_x, shape_y = img_mask.shape shape_x, shape_y = shape_x - 1, shape_y - 1 img_mask[0, :] = img_mask[:, 0] = img_mask[shape_x, :] = img_mask[:, shape_y] = 0 features = [] label = label or "cell" # Get all object ids, remove 0 since this is background ind_objs = np.unique(img_mask) ind_objs = np.delete(ind_objs, np.where(ind_objs == 0)) for obj_int in np.nditer(ind_objs): # Create binary mask for current object and find contour img_mask_loop = np.zeros((img_mask.shape[0], img_mask.shape[1])) img_mask_loop[img_mask == obj_int] = 1 contours_find = measure.find_contours(img_mask_loop, 0.5) if len(contours_find) == 1: index = 0 else: pixels = [] for _, item in enumerate(contours_find): pixels.append(len(item)) index = np.argmax(pixels) contour = contours_find[index] contour_as_numpy = contour[:, np.argsort([1, 0])] contour_as_numpy[:, 1] = np.array([img_mask.shape[0] - h[0] for h in contour]) contour_asList = contour_as_numpy.tolist() if simplify_tol is not None: poly_shapely = shapely_polygon(contour_asList) poly_shapely_simple = poly_shapely.simplify( simplify_tol, preserve_topology=False ) contour_asList = list(poly_shapely_simple.exterior.coords) contour_as_Numpy = np.asarray(contour_asList) # Create and append feature for geojson pol_loop = geojson_polygon([contour_asList]) full_label = label + "_idx" index_number = int(obj_int - 1) features.append( Feature( geometry=pol_loop, properties={full_label: index_number, "label": label} ) ) feature_collection = FeatureCollection( features, bbox=[0, 0, img_mask.shape[1] - 1, img_mask.shape[0] - 1] ) return feature_collection
def _convert_mask(img_mask, label=None, simplify_tol=1.5): # for img_mask, for cells on border, should make sure on border pixels are # set to 0 shape_x, shape_y = img_mask.shape shape_x, shape_y = shape_x - 1, shape_y - 1 img_mask[0, :] = img_mask[:, 0] = img_mask[shape_x, :] = img_mask[:, shape_y] = 0 features = [] label = label or "cell" # Get all object ids, remove 0 since this is background ind_objs = np.unique(img_mask) ind_objs = np.delete(ind_objs, np.where(ind_objs == 0)) for obj_int in np.nditer(ind_objs, flags=["zerosize_ok"]): # Create binary mask for current object and find contour img_mask_loop = np.zeros((img_mask.shape[0], img_mask.shape[1])) img_mask_loop[img_mask == obj_int] = 1 contours_find = measure.find_contours(img_mask_loop, 0.5) if len(contours_find) == 1: index = 0 else: pixels = [] for _, item in enumerate(contours_find): pixels.append(len(item)) index = np.argmax(pixels) contour = contours_find[index] contour_as_numpy = contour[:, np.argsort([1, 0])] contour_as_numpy[:, 1] = np.array( [img_mask.shape[0] - h[0] for h in contour]) contour_asList = contour_as_numpy.tolist() if simplify_tol is not None: poly_shapely = shapely_polygon(contour_asList) poly_shapely_simple = poly_shapely.simplify( simplify_tol, preserve_topology=False) contour_asList = list(poly_shapely_simple.exterior.coords) contour_as_Numpy = np.asarray(contour_asList) # Create and append feature for geojson pol_loop = geojson_polygon([contour_asList]) full_label = label + "_idx" index_number = int(obj_int - 1) features.append( Feature(geometry=pol_loop, properties={ full_label: index_number, "label": label })) return features
# Open ROI file roi_dict_complete = read_roi_zip(file_proc) # Simplify dictionary & get size of annotations annot_dict = {} roi_size_all = [] features = [] # For geojson for key_roi, val_roi in roi_dict_complete.items(): # Get coordinates - maybe x and y have to be exchanged pos = np.column_stack((val_roi['y'], val_roi['x'])) # Create and append feature for geojson pol_loop = geojson_polygon(pos.tolist()) features.append(Feature(geometry=pol_loop,properties= {"label": channels_new[file_ch]['name']})) #, properties={"country": "Spain"}) #) # Create geojson feature collection feature_collection = FeatureCollection(features,bbox = [0, 0.0, image_size[0], image_size[1]]) # Save to json file save_name_json = os.path.join(folder_save, channels_new[file_ch]['name'] + '_annotation.json') with open(save_name_json, 'w') as f: dump(feature_collection, f) f.close() # Find and copy raw data renamed with channel identifier img_raw = os.path.join(drive,path,file_base+img_ext) if os.path.isfile(img_raw):
def masks_to_polygon(img_mask, label=None, simplify_tol=0, plot_simplify=False, save_name=None): ''' Find contours with skimage, simplify them (optional), store as geojson: 1. Loops over each detected object, creates a mask and finds it contour 2. Contour can be simplified (reduce the number of points) - uses shapely: https://shapely.readthedocs.io/en/stable/manual.html#object.simplify - will be performed if tolernace simplify_tol is != 0 3. Polygons will be saved in geojson format, which can be read by ImJoys' AnnotationTool. Annotations for one image are stored as one feature collection each annotation is one feature: "type": "Feature", "geometry": {"type": "Polygon","coordinates": [[]]} "properties": null Args: img_mask (2D numpy array): image wiht segmentation masks. Background is 0, each object has a unique pixel value. simplify_tol (float): tolerance for simplification (All points in the simplified object will be within the tolerance distance of the original geometry) No simplification will be performed when set to 0. plot_simplify (Boolean): plot results of simplifcation. Plot will be shown for EACH mask. Use better for debuggin only. save_name (string): full file-name to save GeoJson file. Not file will be saved when None. Returns: contours (List): contains polygon of each object stored as a numpy array. feature_collection : GeoJson feature collection ''' # Prepare list to store polygon coordinates and geojson features features = [] contours = [] Ncells = img_mask.max() # Loop over all masks (except with index 0 which is background) for i, obj_int in enumerate(range(1, Ncells)): # Create binary mask for current object and find contour img_mask_loop = np.zeros((img_mask.shape[0], img_mask.shape[1])) img_mask_loop[img_mask == obj_int] = 1 contour = measure.find_contours(img_mask_loop, 0.5) # Proceeed only if one contour was found if len(contour) == 1: contour_asNumpy = contour[0] contour_asList = contour_asNumpy.tolist() # Simplify polygon if tolerance is set to any value except 0 if simplify_tol != 0: poly_shapely = shapely_polygon(contour_asList) poly_shapely_simple = poly_shapely.simplify( simplify_tol, preserve_topology=False) contour_asList = list(poly_shapely_simple.exterior.coords) contour_asNumpy = np.asarray(contour_asList) if plot_simplify: plot_polygons(poly_shapely, poly_shapely_simple, obj_int) # Append to polygon list contours.append(contour_asNumpy) # Create and append feature for geojson pol_loop = geojson_polygon(contour_asList) features.append( Feature(geometry=pol_loop, properties={"label": label})) #elif len(contour) == 0: # print(f'No contour found for object {obj_int}') #else: # print(f'More than one contour found for object {obj_int}') # Save to json file if save_name: feature_collection = FeatureCollection(features) with open(save_name, 'w') as f: dump(feature_collection, f) f.close() return features, contours
subfolder = file_base.replace(ident_ch1, "") folder_save = os.path.join(drive,path,'_anet',subfolder) create_folder(folder_save) # Open ROI file roi_dict_complete = read_roi_zip(file_proc) features = [] # For geojson for key_roi, val_roi in roi_dict_complete.items(): # Get coordinates - maybe x and y have to be exchanged # pos = np.column_stack((val_roi['y'], val_roi['x'])) pos = np.column_stack((val_roi['x'], [image_size[1] - h for h in val_roi['y']])) # Create and append feature for geojson pol_loop = geojson_polygon([pos.tolist()]) features.append(Feature(geometry=pol_loop,properties= {"label": 'cells'})) #, properties={"country": "Spain"}) #) # Open ROI file roi_dict_complete = read_roi_zip(file_proc.replace(ident_ch1,ident_ch2)) for key_roi, val_roi in roi_dict_complete.items(): # Get coordinates - maybe x and y have to be exchanged # pos = np.column_stack((val_roi['y'], val_roi['x'])) pos = np.column_stack((val_roi['x'], [image_size[1] - h for h in val_roi['y']])) # Create and append feature for geojson pol_loop = geojson_polygon([pos.tolist()]) features.append(Feature(geometry=pol_loop,properties= {"label": 'nuclei'})) #, properties={"country": "Spain"}) #)