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
Beispiel #2
0
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
Beispiel #3
0
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)
Beispiel #6
0
    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
Beispiel #7
0
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