def warp_field_advanced(canonical_field, warped_live_field, warp_field, gradient_field, band_union_only=False, known_values_only=False, substitute_original=False, data_gradient_field=None, smoothing_gradient_field=None): field_size = warp_field.shape[0] new_warped_live_field = np.ones_like(warped_live_field) for y in range(field_size): for x in range(field_size): original_live_sdf = warped_live_field[y, x] if band_union_only: canonical_sdf = canonical_field[y, x] if value_outside_narrow_band( original_live_sdf) and value_outside_narrow_band( canonical_sdf): new_warped_live_field[y, x] = original_live_sdf continue if known_values_only: if original_live_sdf == 1.0: new_warped_live_field[y, x] = original_live_sdf continue warped_location = Point2d( x, y) + Point2d(coordinates=warp_field[y, x]) if substitute_original: new_value, metainfo = sampling.bilinear_sample_at_replacement_metainfo( warped_live_field, point=warped_location, replacement=original_live_sdf) else: new_value, metainfo = sampling.bilinear_sample_at_metainfo( warped_live_field, point=warped_location) if 1.0 - abs(new_value) < 1e-6: new_value = np.sign(new_value) warp_field[y, x] = 0.0 gradient_field[y, x] = 0.0 if data_gradient_field is not None: data_gradient_field[y, x] = 0.0 if smoothing_gradient_field is not None: smoothing_gradient_field[y, x] = 0.0 if sampling.focus_coordinates_match(x, y): print_interpolation_data(metainfo, original_live_sdf, new_value) new_warped_live_field[y, x] = new_value return new_warped_live_field
def compute_local_data_term_gradient_basic(warped_live_field, canonical_field, x, y, live_gradient_x, live_gradient_y): live_sdf = warped_live_field[y, x] canonical_sdf = canonical_field[y, x] diff = live_sdf - canonical_sdf if focus_coordinates_match(x, y): print("; Live - canonical: {:+01.4f} - {:+01.4f} = {:+01.4f}" .format(live_sdf, canonical_sdf, diff)) compute_local_gradient_central_differences(warped_live_field, x, y, True, True) live_local_gradient = np.array([live_gradient_x[y, x], live_gradient_y[y, x]]) scaling_factor = 10.0 data_gradient = diff * live_local_gradient * scaling_factor local_energy_contribution = 0.5 * pow(diff, 2) return data_gradient, local_energy_contribution
def compute_local_data_term_gradient_thresholded_fdm(warped_live_field, canonical_field, x, y, live_gradient_x, live_gradient_y): live_sdf = warped_live_field[y, x] canonical_sdf = canonical_field[y, x] diff = live_sdf - canonical_sdf if focus_coordinates_match(x, y): print("; Live - canonical: {:+01.4f} - {:+01.4f} = {:+01.4f}" .format(live_sdf, canonical_sdf, diff)) compute_local_gradient_central_differences(warped_live_field, x, y, True, True) x_grad = live_gradient_x[y, x] if abs(x_grad) > 0.5: live_x_minus_one = sample_at(warped_live_field, x - 1, y) live_x_plus_one = sample_at(warped_live_field, x + 1, y) x_grad_forward = live_x_plus_one - live_sdf x_grad_backward = live_sdf - live_x_minus_one x_grad = x_grad_forward if abs(x_grad_forward) < abs(x_grad_backward) else x_grad_backward if abs(x_grad) > 0.5: x_grad = 0 y_grad = live_gradient_y[y, x] if abs(y_grad) > 0.5: live_y_minus_one = sample_at(warped_live_field, x, y - 1) live_y_plus_one = sample_at(warped_live_field, x, y + 1) y_grad_forward = live_y_plus_one - live_sdf y_grad_backward = live_sdf - live_y_minus_one y_grad = y_grad_forward if abs(y_grad_forward) < abs(y_grad_backward) else y_grad_backward if abs(y_grad) > 0.5: y_grad = 0.0 live_local_gradient = np.array([x_grad, y_grad]) scaling_factor = 10.0 data_gradient = diff * live_local_gradient * scaling_factor local_energy_contribution = 0.5 * pow(diff, 2) return data_gradient, local_energy_contribution
def compute_local_smoothing_term_gradient_tikhonov(warp_field, x, y, ignore_if_zero=False, copy_if_zero=True, isomorphic_enforcement_factor=0.1): # 1D discrete laplacian using finite-differences warp = warp_field[y, x] if ignore_if_zero and \ ((x != warp_field.shape[1] - 1 and np.linalg.norm(warp_field[y, x + 1] == 0.0)) or (x != 0 and np.linalg.norm(warp_field[y, x - 1] == 0.0)) or (y != warp_field.shape[0] - 1 and np.linalg.norm(warp_field[y + 1, x] == 0.0)) or (y != 0 and np.linalg.norm(warp_field[y - 1, x] == 0.0))): return np.array([0.0, 0.0], dtype=np.float32), 0.0 if copy_if_zero: warp_x_plus_one = sample_warp_replace_if_zero(warp_field, x + 1, y, warp) warp_x_minus_one = sample_warp_replace_if_zero(warp_field, x - 1, y, warp) warp_y_plus_one = sample_warp_replace_if_zero(warp_field, x, y + 1, warp) warp_y_minus_one = sample_warp_replace_if_zero(warp_field, x, y - 1, warp) else: warp_x_plus_one = sample_warp(warp_field, x + 1, y, warp) warp_x_minus_one = sample_warp(warp_field, x - 1, y, warp) warp_y_plus_one = sample_warp(warp_field, x, y + 1, warp) warp_y_minus_one = sample_warp(warp_field, x, y - 1, warp) if focus_coordinates_match(x, y): print_smoothing_term_data(warp_y_minus_one, warp_x_minus_one, warp_y_plus_one, warp_x_plus_one, warp) scaling_factor = 1.0 smoothing_gradient = -scaling_factor * ( warp_x_plus_one + warp_y_plus_one - 4 * warp + warp_x_minus_one + warp_y_minus_one) warp_gradient_x = 0.5 * (warp_x_plus_one - warp_x_minus_one) * scaling_factor warp_gradient_y = 0.5 * (warp_y_plus_one - warp_y_minus_one) * scaling_factor local_energy_contribution = 0.5 * ( warp_gradient_x.dot(warp_gradient_x) + warp_gradient_y.dot(warp_gradient_y)) return smoothing_gradient, local_energy_contribution
def warp_field_with_with_flag_info(warped_live_field, warp_field, update_field, flag_field): field_size = warp_field.shape[0] new_warped_live_field = np.ones_like(warped_live_field) for y in range(field_size): for x in range(field_size): warped_location = Point2d( x, y) + Point2d(coordinates=warp_field[y, x]) base_point = Point2d(math.floor(warped_location.x), math.floor(warped_location.y)) ratios = warped_location - base_point inverse_ratios = Point2d(1.0, 1.0) - ratios original_value = warped_live_field[y, x] value00 = sampling.sample_at(warped_live_field, point=base_point) flag00 = sampling.sample_flag_at(flag_field, point=base_point) used_replacement = False if flag00 == 0: value00 = original_value used_replacement = True value01 = sampling.sample_at(warped_live_field, point=base_point + Point2d(0, 1)) flag01 = sampling.sample_flag_at(flag_field, point=base_point + Point2d(0, 1)) if flag01 == 0: value01 = original_value used_replacement = True value10 = sampling.sample_at(warped_live_field, point=base_point + Point2d(1, 0)) flag10 = sampling.sample_flag_at(flag_field, point=base_point + Point2d(1, 0)) if flag10 == 0: value10 = original_value used_replacement = True value11 = sampling.sample_at(warped_live_field, point=base_point + Point2d(1, 1)) flag11 = sampling.sample_flag_at(flag_field, point=base_point + Point2d(1, 1)) if flag11 == 0: value11 = original_value used_replacement = True interpolated_value0 = value00 * inverse_ratios.y + value01 * ratios.y interpolated_value1 = value10 * inverse_ratios.y + value11 * ratios.y interpolated_value = interpolated_value0 * inverse_ratios.x + interpolated_value1 * ratios.x if 1.0 - abs(interpolated_value) < 1e-3: # if 1.0 - abs(interpolated_value) < 0.05: interpolated_value = np.sign(interpolated_value) warp_field[y, x] = 0.0 update_field[y, x] = 0.0 if sampling.focus_coordinates_match(x, y): print("[Interpolation data] ", BOLD_YELLOW, "{:+03.3f}*{:03.3f}, {:+03.3f}*{:03.3f}".format( value00, inverse_ratios.y * inverse_ratios.x, value10, inverse_ratios.y * ratios.x, ), RESET, sep='') print(" ", BOLD_YELLOW, "{:+03.3f}*{:03.3f}, {:+03.3f}*{:03.3f}".format( value01, ratios.y * inverse_ratios.x, value11, ratios.y * ratios.x), RESET, " used replacement:", BOLD_GREEN, used_replacement, RESET, " final value: ", BOLD_GREEN, interpolated_value, RESET, sep='') new_warped_live_field[y, x] = interpolated_value np.copyto(warped_live_field, new_warped_live_field)
def __optimization_iteration_direct(self, warped_live_field, canonical_field, warp_field, data_component_field=None, smoothing_component_field=None, level_set_component_field=None, band_union_only=True): self.total_data_energy = 0. self.total_smoothing_energy = 0. self.total_level_set_energy = 0. field_size = warp_field.shape[0] live_gradient_y, live_gradient_x = np.gradient(warped_live_field) for y in range(0, field_size): for x in range(0, field_size): if focus_coordinates_match(x, y): print("Point: ", x, ",", y, sep='', end='') gradient = 0.0 live_sdf = warped_live_field[y, x] live_is_truncated = value_outside_narrow_band(live_sdf) if band_union_only and voxel_is_outside_narrow_band_union( warped_live_field, canonical_field, x, y): continue data_gradient, local_data_energy = \ dt.compute_local_data_term(warped_live_field, canonical_field, x, y, live_gradient_x, live_gradient_y, method=self.data_term_method) scaled_data_gradient = self.data_term_weight * data_gradient self.total_data_energy += self.data_term_weight * local_data_energy gradient += scaled_data_gradient if focus_coordinates_match(x, y): print(" Data grad: ", BOLD_GREEN, -data_gradient, RESET, sep='', end='') if data_component_field is not None: data_component_field[y, x] = data_gradient if self.level_set_term_enabled and not live_is_truncated: level_set_gradient, local_level_set_energy = \ level_set_term_at_location(warped_live_field, x, y) scaled_level_set_gradient = self.level_set_term_weight * level_set_gradient self.total_level_set_energy += self.level_set_term_weight * local_level_set_energy gradient += scaled_level_set_gradient if level_set_component_field is not None: level_set_component_field[y, x] = level_set_gradient if focus_coordinates_match(x, y): print(" Level-set grad (scaled): ", BOLD_GREEN, -scaled_level_set_gradient, RESET, sep='', end='') smoothing_gradient, local_smoothing_energy = \ st.compute_local_smoothing_term_gradient(warp_field, x, y, method=self.smoothing_term_method, copy_if_zero=False, isomorphic_enforcement_factor= self.isomorphic_enforcement_factor) scaled_smoothing_gradient = self.smoothing_term_weight * smoothing_gradient self.total_smoothing_energy += self.smoothing_term_weight * local_smoothing_energy gradient += scaled_smoothing_gradient if smoothing_component_field is not None: smoothing_component_field[y, x] = smoothing_gradient if focus_coordinates_match(x, y): print(" Smoothing grad (scaled): ", BOLD_GREEN, -scaled_smoothing_gradient, RESET, sep='', end='') self.gradient_field[y, x] = gradient if self.sobolev_smoothing_enabled: convolve_with_kernel_preserve_zeros(self.gradient_field, self.sobolev_kernel, True) max_warp = 0.0 max_warp_location = -1 # update the warp field based on the gradient for y in range(0, field_size): for x in range(0, field_size): warp_field[y, x] = -self.gradient_field[ y, x] * self.gradient_descent_rate if focus_coordinates_match(x, y): print(" Warp: ", BOLD_GREEN, warp_field[y, x], RESET, " Warp length: ", BOLD_GREEN, np.linalg.norm(warp_field[y, x]), RESET, sep='') warp_length = np.linalg.norm(warp_field[y, x]) if warp_length > max_warp: max_warp = warp_length max_warp_location = Point2d(x, y) if (x, y) in self.focus_neighborhood_log: log = self.focus_neighborhood_log[(x, y)] log.warp_magnitudes.append(warp_length) log.sdf_values.append(warped_live_field[y, x]) new_warped_live_field = resample_warped_live(canonical_field, warped_live_field, warp_field, self.gradient_field, band_union_only=False, known_values_only=False, substitute_original=False) np.copyto(warped_live_field, new_warped_live_field) return max_warp, max_warp_location
def compute_local_data_term_gradient_advanced_grad(warped_live_field, canonical_field, flag_field, x, y): live_sdf = warped_live_field[y, x] canonical_sdf = canonical_field[y, x] diff = live_sdf - canonical_sdf live_y_minus_one = sample_at(warped_live_field, x, y - 1) flag_y_minus_one = sample_flag_at(flag_field, x, y - 1) live_x_minus_one = sample_at(warped_live_field, x - 1, y) flag_x_minus_one = sample_flag_at(flag_field, x - 1, y) live_y_plus_one = sample_at(warped_live_field, x, y + 1) flag_y_plus_one = sample_flag_at(flag_field, x, y + 1) live_x_plus_one = sample_at(warped_live_field, x + 1, y) flag_x_plus_one = sample_flag_at(flag_field, x + 1, y) x_grad = 0.5 * (live_x_plus_one - live_x_minus_one) y_grad = 0.5 * (live_y_plus_one - live_y_minus_one) reduction_factor = 1.0 special_used_x = False special_used_y = False if flag_y_plus_one == 0: if flag_y_minus_one == 0: y_grad = 0 else: y_grad = reduction_factor * (live_sdf - live_y_minus_one) special_used_y = True elif flag_y_minus_one == 0: y_grad = reduction_factor * (live_y_plus_one - live_sdf) special_used_y = True if flag_x_plus_one == 0: if flag_x_minus_one == 0: x_grad = 0 else: x_grad = reduction_factor * (live_sdf - live_x_minus_one) special_used_x = True elif flag_x_minus_one == 0: x_grad = reduction_factor * (live_x_plus_one - live_sdf) special_used_x = True # if live_y_plus_one == 1.0: # if live_y_minus_one == 1.0: # y_grad = 0 # else: # y_grad = reduction_factor * (live_sdf - live_y_minus_one) # special_used_y = True # elif live_y_minus_one == 1.0: # y_grad = reduction_factor * (live_y_plus_one - live_sdf) # special_used_y = True # # if live_x_plus_one == 1.0: # if live_x_minus_one == 1.0: # x_grad = 0 # else: # x_grad = reduction_factor * (live_sdf - live_x_minus_one) # special_used_x = True # elif live_x_minus_one == 1.0: # x_grad = reduction_factor * (live_x_plus_one - live_sdf) # special_used_x = True if focus_coordinates_match(x, y): print() print("[Grad data ] Special fd x,y: ", BOLD_GREEN, special_used_x, ",", special_used_y, BOLD_BLUE, sep='') print(" ", " {:+01.3f}".format(live_y_minus_one), sep='') print(" ", "{:+01.3f}{:+01.3f}{:+01.3f}".format(live_x_minus_one, live_sdf, live_x_plus_one), sep='') print(" ", " {:+01.3f}".format(live_y_plus_one), RESET, sep='') alternative_data = False if alternative_data: unscaled_warp_gradient_contribution = np.array([0.0, 0.0], dtype=np.float32) if abs(x_grad) > 1e-4: unscaled_warp_gradient_contribution[0] = diff / x_grad if abs(y_grad) > 1e-4: unscaled_warp_gradient_contribution[1] = diff / y_grad else: live_local_gradient = np.array([x_grad, y_grad]) # scaling factor of 100 -- SDF values are 1/10 of the actual voxel distance, since we have 10 voxels in the # narrow band and the values go between 0 and 10. The diff is sampled at 1/10, so is the finite difference, # hence 10 * 10 is the correct factor unscaled_warp_gradient_contribution = diff * live_local_gradient * 100 local_energy_contribution = 0.5 * pow(diff, 2) return unscaled_warp_gradient_contribution, local_energy_contribution