Example #1
0
    def best_frame_indices_in_empty_areas(self, index_y, index_x):
        """
        For a quality area without any alignment point, find the closest quality area with
        alignment points and return its list of frame indices ranked by the local frame quality in
        decreasing order.

        :param index_y: y coordinate of the quality area in the rectangular grid of quality areas
        :param index_x: x coordinate of the quality area in the rectangular grid of quality areas
        :return: frame index list, ranked by the image quality at the closest quality area with
                 alignment points
        """

        # Go though circles with increasing radius "distance" around the current quality area.
        for distance in arange(1, max(self.y_dim, self.x_dim)):
            circle = Miscellaneous.circle_around(index_x, index_y, distance)
            for (compare_x, compare_y) in circle:
                # If the coordinates are within the quality area grid, and if the area at this
                # location has a non-empty list of alignment points, return its list.
                if 0 <= compare_x < self.x_dim and 0 <= compare_y < self.y_dim and \
                        self.quality_areas[compare_y][compare_x]['alignment_point_indices']:
                    return self.quality_areas[compare_y][compare_x]['best_frame_indices']
        # This should never happen, because it means that there is not any quality area with an
        # alignment point.
        raise InternalError("No quality area contains any alignment point")
Example #2
0
def equalize_ap_patch(patch, offset_counters, stack_size, drizzle_factor):
    """
    During drizzling the AP patch gets different numbers of frame contributions at different
    positions in the drizzling pattern, depending on the distribution of sup-pixel shift values.
    The array "offset_counters" contains these numbers, with the sum of all those numbers being the
    total stack size.

    Scale all patch entries with "total stack size" / "offset counter". The result are uniform
    patch entries which look as if there had been "total stack size" contributions in all drizzle
    pattern locations.

    Special care has to be taken at locations where not a single frame contributed (called "holes").
    Here insert the average of patch values at all drizzle positions over a circle with minimum
    radius containing at least one non-zero contribution.

    :param patch: AP buffer after stacking with drizzling.
    :param offset_counters: Integer array, size drizzle_factor x drizzle_factor, with contribution
                            counts at all drizzle locations.
    :param stack_size: Overall number of frames stacked
    :param drizzle_factor: Factor by which the number of pixels is multiplied in each direction.
    :return: Number of drizzle locations without frame contributions.
    """

    dim_y, dim_x = patch.shape[:2]
    holes = []

    # First normalize the patch locations with non-zero contributions.
    for y_offset in range(drizzle_factor):
        for x_offset in range(drizzle_factor):
            if offset_counters[y_offset, x_offset]:
                normalization_factor = stack_size / offset_counters[y_offset,
                                                                    x_offset]
                patch[y_offset:dim_y:drizzle_factor,
                      x_offset:dim_x:drizzle_factor] *= normalization_factor
            # For locations with zero contributions (holes) remember the location.
            else:
                holes.append((y_offset, x_offset))

    # Now fill the holes with interpolated values from locations close by.
    for (y_offset, x_offset) in holes:

        # Initialize the buffer locations witz zeros.
        patch[y_offset:dim_y:drizzle_factor,
              x_offset:dim_x:drizzle_factor] = 0.

        # Look for the circle with smallest radius around the hole with at least one non-zero
        # contribution.
        for radius in range(1, drizzle_factor):
            n_success = 0
            for (y, x) in Miscellaneous.circle_around(y_offset, x_offset,
                                                      radius):
                if 0 <= y < drizzle_factor and 0 <= x < drizzle_factor and (
                        y, x) not in holes:
                    # A non-zero entry is found, add its contribution to the buffer.
                    patch[y_offset:dim_y:drizzle_factor, x_offset:dim_x:drizzle_factor] += \
                        patch[y:dim_y:drizzle_factor, x:dim_x:drizzle_factor]
                    n_success += 1

            # There was at least one non-zero contribution on the circle with this radius. Normalize
            # the buffer with the number of contributions and continue with the next hole.
            if n_success:
                patch[y_offset:dim_y:drizzle_factor,
                      x_offset:dim_x:drizzle_factor] *= 1. / n_success
                break

    # Return the number of holes in the drizzle pattern.
    return len(holes)