def get_metric_val(label_tensor, predict_tensor, thres=0.5): ''' label_tensor: batchsize x 1 x 512 x 512 predict_tensor: batchsize x 1 x 512 x 512 ''' label_array = np.squeeze(label_tensor.data.cpu().numpy(), 1).astype(np.int) predict_array = np.squeeze(predict_tensor.data.cpu().numpy(), 1) predict_array = (predict_array > thres).astype(np.int) random_error_error = 0.0 random_error_precision = 0.0 random_error_recall = 0.0 false_split = 0.0 false_merge = 0.0 for i in range(label_array.shape[0]): error, precision, recall = adapted_rand_error(label_array[i], predict_array[i]) splits, merges = variation_of_information(label_array[i], predict_array[i]) random_error_error += error random_error_precision += precision random_error_recall += recall false_split += splits false_merge += merges return random_error_error, random_error_precision, random_error_recall, false_split, false_merge
def get_vi(pred: np.ndarray, mask: np.ndarray, bg_value: int = 0, method: int = 1) -> Tuple: """ Referenced by: Marina Meilă (2007), Comparing clusterings—an information based distance, Journal of Multivariate Analysis, Volume 98, Issue 5, Pages 873-895, ISSN 0047-259X, DOI:10.1016/j.jmva.2006.11.013. :param method: 0: skimage implementation and 1: gala implementation (https://github.com/janelia-flyem/gala.) :return Tuple = (VI, merger_error, split_error) """ vi, merger_error, split_error = 0.0, 0.0, 0.0 label_pred, num_pred = label(pred, connectivity=1, background=bg_value, return_num=True) label_mask, num_mask = label(mask, connectivity=1, background=bg_value, return_num=True) if method == 0: # scikit-image split_error, merger_error = metrics.variation_of_information( label_mask, label_pred) elif method == 1: # gala merger_error, split_error = ev.split_vi(label_pred, label_mask) vi = merger_error + split_error if math.isnan(vi): return 10, 5, 5 return merger_error, split_error, vi
def forward(self, x): input1 = x["reference"].cpu().numpy().astype(np.uint8) input2 = x["other"].cpu().numpy().astype(np.uint8) sizeIn = input1.shape distance = np.empty((sizeIn[0], sizeIn[1])) for i in range(sizeIn[0]): for j in range(sizeIn[1]): in1 = np.transpose(input1[i, j], [1, 2, 0]) in2 = np.transpose(input2[i, j], [1, 2, 0]) if self.mode == "L2": distance[i, j] = metrics.mean_squared_error( in1, in2) / (255.0 * 255.0) elif self.mode == "SSIM": distance[i, j] = 1 - metrics.structural_similarity( in1, in2, multichannel=True) #invert as distance measure elif self.mode == "PSNR": distance[i, j] = -metrics.peak_signal_noise_ratio( in1, in2) #invert as distance measure elif self.mode == "MI": distance[i, j] = np.mean( metrics.variation_of_information(in1, in2)) return torch.from_numpy(distance)
def __call__(self, input_seg, gt_seg): splits, merges = variation_of_information(gt_seg, input_seg) self.splits_scores.append(splits) self.merges_scores.append(merges) are, arp, arr = adapted_rand_error(gt_seg, input_seg) self.are_score.append(are) self.arp_score.append(arp) self.arr_score.append(arr)
def eval_metric_array(pred, label): im_true = ndi.label(ndi.binary_fill_holes(label))[0] im_pred = ndi.label(ndi.binary_fill_holes(pred))[0] error, precision, recall = adapted_rand_error(im_true, im_pred) splits, merges = variation_of_information(im_true, im_pred) return error, precision, recall, splits, merges
def test_vi_ignore_labels(): im1 = np.array([[1, 0], [2, 3]], dtype='uint8') im2 = np.array([[1, 1], [1, 0]], dtype='uint8') false_splits, false_merges = variation_of_information(im1, im2, ignore_labels=[0]) assert (false_splits, false_merges) == (0, 2 / 3)
def compare(self, f_quote: str): images = [self.image_base.copy(), cv2.imread(f_quote)] shape_min = (min([i.shape[1] for i in images]), min([i.shape[0] for i in images])) logging.debug('Comparing size: %s', shape_min) for i in range(len(images)): images[i] = Image.fromarray(images[i]).resize( shape_min, Image.ANTIALIAS) images[i] = numpy.array(images[i]) return numpy.mean(variation_of_information(images[0], images[1]))
def validate(res_path, exp_path): seg_key = 'connected_components' with z5py.File(res_path, 'r') as f: ds = f[seg_key] res = ds[:] with z5py.File(exp_path, 'r') as f: ds = f[seg_key] exp = ds[:] assert res.shape == exp.shape vi0, vi1 = variation_of_information(exp, res) print("variation of information (should be close to zero):", vi0 + vi1)
def eval_metric(pred_path, label_path): pred = Image.open(pred_path) label = Image.open(label_path) label = np.array(label) pred = np.array(pred)[:, :, 0] label[label == 255] = 1 pred[pred == 255] = 1 im_true = ndi.label(ndi.binary_fill_holes(label))[0] im_pred = ndi.label(ndi.binary_fill_holes(pred))[0] error, precision, recall = adapted_rand_error(im_true, im_pred) splits, merges = variation_of_information(im_true, im_pred) return (error, precision, recall), (splits, merges)
def compute_similarity(self, im, im_deg, sim_method='mutual_info'): im = np.array(im) im_deg = np.array(im_deg) if sim_method == 'mutual_info': return mutual_information(im, im_deg) elif sim_method == 'dice': return f1_score( im.astype(bool).ravel(), im_deg.astype(bool).ravel()) elif sim_method == 'ssim': return ssim(im.astype(bool), im_deg.astype(bool)) elif sim_method == 'var_info': under_seg, over_seg = variation_of_information( im.astype(bool), im_deg.astype(bool)) return 1 - (under_seg + over_seg) elif sim_method == 'mse': return 1 - mean_squared_error( im.astype(bool).ravel(), im_deg.astype(bool).ravel())
threshold=0.69) im_test3 = label(im_test3) method_names = [ 'Compact watershed', 'Canny filter', 'Morphological Geodesic Active Contours' ] short_method_names = ['Compact WS', 'Canny', 'GAC'] precision_list = [] recall_list = [] split_list = [] merge_list = [] for name, im_test in zip(method_names, [im_test1, im_test2, im_test3]): error, precision, recall = adapted_rand_error(im_true, im_test) splits, merges = variation_of_information(im_true, im_test) split_list.append(splits) merge_list.append(merges) precision_list.append(precision) recall_list.append(recall) print(f"\n## Method: {name}") print(f"Adapted Rand error: {error}") print(f"Adapted Rand precision: {precision}") print(f"Adapted Rand recall: {recall}") print(f"False Splits: {splits}") print(f"False Merges: {merges}") fig, axes = plt.subplots(2, 3, figsize=(9, 6), constrained_layout=True) ax = axes.ravel() ax[0].scatter(merge_list, split_list)
def test_vi(): im_true = np.array([1, 2, 3, 4]) im_test = np.array([1, 1, 8, 8]) assert_equal(np.sum(variation_of_information(im_true, im_test)), 1)
def segment_from_directory( directory, suffix, affinities_channels, centroids_channel, thresholding_channel, scale = (4, 1, 1), w_scale=None, compactness=0., display=True, validation=False, **kwargs # ): images, _, output, GT = get_dataset(directory, GT=True, validation=validation) images = da.squeeze(images) print(output.shape) segmentations = [] masks = [] scores = {'GT | Output' : [], 'Output | GT' : []} for i in range(output.shape[0]): gt = GT[i].compute() seg, _, mask = segment_output_image( output[i], affinities_channels, centroids_channel, thresholding_channel, scale=w_scale, compactness=0.) vi = variation_of_information(gt, seg) scores['GT | Output'].append(vi[0]) scores['Output | GT'].append(vi[1]) seg = da.from_array(seg) segmentations.append(seg) masks.append(mask) segmentations = da.stack(segmentations) masks = da.stack(masks) # Save the VI data scores = pd.DataFrame(scores) if validation: s = 'validation_VI.csv' else: s = '_VI.csv' s_path = os.path.join(directory, suffix + s) scores.to_csv(s_path) gt_o = scores['GT | Output'].mean() o_gt = scores['Output | GT'].mean() print(f'Conditional entropy H(GT|Output): {gt_o}') print(f'Conditional entropy H(Output|GT): {o_gt}') if display: # Now Display z_affs = output[:, affinities_channels[0], ...] y_affs = output[:, affinities_channels[1], ...] x_affs = output[:, affinities_channels[2], ...] c = output[:, thresholding_channel, ...] cl = output[:, centroids_channel, ...] v_scale = [1] * len(images.shape) v_scale[-3:] = scale print(images.shape, v_scale, z_affs.shape, masks.shape) v = napari.Viewer() v.add_image(images, name='Input images', blending='additive', visible=True, scale=v_scale) v.add_image(c, name='Thresholding channel', blending='additive', visible=False, scale=v_scale) v.add_image(cl, name='Centroids channel', blending='additive', visible=False, scale=v_scale) v.add_image(z_affs, name='z affinities', blending='additive', visible=False, scale=v_scale, colormap='bop purple') v.add_image(y_affs, name='y affinities', blending='additive', visible=False, scale=v_scale, colormap='bop orange') v.add_image(x_affs, name='x affinities', blending='additive', visible=False, scale=v_scale, colormap='bop blue') v.add_labels(masks, name='Masks', blending='additive', visible=False, scale=v_scale) v.add_labels(GT, name='Ground truth', blending='additive', visible=False, scale=v_scale) v.add_labels(segmentations, name='Segmentations', blending='additive', visible=True, scale=v_scale) napari.run()