Example #1
0
    def test_match_coordinates_shuffled_40x40(self):
        """
        Test MatchCoordinates for shuffled optical coordinates, comparing the order of the shuffled optical list and the estimated coordinates
        generated by MatchCoordinates
        """
        electron_coordinates = self.electron_coordinates_10x10
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        shuffled_coordinates = coordinates._TransformCoordinates(
            electron_coordinates, (translation_x, translation_y), rotation,
            (scale_x, scale_y))
        shuffle(shuffled_coordinates)

        known_estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates(
            shuffled_coordinates, electron_coordinates, 0.25, 0.25)
        if known_estimated_coordinates != []:
            (calc_translation_x, calc_translation_y), (
                calc_scaling_x,
                calc_scaling_y), calc_rotation = transform.CalculateTransform(
                    known_optical_coordinates, known_estimated_coordinates)
            numpy.testing.assert_almost_equal(
                (calc_translation_x, calc_translation_y, calc_scaling_x,
                 calc_scaling_y, calc_rotation),
                (translation_x, translation_y, scale_x, scale_y, rotation), 1)
Example #2
0
    def test_match_coordinates_shuffled__distorted_10x10(self):
        """
        Test MatchCoordinates for shuffled and distorted optical coordinates, comparing the order of the shuffled optical list and the estimated coordinates
        generated by MatchCoordinates
        """
        electron_coordinates = self.electron_coordinates_10x10
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        shuffled_coordinates = coordinates._TransformCoordinates(
            electron_coordinates, (translation_x, translation_y), rotation,
            (scale_x, scale_y))
        shuffle(shuffled_coordinates)
        distorted_coordinates = []
        # Add noise to the coordinates
        for i in xrange(shuffled_coordinates.__len__()):
            distortion = tuple((uniform(-0.1, 0.1), uniform(-0.1, 0.1)))
            distorted_coordinates.append(
                tuple(map(operator.add, shuffled_coordinates[i], distortion)))

        known_estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates(
            distorted_coordinates, electron_coordinates, 0.25, 0.25)
        if known_estimated_coordinates != []:
            (calc_translation_x, calc_translation_y), (
                calc_scaling_x,
                calc_scaling_y), calc_rotation = transform.CalculateTransform(
                    shuffled_coordinates, known_estimated_coordinates)
            numpy.testing.assert_almost_equal(
                (calc_translation_x, calc_translation_y, calc_scaling_x,
                 calc_scaling_y, calc_rotation),
                (translation_x, translation_y, scale_x, scale_y, rotation), 1)
Example #3
0
    def test_precomputed_transformation_40x40(self):
        """
        Test MatchCoordinates for applied transformation
        """
        electron_coordinates = self.electron_coordinates_40x40
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(electron_coordinates, (translation_x, translation_y), rotation, (scale_x, scale_y))

        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(transformed_coordinates, electron_coordinates, 0.25, 0.25)
        (calc_translation_x, calc_translation_y), (calc_scaling_x, calc_scaling_y), calc_rotation = transform.CalculateTransform(known_optical_coordinates, known_estimated_coordinates)
        numpy.testing.assert_almost_equal((calc_translation_x, calc_translation_y, calc_scaling_x, calc_scaling_y, calc_rotation), (translation_x, translation_y, scale_x, scale_y, rotation), 0)
Example #4
0
    def test_precomputed_output_missing_point_40x40(self):
        """
        Test MatchCoordinates if NaN is returned in the corresponding position in case of missing point
        """
        electron_coordinates = self.electron_coordinates_40x40
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(electron_coordinates, (translation_x, translation_y), rotation, (scale_x, scale_y))
        rand = random.randint(0, len(transformed_coordinates) - 1)
        del transformed_coordinates[rand]
        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(transformed_coordinates, electron_coordinates, 0.25, 0.25)

        self.assertEqual(len(known_estimated_coordinates), len(electron_coordinates) - 1)
Example #5
0
    def test_shuffled_40x40(self):
        """
        Test MatchCoordinates for shuffled optical coordinates, comparing the order of the shuffled optical list and the estimated coordinates
        generated by MatchCoordinates
        """
        electron_coordinates = self.electron_coordinates_40x40
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        shuffled_coordinates = coordinates._TransformCoordinates(electron_coordinates, (translation_x, translation_y), rotation, (scale_x, scale_y))
        shuffle(shuffled_coordinates)

        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(shuffled_coordinates, electron_coordinates, 0.25, 0.25)
        (calc_translation_x, calc_translation_y), (calc_scaling_x, calc_scaling_y), calc_rotation = transform.CalculateTransform(known_optical_coordinates, known_estimated_coordinates)
        numpy.testing.assert_almost_equal((calc_translation_x, calc_translation_y, calc_scaling_x, calc_scaling_y, calc_rotation), (translation_x, translation_y, scale_x, scale_y, rotation), 1)
Example #6
0
    def test_match_coordinates_precomputed_output_missing_point_3x3(self):
        """
        Test MatchCoordinates if NaN is returned in the corresponding position in case of missing point
        """
        electron_coordinates = self.electron_coordinates_3x3
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(electron_coordinates, (translation_x, translation_y), rotation, (scale_x, scale_y))
        rand = random.randint(0, len(transformed_coordinates) - 1)
        del transformed_coordinates[rand]
        known_estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates(transformed_coordinates, electron_coordinates, 0.25, 0.25)

        if known_estimated_coordinates != []:
            numpy.testing.assert_equal(known_estimated_coordinates.__len__(), electron_coordinates.__len__() - 1)
Example #7
0
    def test_precomputed_output_missing_point_40x40(self):
        """
        Test MatchCoordinates if NaN is returned in the corresponding position in case of missing point
        """
        electron_coordinates = self.electron_coordinates_40x40
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(
            electron_coordinates, (translation_x, translation_y), rotation,
            (scale_x, scale_y))
        rand = random.randint(0, len(transformed_coordinates) - 1)
        del transformed_coordinates[rand]
        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(
            transformed_coordinates, electron_coordinates, 0.25, 0.25)

        self.assertEqual(len(known_estimated_coordinates),
                         len(electron_coordinates) - 1)
Example #8
0
    def test_match_coordinates_precomputed_output_missing_point_3x3(self):
        """
        Test MatchCoordinates if NaN is returned in the corresponding position in case of missing point
        """
        electron_coordinates = self.electron_coordinates_3x3
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(
            electron_coordinates, (translation_x, translation_y), rotation,
            (scale_x, scale_y))
        rand = random.randint(0, transformed_coordinates.__len__() - 1)
        del transformed_coordinates[rand]
        known_estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates(
            transformed_coordinates, electron_coordinates, 0.25, 0.25)

        if known_estimated_coordinates != []:
            numpy.testing.assert_equal(known_estimated_coordinates.__len__(),
                                       electron_coordinates.__len__() - 1)
Example #9
0
    def test_shuffled__distorted_10x10(self):
        """
        Test MatchCoordinates for shuffled and distorted optical coordinates, comparing the order of the shuffled optical list and the estimated coordinates
        generated by MatchCoordinates
        """
        electron_coordinates = self.electron_coordinates_10x10
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        shuffled_coordinates = coordinates._TransformCoordinates(electron_coordinates, (translation_x, translation_y), rotation, (scale_x, scale_y))
        shuffle(shuffled_coordinates)
        distorted_coordinates = []
        # Add noise to the coordinates
        for i in xrange(len(shuffled_coordinates)):
            distortion = tuple((uniform(-0.1, 0.1), uniform(-0.1, 0.1)))
            distorted_coordinates.append(tuple(map(operator.add, shuffled_coordinates[i], distortion)))

        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(distorted_coordinates, electron_coordinates, 0.25, 0.25)
        (calc_translation_x, calc_translation_y), (calc_scaling_x, calc_scaling_y), calc_rotation = transform.CalculateTransform(shuffled_coordinates, known_estimated_coordinates)
        numpy.testing.assert_almost_equal((calc_translation_x, calc_translation_y, calc_scaling_x, calc_scaling_y, calc_rotation), (translation_x, translation_y, scale_x, scale_y, rotation), 1)
Example #10
0
    def test_precomputed_transformation_40x40(self):
        """
        Test MatchCoordinates for applied transformation
        """
        electron_coordinates = self.electron_coordinates_40x40
        translation_x, translation_y = self.translation_x, self.translation_y
        scale_x, scale_y = self.scale_x, self.scale_y
        rotation = self.rotation

        transformed_coordinates = coordinates._TransformCoordinates(
            electron_coordinates, (translation_x, translation_y), rotation,
            (scale_x, scale_y))

        known_estimated_coordinates, known_optical_coordinates, max_dist = coordinates.MatchCoordinates(
            transformed_coordinates, electron_coordinates, 0.25, 0.25)
        (calc_translation_x, calc_translation_y), (
            calc_scaling_x,
            calc_scaling_y), calc_rotation = transform.CalculateTransform(
                known_optical_coordinates, known_estimated_coordinates)
        numpy.testing.assert_almost_equal(
            (calc_translation_x, calc_translation_y, calc_scaling_x,
             calc_scaling_y, calc_rotation),
            (translation_x, translation_y, scale_x, scale_y, rotation), 0)
Example #11
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(description=
                     "Automated AR acquisition at multiple spot locations")

    parser.add_argument("--repetitions_x", "-x", dest="repetitions_x", required=True,
                        help="repetitions defines the number of CL spots in the grid (x dimension)")
    parser.add_argument("--repetitions_y", "-y", dest="repetitions_y", required=True,
                        help="repetitions defines the number of CL spots in the grid (y dimension)")
    parser.add_argument("--dwell_time", "-t", dest="dwell_time", required=True,
                        help="dwell_time indicates the time to scan each spot (unit: s)")
    parser.add_argument("--max_allowed_diff", "-d", dest="max_allowed_diff", required=True,
                        help="max_allowed_diff indicates the maximum allowed difference in electron coordinates (unit: m)")

    options = parser.parse_args(args[1:])
    repetitions = (int(options.repetitions_x), int(options.repetitions_y))
    dwell_time = float(options.dwell_time)
    max_allowed_diff = float(options.max_allowed_diff)

    try:
        escan = None
        detector = None
        ccd = None
        # find components by their role
        for c in model.getComponents():
            if c.role == "e-beam":
                escan = c
            elif c.role == "se-detector":
                detector = c
            elif c.role == "ccd":
                ccd = c
        if not all([escan, detector, ccd]):
            logging.error("Failed to find all the components")
            raise KeyError("Not all components found")
    
        # ccd.data.get()
        future_scan = images.ScanGrid(repetitions, dwell_time, escan, ccd, detector)

        # Wait for ScanGrid to finish
        optical_image, electron_coordinates, electron_scale = future_scan.result()
        hdf5.export("scanned_image.h5", optical_image)
        logging.debug("electron coord = %s", electron_coordinates)

        ############## TO BE REMOVED ON TESTING##############
#        grid_data = hdf5.read_data("scanned_image.h5")
#        C, T, Z, Y, X = grid_data[0].shape
#        grid_data[0].shape = Y, X
#        optical_image = grid_data[0]
        #####################################################
    
        logging.debug("Isolating spots...")
        subimages, subimage_coordinates = coordinates.DivideInNeighborhoods(optical_image, repetitions, optical_scale)
        logging.debug("Number of spots found: %d", len(subimages))

        hdf5.export("spot_found.h5", subimages,thumbnail=None)
        logging.debug("Finding spot centers...")
        spot_coordinates = coordinates.FindCenterCoordinates(subimages)
        logging.debug("center coord = %s", spot_coordinates)
        optical_coordinates = coordinates.ReconstructCoordinates(subimage_coordinates, spot_coordinates)
        logging.debug(optical_coordinates)
        rgb_optical = img.DataArray2RGB(optical_image)
        
        for ta in optical_coordinates:
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 0] = 255
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 1] *= 0.5
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 2] *= 0.5
        
        misc.imsave('spots_image.png', rgb_optical)

        # TODO: Make function for scale calculation
        sorted_coordinates = sorted(optical_coordinates, key=lambda tup: tup[1])
        tab = tuple(map(operator.sub, sorted_coordinates[0], sorted_coordinates[1]))
        optical_scale = math.hypot(tab[0], tab[1])
        scale = electron_scale[0] / optical_scale
        print scale

        # max_allowed_diff in pixels
        max_allowed_diff_px = max_allowed_diff / escan.pixelSize.value[0]

        logging.debug("Matching coordinates...")
        known_electron_coordinates, known_optical_coordinates = coordinates.MatchCoordinates(optical_coordinates, electron_coordinates, scale, max_allowed_diff_px)
    
        logging.debug("Calculating transformation...")
        (calc_translation_x, calc_translation_y), (calc_scaling_x, calc_scaling_y), calc_rotation = transform.CalculateTransform(known_electron_coordinates, known_optical_coordinates)
        logging.debug("Electron->Optical: ")
        print calc_translation_x, calc_translation_y, calc_scaling_x, calc_scaling_y, calc_rotation
        final_electron = coordinates._TransformCoordinates(known_optical_coordinates, (calc_translation_x, calc_translation_y), calc_rotation, (calc_scaling_x, calc_scaling_y))

        logging.debug("Overlay done.")
        
        # Calculate distance between the expected and found electron coordinates
        coord_diff = []
        for ta, tb in zip(final_electron, known_electron_coordinates):
            tab = tuple(map(operator.sub, ta, tb))
            coord_diff.append(math.hypot(tab[0], tab[1]))

        mean_difference = numpy.mean(coord_diff) * escan.pixelSize.value[0]

        variance_sum = 0
        for i in range(0, len(coord_diff)):
            variance_sum += (mean_difference - coord_diff[i]) ** 2
        variance = (variance_sum / len(coord_diff)) * escan.pixelSize.value[0]
        
        not_found_spots = len(electron_coordinates) - len(final_electron)

        # Generate overlay image
        logging.debug("Generating images...")
        (calc_translation_x, calc_translation_y), (calc_scaling_x, calc_scaling_y), calc_rotation = transform.CalculateTransform(known_optical_coordinates, known_electron_coordinates)
        logging.debug("Optical->Electron: ")
        print calc_translation_x, calc_translation_y, calc_scaling_x, calc_scaling_y, calc_rotation
        overlay_coordinates = coordinates._TransformCoordinates(known_electron_coordinates, (calc_translation_y, calc_translation_x), -calc_rotation, (calc_scaling_x, calc_scaling_y))

        for ta in overlay_coordinates:
            rgb_optical[ta[0] - 1:ta[0] + 1, ta[1] - 1:ta[1] + 1, 1] = 255
            
        misc.imsave('overlay_image.png', rgb_optical)
        misc.imsave('optical_image.png', optical_image)
        logging.debug("Done. Check electron_image.png, optical_image.png and overlay_image.png.")

    except:
        logging.exception("Unexpected error while performing action.")
        return 127

    logging.info("\n**Overlay precision stats (Resulted to expected electron coordinates comparison)**\n Mean distance: %f (unit: m)\n Variance: %f (unit: m)\n Not found spots: %d", mean_difference, variance, not_found_spots)
    return 0
Example #12
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(
        description="Automated AR acquisition at multiple spot locations")

    parser.add_argument(
        "--repetitions_x",
        "-x",
        dest="repetitions_x",
        required=True,
        help=
        "repetitions defines the number of CL spots in the grid (x dimension)")
    parser.add_argument(
        "--repetitions_y",
        "-y",
        dest="repetitions_y",
        required=True,
        help=
        "repetitions defines the number of CL spots in the grid (y dimension)")
    parser.add_argument(
        "--dwell_time",
        "-t",
        dest="dwell_time",
        required=True,
        help="dwell_time indicates the time to scan each spot (unit: s)")
    parser.add_argument(
        "--max_allowed_diff",
        "-d",
        dest="max_allowed_diff",
        required=True,
        help=
        "max_allowed_diff indicates the maximum allowed difference in electron coordinates (unit: m)"
    )

    options = parser.parse_args(args[1:])
    repetitions = (int(options.repetitions_x), int(options.repetitions_y))
    dwell_time = float(options.dwell_time)
    max_allowed_diff = float(options.max_allowed_diff)

    try:
        escan = None
        detector = None
        ccd = None
        # find components by their role
        for c in model.getComponents():
            if c.role == "e-beam":
                escan = c
            elif c.role == "se-detector":
                detector = c
            elif c.role == "ccd":
                ccd = c
        if not all([escan, detector, ccd]):
            logging.error("Failed to find all the components")
            raise KeyError("Not all components found")

        # ccd.data.get()
        gscanner = GridScanner(repetitions, dwell_time, escan, ccd, detector)

        # Wait for ScanGrid to finish
        optical_image, electron_coordinates, electron_scale = gscanner.DoAcquisition(
        )
        hdf5.export("scanned_image.h5", optical_image)
        logging.debug("electron coord = %s", electron_coordinates)

        ############## TO BE REMOVED ON TESTING##############
        #        grid_data = hdf5.read_data("scanned_image.h5")
        #        C, T, Z, Y, X = grid_data[0].shape
        #        grid_data[0].shape = Y, X
        #        optical_image = grid_data[0]
        #####################################################

        logging.debug("Isolating spots...")
        opxs = optical_image.metadata[model.MD_PIXEL_SIZE]
        optical_dist = escan.pixelSize.value[0] * electron_scale[0] / opxs[0]
        subimages, subimage_coordinates = coordinates.DivideInNeighborhoods(
            optical_image, repetitions, optical_dist)
        logging.debug("Number of spots found: %d", len(subimages))

        hdf5.export("spot_found.h5", subimages, thumbnail=None)
        logging.debug("Finding spot centers...")
        spot_coordinates = spot.FindCenterCoordinates(subimages)
        logging.debug("center coord = %s", spot_coordinates)
        optical_coordinates = coordinates.ReconstructCoordinates(
            subimage_coordinates, spot_coordinates)
        logging.debug(optical_coordinates)
        rgb_optical = img.DataArray2RGB(optical_image)

        for ta in optical_coordinates:
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 0] = 255
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 1] *= 0.5
            rgb_optical[ta[1] - 1:ta[1] + 1, ta[0] - 1:ta[0] + 1, 2] *= 0.5

        misc.imsave('spots_image.png', rgb_optical)

        # TODO: Make function for scale calculation
        sorted_coordinates = sorted(optical_coordinates,
                                    key=lambda tup: tup[1])
        tab = tuple(
            map(operator.sub, sorted_coordinates[0], sorted_coordinates[1]))
        optical_scale = math.hypot(tab[0], tab[1])
        scale = electron_scale[0] / optical_scale
        print(scale)

        # max_allowed_diff in pixels
        max_allowed_diff_px = max_allowed_diff / escan.pixelSize.value[0]

        logging.debug("Matching coordinates...")
        known_electron_coordinates, known_optical_coordinates, max_diff = coordinates.MatchCoordinates(
            optical_coordinates, electron_coordinates, scale,
            max_allowed_diff_px)

        logging.debug("Calculating transformation...")
        (calc_translation_x, calc_translation_y), (
            calc_scaling_x,
            calc_scaling_y), calc_rotation = transform.CalculateTransform(
                known_electron_coordinates, known_optical_coordinates)
        logging.debug("Electron->Optical: ")
        print(calc_translation_x, calc_translation_y, calc_scaling_x,
              calc_scaling_y, calc_rotation)
        final_electron = coordinates._TransformCoordinates(
            known_optical_coordinates,
            (calc_translation_x, calc_translation_y), calc_rotation,
            (calc_scaling_x, calc_scaling_y))

        logging.debug("Overlay done.")

        # Calculate distance between the expected and found electron coordinates
        coord_diff = []
        for ta, tb in zip(final_electron, known_electron_coordinates):
            tab = tuple(map(operator.sub, ta, tb))
            coord_diff.append(math.hypot(tab[0], tab[1]))

        mean_difference = numpy.mean(coord_diff) * escan.pixelSize.value[0]

        variance_sum = 0
        for i in range(0, len(coord_diff)):
            variance_sum += (mean_difference - coord_diff[i])**2
        variance = (variance_sum / len(coord_diff)) * escan.pixelSize.value[0]

        not_found_spots = len(electron_coordinates) - len(final_electron)

        # Generate overlay image
        logging.debug("Generating images...")
        (calc_translation_x, calc_translation_y), (
            calc_scaling_x,
            calc_scaling_y), calc_rotation = transform.CalculateTransform(
                known_optical_coordinates, known_electron_coordinates)
        logging.debug("Optical->Electron: ")
        print(calc_translation_x, calc_translation_y, calc_scaling_x,
              calc_scaling_y, calc_rotation)
        overlay_coordinates = coordinates._TransformCoordinates(
            known_electron_coordinates,
            (calc_translation_y, calc_translation_x), -calc_rotation,
            (calc_scaling_x, calc_scaling_y))

        for ta in overlay_coordinates:
            rgb_optical[ta[0] - 1:ta[0] + 1, ta[1] - 1:ta[1] + 1, 1] = 255

        misc.imsave('overlay_image.png', rgb_optical)
        misc.imsave('optical_image.png', optical_image)
        logging.debug(
            "Done. Check electron_image.png, optical_image.png and overlay_image.png."
        )

    except:
        logging.exception("Unexpected error while performing action.")
        return 127

    logging.info(
        "\n**Overlay precision stats (Resulted to expected electron coordinates comparison)**\n Mean distance: %f (unit: m)\n Variance: %f (unit: m)\n Not found spots: %d",
        mean_difference, variance, not_found_spots)
    return 0