def load_image_annot_compute_features_labels(idx_row, params, show_debug_imgs=SHOW_DEBUG_IMAGES ): """ load image and annotation, and compute superpixel features and labels :param (int, {...}) idx_row: row from table with paths :param {str: ...} params: segmentation parameters :param bool show_debug_imgs: whether show debug images :return (...): """ def path_out_img(params, dir_name, name): return os.path.join(params['path_exp'], dir_name, name + '.png') idx, row = idx_row idx_name = get_idx_name(idx, row['path_image']) img = load_image(row['path_image'], params['img_type']) annot = load_image(row['path_annot'], 'segm') logging.debug('.. processing: %s', idx_name) assert img.shape[:2] == annot.shape[:2], \ 'individual size of image %s and seg_pipe %s for "%s" - "%s"' % \ (repr(img.shape), repr(annot.shape), row['path_image'], row['path_annot']) if show_debug_imgs: plt.imsave(path_out_img(params, FOLDER_IMAGE, idx_name), img, cmap=plt.cm.gray) plt.imsave(path_out_img(params, FOLDER_ANNOT, idx_name), annot) # duplicate gray band to be as rgb # if img.ndim == 2: # img = np.rollaxis(np.tile(img, (3, 1, 1)), 0, 3) slic = seg_spx.segment_slic_img2d(img, sp_size=params['slic_size'], rltv_compact=params['slic_regul']) img = seg_pipe.convert_img_color_space(img, params.get('clr_space', 'rgb')) logging.debug('computed SLIC with %i labels', slic.max()) if show_debug_imgs: img_slic = segmentation.mark_boundaries(img / float(img.max()), slic, color=(1, 0, 0), mode='subpixel') plt.imsave(path_out_img(params, FOLDER_SLIC, idx_name), img_slic) features, ft_names = seg_fts.compute_selected_features_img2d( img, slic, params['features']) label_hist = seg_label.histogram_regions_labels_norm(slic, annot) labels = np.argmax(label_hist, axis=1) slic_annot = labels[slic] if show_debug_imgs: plt.imsave(path_out_img(params, FOLDER_SLIC_ANNOT, idx_name), slic_annot) return idx_name, img, annot, slic, features, labels, label_hist, ft_names
def compute_color2d_superpixels_features(image, clr_space='rgb', sp_size=30, sp_regul=0.2, dict_features=FTS_SET_SIMPLE, fts_norm=True): """ segment image into superpixels and estimate features per superpixel :param ndarray image: input RGB image :param str clr_space: chose the color space :param int sp_size: initial size of a superpixel(meaning edge lenght) :param float sp_regul: regularisation in range(0;1) where "0" gives elastic and "1" nearly square segments :param {str: [str]} dict_features: list of features to be extracted :param bool fts_norm: weather nomalise features :return [[int]], [[floats]]: superpixels and related of features """ assert sp_regul > 0., 'slic. regularisation must be positive' logging.debug('run Superpixel clustering.') slic = seg_sp.segment_slic_img2d(image, sp_size=sp_size, rltv_compact=sp_regul) # plt.figure(), plt.imshow(slic) logging.debug('extract slic/superpixels features.') image = convert_img_color_space(image, clr_space) features, _ = seg_fts.compute_selected_features_img2d( image, slic, dict_features) logging.debug('list of features RAW: %s', repr(features.shape)) features[np.isnan(features)] = 0 if fts_norm: logging.debug('norm all features.') features, _ = seg_fts.norm_features(features) logging.debug('list of features NORM: %s', repr(features.shape)) return slic, features
def compute_edge_weights(segments, image=None, features=None, proba=None, edge_type=''): """ pp 32, http://www.coe.utah.edu/~cs7640/readings/graph_cuts_intro.pdf exp(- norm value diff) * (geom dist vertex)**-1 :param ndarry segments: superpixels :param ndarry image: input image :param ndarry features: features for each segment (superpixel) :param ndarry proba: probability of each superpixel and class :param str edge_type: contains edge type, if 'model', after '_' you can specify the metric, eg. 'model_l2' :return [[int, int]], [float]: >>> segments = np.array([[0] * 3 + [1] * 5 + [2] * 4, ... [4] * 4 + [5] * 5 + [6] * 3]) >>> np.random.seed(0) >>> img = np.random.random(segments.shape + (3,)) * 255 >>> features = np.random.random((segments.max() + 1, 15)) * 10 >>> proba = np.random.random((segments.max() + 1, 2)) >>> edges, weights = compute_edge_weights(segments) >>> edges.tolist() [[0, 1], [1, 2], [0, 4], [1, 4], [1, 5], [2, 5], [4, 5], [2, 6], [5, 6]] >>> np.round(weights, 2).tolist() [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] >>> edges, weights = compute_edge_weights(segments, image=img, ... edge_type='spatial') >>> np.round(weights, 3).tolist() [0.776, 0.69, 2.776, 0.853, 2.194, 0.853, 0.69, 2.776, 0.776] >>> edges, weights = compute_edge_weights(segments, image=img, ... edge_type='color') >>> np.round(weights, 3).tolist() [0.06, 0.002, 0.0, 0.0, 0.0, 0.009, 0.0, 0.019, 0.044] >>> edges, weights = compute_edge_weights(segments, features=features, ... edge_type='features') >>> np.round(weights, 3).tolist() [0.031, 0.005, 0.051, 0.032, 0.096, 0.013, 0.018, 0.033, 0.013] >>> edges, weights = compute_edge_weights(segments, proba=proba, ... edge_type='model') >>> np.round(weights, 3).tolist() [0.0, 0.028, 1.122, 0.038, 0.117, 0.688, 0.487, 1.152, 0.282] """ logging.debug('extraction segment connectivity...') _, edges = get_vertexes_edges(segments) # convert variables edges = np.array(edges, dtype=np.int32) logging.debug('graph edges %s', repr(edges.shape)) if edge_type.startswith('model'): assert proba is not None metric = edge_type.split('_')[-1] if '_' in edge_type else 'lT' edge_weights = compute_edge_model(edges, proba, metric) elif edge_type == 'color': assert image is not None # {'color': ['mean', 'median']} image_float = np.array(image, dtype=float) if np.max(image) > 1: image_float /= 255. color, _ = seg_fts.compute_selected_features_img2d( image_float, segments, {'color': ['mean']}) vertex_1 = color[edges[:, 0]] vertex_2 = color[edges[:, 1]] dist = metrics.pairwise.paired_manhattan_distances(vertex_1, vertex_2) weights = dist.astype(float) / (2 * np.std(dist)**2) edge_weights = np.exp(-weights) elif edge_type == 'features': assert features is not None features_norm = preprocessing.StandardScaler().fit_transform(features) vertex_1 = features_norm[edges[:, 0]] vertex_2 = features_norm[edges[:, 1]] dist = metrics.pairwise.paired_euclidean_distances(vertex_1, vertex_2) weights = dist.astype(float) / (2 * np.std(dist)**2) edge_weights = np.exp(-weights) else: edge_weights = np.ones(len(edges)) edge_weights = np.array(edge_weights, dtype=float) if edge_type in ['model', 'features', 'color', 'spatial']: centres = seg_spx.superpixel_centers(segments) spatial = compute_spatial_dist(centres, edges, relative=True) edge_weights /= spatial return edges, edge_weights
def segment_image(imgs_idx_path, params, classif, path_out, path_visu=None): """ perform image segmentation on input image with given paramters and trained classifier, and save results :param (int, str) imgs_idx_path: :param {str: ...} params: segmentation parameters :param obj classif: trained classifier :param str path_out: path for output :param str path_visu: the existing patch means export also visualisation :return str, ndarray, ndarray: """ idx, path_img = parse_imgs_idx_path(imgs_idx_path) logging.debug('segmenting image: "%s"', path_img) idx_name = get_idx_name(idx, path_img) img = load_image(path_img, params['img_type']) slic = seg_spx.segment_slic_img2d(img, sp_size=params['slic_size'], rltv_compact=params['slic_regul']) img = seg_pipe.convert_img_color_space(img, params.get('clr_space', 'rgb')) features, _ = seg_fts.compute_selected_features_img2d( img, slic, params['features']) labels = classif.predict(features) segm = labels[slic] img_seg = Image.fromarray(segm.astype(np.uint8)) path_img = os.path.join(path_out, idx_name + '.png') logging.debug('export segmentation: %s', path_img) img_seg = Image.fromarray(segm.astype(np.uint8)) img_seg.convert('L').save(path_img) # io.imsave(path_img, segm) # plt.imsave(os.path.join(path_out, idx_name + '_rgb.png'), seg_pipe) if path_visu is not None and os.path.isdir(path_visu): export_draw_image_segm_contour(img, segm, path_visu, idx_name) try: # in case some classiefier do not support predict_proba proba = classif.predict_proba(features) segm_soft = proba[slic] path_npz = os.path.join(path_out, idx_name + '.npz') np.savez_compressed(path_npz, segm_soft) except: logging.warning('classif: %s not support predict_proba(.)', repr(classif)) proba = None segm_soft = None # if probabilities was not estimated of GC regul. is zero if proba is not None and params['gc_regul'] > 0: gc_regul = params['gc_regul'] if params['gc_use_trans']: label_penalty = seg_gc.compute_pairwise_cost_from_transitions( params['label_transitions']) gc_regul = (gc_regul * label_penalty) labels_gc = seg_gc.segment_graph_cut_general( slic, proba, img, features, gc_regul, edge_type=params['gc_edge_type']) # labels_gc = seg_gc.segment_graph_cut_simple(slic, proba, gc_regul) segm_gc = labels_gc[slic] # relabel according classif classes segm_gc = classif.classes_[segm_gc] path_img = os.path.join(path_out, idx_name + '_gc.png') logging.debug('export segmentation: %s', path_img) img_seg_gc = Image.fromarray(segm_gc.astype(np.uint8)) img_seg_gc.convert('L').save(path_img) # io.imsave(path_img, segm_gc) if path_visu is not None and os.path.isdir(path_visu): export_draw_image_segm_contour(img, segm_gc, path_visu, idx_name, '_gc') if SHOW_DEBUG_IMAGES: labels_map = np.argmax(proba, axis=1) plt.imsave(os.path.join(path_visu, idx_name + '_map.png'), labels_map[slic]) if not segm_soft is None: for lb in range(segm_soft.shape[2]): uc_name = idx_name + '_gc_unary-lb%i.png' % lb plt.imsave(os.path.join(path_visu, uc_name), segm_soft[:, :, lb], vmin=0., vmax=1., cmap=plt.cm.Greens) else: segm_gc = np.zeros(segm.shape) # gc.collect(), time.sleep(1) return idx_name, segm, segm_gc