예제 #1
0
    def test_image_row_sum_is_calculated_correctly(self):
        """
        Added 04.11.2018
        @return:
        """
        lightning_image = LightningImage(self.sum_array)

        row_sum = lightning_image.row_sum()
        self.assertListEqual([2, 2], list(row_sum))
예제 #2
0
    def test_image_row_sum_scaling_works(self):
        """
        Added 04.11.2018
        @return:
        """
        lightning_image = LightningImage(self.sum_array)

        row_sum = lightning_image.row_sum(scale=1)
        # Here we need to test each element separately because the elements are float and we obviously cannot
        # hard-compare two floats & there is no "ListAlmostEqual" Assertion
        self.assertAlmostEqual(1.0, row_sum[0], 2)
        self.assertAlmostEqual(1.0, row_sum[1], 2)
예제 #3
0
class SimpleAreaSegmentationEngine(AbstractAreaSegmentationEngine):
    """
    This procedure assumes the image is already processed.

    Given an Image object, this algorithm will calculate the pixel sums along the rows and the columns of the picture.
    The resulting intensity function is then segmented into sub sequences along the axis's by watching, when the
    function first exceeds a certain threshold and when it drops below it again.
    From these sequences along the axis all possible combinations(=areas on the picture) are computed. These areas are
    suspected to contain intensity maximums. In the last step the average of each area is checked against another
    threshold to remove false positives from the final result.

    CHANGELOG

    Added 16.11.2018
    """
    DEFAULT_CONFIG = {
        'threshold': 1.0,
        'checking': True,
        'check_threshold': 0.03,
    }

    def __init__(self, config):
        """
        The constructor.

        The config dict can have the following parameters:
        - threshold:        A float, which defines the factor between a value of the axis sum function and the global
                            average of the latter that qualifies a value as surpassing the threshold.
                            A threshold RELATIVE to the average of the function. DEFAULT is 1.0
        - checking:         boolean flag of whether or not to perform the last checking operation
        - check_threshold:  A float threshold value relative to 255 the average of an area has to have to qualify as a
                            valid solution to the problem. DEFAULT is 0.03, equates to roughly a grayscale value of 7,
                            which has to be the average of an area.

        CHANGELOG

        Added 16.11.2018

        @param dict config:
        """
        AbstractAreaSegmentationEngine.__init__(self, config)
        self.config = self.DEFAULT_CONFIG.copy()
        self.config.update(config)

        self.current = None

    def __call__(self, lightning_image):
        """
        The main function executed, when the engine is called.

        CHANGELOG

        Added 16.11.2018

        @param LightningImage lightning_image:
        @return: List(Tuple())
        """
        # A copy of the image object is being made, so transformations can be used without disturbing the original
        # image
        self.current = LightningImage(lightning_image)

        # Calculating the row and column sums of the grayscale values
        self.x_sums = self.current.row_sum()
        self.y_sums = self.current.column_sum()

        # Calculating the mean value of both these functions
        x_average = np.average(self.x_sums)
        y_average = np.average(self.y_sums)

        # Calculating the thresholds based on the factor given by the config
        self.x_threshold = x_average * self.config['threshold']
        self.y_threshold = y_average * self.config['threshold']

        # Getting all the possible areas
        x_sequences = threshold_sequencing(self.x_sums,
                                           self.config['threshold'])
        y_sequences = threshold_sequencing(self.y_sums,
                                           self.config['threshold'])

        areas = combinations_2d(x_sequences, y_sequences)

        if self.config['checking']:
            # Creating areas only from all the possible combinations of two axis's sub sequences also creates a lot
            # of false areas.
            # Here we go through all the areas and essentially compute the average amount of signal within them. Areas
            # are only part of the final solution, if the average within them surpasses a certain threshold
            result = []
            for area in areas:
                # Calculating the average within these areas and only using these that contain a high enough value
                av = average_2d(self.current.array, area)
                # print("Checking {} with average {}".format(str(area), av))
                if (av / 255) >= self.config['check_threshold']:
                    result.append(area)
            return result

        return areas