Beispiel #1
0
    def select_alignment_rect(self, scale_factor):
        """
        Using the frame with the highest rank (sharpest image), select the rectangular patch
        where structure is best in both x and y directions. The size of the patch is the size of the
        frame divided by "scale_factor" in both coordinate directions.

        :param scale_factor: Ratio of the size of the frame and the alignment patch in both
                             coordinate directions
        :return: A four tuple (x_low, x_high, y_low, y_high) with pixel coordinates of the
                 optimal patch
        """

        dim_y, dim_x = self.shape[0:2]

        # Compute the extensions of the alignment rectangle in y and x directions.
        rect_y = int(self.shape[0] / scale_factor)
        rect_x = int(self.shape[1] / scale_factor)

        # Initialize the quality measure of the optimal location to an impossible value (<0).
        quality = -1.

        # Compute for all locations in the frame the "quality measure" and find the place with
        # the maximum value.
        for x_low in arange(0, dim_x - rect_x + 1, rect_x):
            x_high = x_low + rect_x
            for y_low in arange(0, dim_y - rect_y + 1, rect_y):
                y_high = y_low + rect_y
                new_quality = Miscellaneous.quality_measure(
                    self.frames_mono[self.frame_ranks_max_index][y_low:y_high,
                                                                 x_low:x_high])
                if new_quality > quality:
                    (self.x_low_opt, self.x_high_opt, self.y_low_opt,
                     self.y_high_opt) = (x_low, x_high, y_low, y_high)
                    quality = new_quality
        return (self.x_low_opt, self.x_high_opt, self.y_low_opt,
                self.y_high_opt)
    def create_ap_grid(self):
        """
        Create a 2D staggered grid of alignment points. For each AP compute its center coordinates,
        and the coordinate limits of its alignment box and alignment patch. Only alignment points
        which satisfy the conditions on brightness, contrast and structure are eventually added to
        the list.

        :return: List of alignment points.
        """

        # The alignment patch is the area which is stacked after a rigid displacement.
        half_patch_width = self.configuration.alignment_points_half_patch_width
        # The alignment box is the object on which the displacement computation is performed.
        half_box_width = self.configuration.alignment_points_half_box_width
        # Number of pixels in one coordinate direction between alignment points
        step_size = self.configuration.alignment_points_step_size
        # Maximum displacement searched for in the alignment process.
        search_width = self.configuration.alignment_points_search_width
        # Minimum structure value for an alignment point (between 0. and 1.)
        structure_threshold = self.configuration.alignment_points_structure_threshold
        # The brightest pixel must be brighter than this value (0 < value <256). Please note that
        # brightness and contrast values are converted to 16bit resolution.
        brightness_threshold = self.configuration.alignment_points_brightness_threshold * 256
        # The difference between the brightest and darkest pixel values must be larger than this
        # value (0 < value < 256)
        contrast_threshold = self.configuration.alignment_points_contrast_threshold * 256

        # Compute the minimum distance of an AP from the boundary.
        min_boundary_distance = max(half_box_width + search_width,
                                    half_patch_width)

        # Compute y and x coordinate locations of alignemnt points. Note that the grid is staggered.
        ap_locations_y = self.ap_locations(self.num_pixels_y,
                                           min_boundary_distance, step_size,
                                           True)
        ap_locations_x_even = self.ap_locations(self.num_pixels_x,
                                                min_boundary_distance,
                                                step_size, True)
        ap_locations_x_odd = self.ap_locations(self.num_pixels_x,
                                               min_boundary_distance,
                                               step_size, False)

        # Reset the alignment point list, and initialize counters for APs which are dropped because
        # they do not satisfy the brightness or structure condition.
        self.alignment_points = []
        self.alignment_points_dropped_dim = 0
        self.alignment_points_dropped_structure = 0

        # Compute the minimum distance of an AP center from the frame boundary.
        min_boundary_distance = max(
            self.configuration.alignment_points_half_box_width + \
            self.configuration.alignment_points_search_width,
            self.configuration.alignment_points_half_patch_width)

        # Create alignment point rows, start with an even one.
        even = True
        for index_y, y in enumerate(ap_locations_y):
            # For the first row extend the patch to the upper frame border, and for the last row
            # to the lower frame border.
            extend_y_low = (index_y == 0)
            extend_y_high = (index_y == len(ap_locations_y) - 1)

            # Create x coordinate, depending on the y row being even or odd (staggered grid).
            if even:
                ap_locations_x = ap_locations_x_even
            else:
                ap_locations_x = ap_locations_x_odd

            # For each location create an alignment point.
            for index_x, x in enumerate(ap_locations_x):
                # For the first point in a row, extend the patch to the left frame border, and for
                # the last point in a row to the right frame border.
                extend_x_low = (index_x == 0)
                extend_x_high = (index_x == len(ap_locations_x) - 1)

                alignment_point = self.new_alignment_point(
                    y, x, extend_x_low, extend_x_high, extend_y_low,
                    extend_y_high)

                # Compute structure and brightness information for the alignment box.
                max_brightness = amax(alignment_point['reference_box'])
                min_brightness = amin(alignment_point['reference_box'])
                # If the alignment box satisfies the brightness conditions, add the AP to the list.
                if max_brightness > brightness_threshold and max_brightness - \
                        min_brightness > contrast_threshold:

                    # Check if the fraction of dark pixels exceeds a threshold.
                    box = alignment_point['reference_box']
                    fraction = (box < brightness_threshold).sum() / (
                        box.shape[0] * box.shape[1])
                    if fraction > self.configuration.alignment_points_dim_fraction_threshold:

                        # Compute the center of mass of the brightness distribution within the box,
                        # and shift the box center to this location.
                        com = ndimage.measurements.center_of_mass(box)
                        y_adapted = y + int(com[0]) - half_box_width
                        x_adapted = x + int(com[1]) - half_box_width

                        y_adapted = max(y_adapted, min_boundary_distance)
                        y_adapted = min(
                            y_adapted,
                            self.num_pixels_y - min_boundary_distance)
                        x_adapted = max(x_adapted, min_boundary_distance)
                        x_adapted = min(
                            x_adapted,
                            self.num_pixels_x - min_boundary_distance)

                        # Replace the alignment point with a new one, using the updated
                        # coordinates.
                        alignment_point = self.new_alignment_point(
                            y_adapted, x_adapted, extend_x_low, extend_x_high,
                            extend_y_low, extend_y_high)

                    alignment_point[
                        'structure'] = Miscellaneous.quality_measure(
                            alignment_point['reference_box'])
                    self.alignment_points.append(alignment_point)
                else:
                    # If a point does not satisfy the conditions, increase the counter.
                    self.alignment_points_dropped_dim += 1

            # Switch between even and odd rows.
            even = not even

        # Normalize the structure information for all alignment point boxes by dividing by the
        # maximum value.
        structure_max = max(alignment_point['structure']
                            for alignment_point in self.alignment_points)
        alignment_points_dropped_structure_indices = []
        for alignment_point_index, alignment_point in enumerate(
                self.alignment_points):
            alignment_point['structure'] /= structure_max
            # Remove alignment points with too little structure and increment the counter.
            if alignment_point['structure'] < structure_threshold:
                alignment_points_dropped_structure_indices.append(
                    alignment_point_index)
                self.alignment_points_dropped_structure += 1

        # Remove alignment points which do not satisfy the structure condition, if there is any.
        if alignment_points_dropped_structure_indices:
            alignment_points_new = []
            dropped_index = 0
            for alignment_point_index, alignment_point in enumerate(
                    self.alignment_points):
                if alignment_point_index != alignment_points_dropped_structure_indices[
                        dropped_index]:
                    alignment_points_new.append(alignment_point)
                elif dropped_index < len(
                        alignment_points_dropped_structure_indices) - 1:
                    dropped_index += 1
            self.alignment_points = alignment_points_new