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)
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)
def test_match_coordinates_single_element(self): """ Test MatchCoordinates for single element lists, warning should be thrown """ optical_coordinates = [(9.1243, 6.7570)] electron_coordinates = self.electron_coordinates_1x1 estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates( optical_coordinates, electron_coordinates, 0.25, 0.25) numpy.testing.assert_equal(estimated_coordinates, [])
def test_single_element(self): """ Test MatchCoordinates for single element lists, error should be raised """ optical_coordinates = [(9.1243, 6.7570)] electron_coordinates = self.electron_coordinates_1x1 with self.assertRaises(LookupError): r = coordinates.MatchCoordinates(optical_coordinates, electron_coordinates, 0.25, 0.25)
def test_match_coordinates_precomputed_output(self): """ Test MatchCoordinates for precomputed output """ optical_coordinates = [(9.1243, 6.7570), (10.7472, 16.8185), (4.7271, 12.6429), (13.9714, 6.0185), (5.6263, 17.5885), (14.8142, 10.9271), (10.0384, 11.8815), (15.5146, 16.0694), (4.4803, 7.5966)] electron_coordinates = self.electron_coordinates_3x3 estimated_coordinates, known_optical_coordinates = coordinates.MatchCoordinates( optical_coordinates, electron_coordinates, 0.25, 0.25) numpy.testing.assert_equal(estimated_coordinates, [(2, 1), (2, 3), (1, 2), (3, 1), (1, 3), (3, 2), (2, 2), (3, 3), (1, 1)])
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)
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)
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)
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