def main(): """Main function.""" args = parse_args() syris.init(loglevel=logging.INFO, double_precision=args.double_precision) units = q.Quantity(1, args.units) triangles = make_cube( ).magnitude if args.input is None else read_blender_obj(args.input) triangles = triangles * units tr = geom.Trajectory([(0, 0, 0)] * units) mesh = Mesh(triangles, tr, center=args.center, iterations=args.supersampling) LOG.info('Number of triangles: {}'.format(mesh.num_triangles)) shape = (args.n, args.n) if args.pixel_size is None: if args.input is None: fov = 4. * units else: # Maximum sample size in x and y direction max_diff = np.max(mesh.extrema[:-1, 1] - mesh.extrema[:-1, 0]) fov = max_diff fov *= args.margin args.pixel_size = fov / args.n else: fov = args.n * args.pixel_size if args.translate is None: translate = (fov.simplified.magnitude / 2., fov.simplified.magnitude / 2., 0) * q.m else: translate = (args.translate[0].simplified.magnitude, args.translate[1].simplified.magnitude, 0) * q.m LOG.info('Translation: {}'.format(translate.rescale(q.um))) mesh.translate(translate) mesh.rotate(args.y_rotate, geom.Y_AX) mesh.rotate(args.x_rotate, geom.X_AX) fmt = 'n: {}, pixel size: {}, FOV: {}' LOG.info( fmt.format(args.n, args.pixel_size.rescale(q.um), fov.rescale(q.um))) st = time.time() proj = mesh.project(shape, args.pixel_size, t=None).get() LOG.info('Duration: {} s'.format(time.time() - st)) offset = (0, translate[1].simplified, -(fov / 2.).simplified) * q.m if args.projection_filename is not None: save_image(args.projection_filename, proj) if args.compute_slice: sl = mesh.compute_slices((1, ) + shape, args.pixel_size, offset=offset).get()[0] if args.slice_filename is not None: save_image(args.slice_filename, sl) show(sl, title='Slice at y = {}'.format(args.n / 2)) show(proj, title='Projection') plt.show()
def process(args, device_index): import syris from syris.geometry import Trajectory from syris.bodies.mesh import Mesh, read_blender_obj syris.init(device_index=device_index, logfile=args.logfile, double_precision=args.double_precision) path, ext = os.path.splitext(args.input) if ext == ".obj": tri = read_blender_obj(args.input) else: tri = np.load(args.input) tri = tri * q.um tr = Trajectory([(0, 0, 0)] * q.um) mesh = Mesh(tri, tr, center=None, iterations=args.supersampling_projection) if args.n: n = args.n fov = n * args.pixel_size else: fov = max([ends[1] - ends[0] for ends in mesh.extrema[:-1]]) * 1.1 n = int(np.ceil((fov / args.pixel_size).simplified.magnitude)) shape = (n, n) if args.make_gt: LOG.info("--- Args info ---") log_attributes(args) return make_ground_truth(args, shape, mesh) else: num_projs = int( np.pi * n) if args.num_projections is None else args.num_projections angles = np.linspace(0, args.rotation_angle, num_projs, endpoint=False) * q.deg if device_index == 0: LOG.info("n: {}, ps: {}, FOV: {}".format(n, args.pixel_size, fov)) LOG.info("Total rotation angle: {} deg".format( args.rotation_angle)) LOG.info("Number of projections: {}".format(num_projs)) LOG.info("--- Mesh info ---") log_attributes(mesh) LOG.info("--- Args info ---") log_attributes(args) return scan( shape, args.pixel_size, args.rotation_axis, mesh, angles, args.prefix, lamino_angle=args.lamino_angle, index=device_index, num_devices=args.num_devices, ss=args.supersampling, )
def main(): syris.init() n = 256 shape = (n, n) ps = 1 * q.um fov = n * ps triangles = make_cube().magnitude * n / 8. * ps # Rotation around the vertical axis points = make_circle(axis='y').magnitude * fov / 30000 + fov / 2 trajectory = geom.Trajectory(points, pixel_size=ps, velocity=10 * q.um / q.s) # *orientation* aligns the object with the trajectory derivative mesh = Mesh(triangles, trajectory, orientation=geom.Z_AX) # Compute projection at the angle Pi/4 projection = mesh.project(shape, ps, t=trajectory.time / 8).get() show(projection) plt.show()
def make_cube_body(n, ps, cube_edge, phase_shift=None): fov = n * ps triangles = make_cube().magnitude * cube_edge / 2 # Rotation around the vertical axis points = make_circle(axis="y", overall_angle=np.pi * q.rad, phase_shift=phase_shift).magnitude points = points * fov / 4 + [n // 2, 0, 0] * ps trajectory = geom.Trajectory(points, pixel_size=ps, velocity=ps / q.s) # *orientation* aligns the object with the trajectory derivative mesh = Mesh(triangles, trajectory, orientation=geom.Z_AX) return mesh
def test_project_composite(self): n = 64 shape = (n, n) ps = 1 * q.um x = np.linspace(0, n, num=10) y = z = np.zeros(x.shape) traj_x = Trajectory(zip(x, y, z) * ps, velocity=ps / q.s) traj_y = Trajectory(zip(y, x, z) * ps, velocity=ps / q.s) traj_xy = Trajectory(zip(n - x, x, z) * ps, velocity=ps / q.s) mb = MetaBall(traj_x, n * ps / 16) cube = make_cube() / q.m * 16 * ps / 4 mesh = Mesh(cube, traj_xy) composite = CompositeBody(traj_y, bodies=[mb, mesh]) composite.bind_trajectory(ps) composite.move(n / 2 * q.s) p = composite.project(shape, ps).get() composite.clear_transformation() # Compute composite.move(n / 2 * q.s) p_separate = (mb.project(shape, ps) + mesh.project(shape, ps)).get() np.testing.assert_almost_equal(p, p_separate)
def main(): args = parse_args() syris.init(device_index=0) n = 512 shape = (n, n) ps = 1 * q.um x = np.linspace(0, n, num=10) y = z = np.zeros(x.shape) traj_x = Trajectory(zip(x, y, z) * ps, velocity=ps / q.s) traj_y = Trajectory(zip(y, x, z) * ps, velocity=ps / q.s) traj_xy = Trajectory(zip(n - x, x, z) * ps, velocity=ps / q.s) mb = MetaBall(traj_x, n * ps / 16) cube = make_cube() / q.m * 16 * ps mesh = Mesh(cube, traj_xy) composite = CompositeBody(traj_y, bodies=[mb, mesh]) composite.bind_trajectory(ps) t = args.t * n * q.s composite.move(t) p = composite.project(shape, ps).get() show(p, title='Projection') plt.show()
def make_motion(args): syris.init() n = 256 shape = (n, n) energies = np.arange(5, 30, 1) * q.keV bm, detector = make_devices(n, energies) mb = create_sample(n, detector.pixel_size, velocity=20 * q.mm / q.s) mb_2 = create_sample(n, detector.pixel_size, velocity=10 * q.mm / q.s) mb.material = get_material('pmma_5_30_kev.mat') mb_2.material = mb.material cube = make_cube( ) / q.m * 30 * detector.pixel_size + 0.1 * detector.pixel_size fov = detector.pixel_size * n circle = make_circle().magnitude * fov / 30000 + fov / 2 tr = Trajectory(circle, velocity=10 * q.um / q.s) glass = get_material('glass.mat') mesh = Mesh(cube, tr, material=glass) ex = Experiment([bm, mb, mb_2, mesh], bm, detector, 0 * q.m, energies) for sample in ex.samples: if sample != bm: sample.trajectory.bind(detector.pixel_size) if args.show_flat: show(get_flat(shape, energies, detector, bm), title='Counts') plt.show() if args.conduct: if args.output is not None and not os.path.exists(args.output): os.makedirs(args.output, mode=0o755) t_0 = 0 * q.s if args.num_images: t_1 = args.num_images / detector.camera.fps else: t_1 = ex.time st = time.time() mpl_im = None for i, proj in enumerate(ex.make_sequence(t_0, t_1)): image = get_host(proj) if args.show: if mpl_im is None: plt.figure() mpl_im = plt.imshow(image) plt.show(False) else: mpl_im.set_data(image) plt.draw() if args.output: path = os.path.join(args.output, 'projection_{:>05}.png').format(i) scipy.misc.imsave(path, image) print 'Maximum intensity:', image.max() print 'Duration: {} s'.format(time.time() - st) plt.show()
class TestMesh(SyrisTest): def setUp(self): default_syris_init() self.triangles = make_cube() self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.mesh = Mesh(self.triangles, self.trajectory) def shift_mesh(self, point): triangles = self.triangles + np.array(point)[:, np.newaxis] * point.units return Mesh(triangles, self.trajectory, center=None) def test_furthest_point(self): self.assertAlmostEqual(get_magnitude(self.mesh.furthest_point), np.sqrt(3)) def test_bounding_box(self): bbox_points = get_magnitude(self.mesh.bounding_box.points).astype( np.int).tolist() seed = (-1, 1) for point in itertools.product(seed, seed, seed): self.assertTrue(list(point) in bbox_points) def test_num_triangles(self): self.assertEqual(12, self.mesh.num_triangles) def test_extrema(self): for endpoints in self.mesh.extrema: self.assertAlmostEqual(-1, get_magnitude(endpoints[0])) self.assertAlmostEqual(1, get_magnitude(endpoints[1])) def test_center_of_gravity(self): gt = (1, 2, 3) * q.m mesh = self.shift_mesh(gt) center = get_magnitude(mesh.center_of_gravity) np.testing.assert_almost_equal(get_magnitude(gt), center) def test_center_of_bbox(self): gt = (1, 2, 3) * q.m mesh = self.shift_mesh(gt) center = get_magnitude(mesh.center_of_bbox) np.testing.assert_almost_equal(get_magnitude(gt), center) def test_diff(self): gt = np.ones((3, 2)) * 2 np.testing.assert_almost_equal(gt, get_magnitude(self.mesh.diff)) def test_vectors(self): ba, ca = self.mesh.vectors a = self.triangles[:, ::3] b = self.triangles[:, 1::3] c = self.triangles[:, 2::3] ba_gt = (b - a).transpose() ca_gt = (c - a).transpose() np.testing.assert_almost_equal(ba_gt, ba) np.testing.assert_almost_equal(ca_gt, ca) def test_areas(self): np.testing.assert_almost_equal(2 * q.m**2, self.mesh.areas) def test_normals(self): v_0, v_1 = self.mesh.vectors gt = np.cross(v_0, v_1) * q.um np.testing.assert_almost_equal(gt, self.mesh.normals) def test_max_triangle_x_diff(self): self.assertEqual(2 * q.m, self.mesh.max_triangle_x_diff) def test_sort(self): self.mesh.sort() x = get_magnitude(self.mesh.triangles[0, 2::3]) # Triangles must be sorted by the last vertex np.testing.assert_almost_equal(x, sorted(x)) # The greatest is the last vertex in a triangle, all other vertices must be smaller x = get_magnitude(self.mesh.triangles[0, :]) for i in range(0, len(x), 3): self.assertTrue(x[i] <= x[i + 2]) self.assertTrue(x[i + 1] <= x[i + 2]) def test_get_degenerate_triangles(self): triangles = get_magnitude(self.mesh.get_degenerate_triangles()) for i in range(0, triangles.shape[1], 3): vertices = triangles[:, i:i + 3] x = vertices[0, :] y = vertices[1, :] x_any = np.any(x - x[0]) y_any = np.any(y - y[0]) self.assertTrue(not (x_any and y_any)) self.mesh.rotate(45 * q.deg, X_AX) self.mesh.rotate(45 * q.deg, Y_AX) self.mesh.transform() self.assertEqual(0, self.mesh.get_degenerate_triangles().shape[1])
def shift_mesh(self, point): triangles = self.triangles + np.array(point)[:, np.newaxis] * point.units return Mesh(triangles, self.trajectory, center=None)
def setUp(self): default_syris_init() self.triangles = make_cube() self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.mesh = Mesh(self.triangles, self.trajectory)
def setUp(self): syris.init(device_index=0) self.triangles = make_cube() self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.mesh = Mesh(self.triangles, self.trajectory)
class TestMesh(SyrisTest): def setUp(self): syris.init(device_index=0) self.triangles = make_cube() self.trajectory = Trajectory([(0, 0, 0)] * q.m) self.mesh = Mesh(self.triangles, self.trajectory) def shift_mesh(self, point): triangles = self.triangles + np.array(point)[:, np.newaxis] * point.units return Mesh(triangles, self.trajectory, center=None) def test_furthest_point(self): self.assertAlmostEqual(get_magnitude(self.mesh.furthest_point), np.sqrt(3)) def test_bounding_box(self): bbox_points = get_magnitude(self.mesh.bounding_box.points).astype(np.int).tolist() seed = (-1, 1) for point in itertools.product(seed, seed, seed): self.assertTrue(list(point) in bbox_points) def test_num_triangles(self): self.assertEqual(12, self.mesh.num_triangles) def test_extrema(self): for endpoints in self.mesh.extrema: self.assertAlmostEqual(-1, get_magnitude(endpoints[0])) self.assertAlmostEqual(1, get_magnitude(endpoints[1])) def test_center_of_gravity(self): gt = (1, 2, 3) * q.m mesh = self.shift_mesh(gt) center = get_magnitude(mesh.center_of_gravity) np.testing.assert_almost_equal(get_magnitude(gt), center) def test_center_of_bbox(self): gt = (1, 2, 3) * q.m mesh = self.shift_mesh(gt) center = get_magnitude(mesh.center_of_bbox) np.testing.assert_almost_equal(get_magnitude(gt), center) def test_diff(self): gt = np.ones((3, 2)) * 2 np.testing.assert_almost_equal(gt, get_magnitude(self.mesh.diff)) def test_vectors(self): ba, ca = self.mesh.vectors a = self.triangles[:, ::3] b = self.triangles[:, 1::3] c = self.triangles[:, 2::3] ba_gt = (b - a).transpose() ca_gt = (c - a).transpose() np.testing.assert_almost_equal(ba_gt, ba) np.testing.assert_almost_equal(ca_gt, ca) def test_areas(self): np.testing.assert_almost_equal(2 * q.m ** 2, self.mesh.areas) def test_normals(self): v_0, v_1 = self.mesh.vectors gt = np.cross(v_0, v_1) * q.um np.testing.assert_almost_equal(gt, self.mesh.normals) def test_max_triangle_x_diff(self): self.assertEqual(2 * q.m, self.mesh.max_triangle_x_diff) def test_sort(self): self.mesh.sort() x = get_magnitude(self.mesh.triangles[0, 2::3]) # Triangles must be sorted by the last vertex np.testing.assert_almost_equal(x, sorted(x)) # The greatest is the last vertex in a triangle, all other vertices must be smaller x = get_magnitude(self.mesh.triangles[0, :]) for i in range(0, len(x), 3): self.assertTrue(x[i] <= x[i + 2]) self.assertTrue(x[i + 1] <= x[i + 2]) def test_get_degenerate_triangles(self): triangles = get_magnitude(self.mesh.get_degenerate_triangles()) for i in range(0, triangles.shape[1], 3): vertices = triangles[:, i:i + 3] x = vertices[0, :] y = vertices[1, :] x_any = np.any(x - x[0]) y_any = np.any(y - y[0]) self.assertTrue(not (x_any and y_any)) self.mesh.rotate(45 * q.deg, X_AX) self.mesh.rotate(45 * q.deg, Y_AX) self.mesh.transform() self.assertEqual(0, self.mesh.get_degenerate_triangles().shape[1])
def make_complex_trajectory_sequence(args): edge = 20 x = np.linspace(0, args.n / 2 - args.n / 4 - edge - 5, num=10) y = z = np.zeros(x.shape) # Move along x axis traj_x = Trajectory(zip(x, y, z) * args.ps, velocity=args.ps / q.s, pixel_size=args.ps) # Move along y axis traj_y = Trajectory(zip(y, x, z) * args.ps, velocity=args.ps / q.s, pixel_size=args.ps) # Move along both x and y axes traj_xy = Trajectory(zip(x, x, z) * args.ps, velocity=args.ps / q.s, pixel_size=args.ps) # Circular trajectory of the composite body rotates around the image center and with radius # n / 4 pixels. circle = args.n / 2 * args.ps + make_circle( ).magnitude * args.n / 4 * args.ps traj_circle = Trajectory(circle, velocity=args.ps / q.s, pixel_size=args.ps) # Make the trajectory of the circle the same duration as the simple linear one. traj_circle = Trajectory(circle, velocity=traj_circle.length / traj_xy.length * args.ps / q.s) # three cubes in the same height and depth, shifted only along the x axis. traj_stationary = Trajectory([(0, 0, 0)] * args.ps) traj_stationary_1 = Trajectory([(-2 * edge, 0, 0)] * args.ps) traj_stationary_2 = Trajectory([(2 * edge, 0, 0)] * args.ps) cube = make_cube() / q.m * edge * args.ps # The cubes are elongated along y axis. cube[::2, :] /= 3 mesh = Mesh(cube, traj_x, orientation=geom.Y_AX) mesh_2 = Mesh(cube, traj_y, orientation=geom.Y_AX) mesh_3 = Mesh(cube, traj_xy, orientation=geom.Y_AX) mesh_stationary = Mesh(cube, traj_stationary, orientation=geom.Y_AX) mesh_stationary_1 = Mesh(cube, traj_stationary_1, orientation=geom.Y_AX) mesh_stationary_2 = Mesh(cube, traj_stationary_2, orientation=geom.Y_AX) bodies = [ mesh, mesh_2, mesh_3, mesh_stationary, mesh_stationary_1, mesh_stationary_2 ] composite = CompositeBody(traj_circle, bodies=bodies, orientation=geom.Y_AX) composite.bind_trajectory(args.ps) total_time = composite.time if args.t is None: times = np.linspace(0, 1, 100) else: if args.t < 0 or args.t > 1: raise ValueError('--t must be in the range [0, 1]') times = [args.t] im = None for index, i in enumerate(times): t = i * total_time composite.clear_transformation() composite.move(t) p = composite.project(args.shape, args.ps).get() if im is None: im = show(p, title='Projection') else: im.set_data(p) plt.draw() plt.show()
def read_collada(filename, scene_origin, orientation=geom.X_AX, mapping='xxyzz-y', iterations=1): """Read collada (*.dae) scene file *filename* and return list with objects of type Mesh. Place it at *scene_origin*. *orientation* specifies the direction of orientation vectors for all meshes. Scene objects must have materials assigned. For assigned material 'Material', a syris material file 'Material.mat' is expected *filename*'s path. *mapping* can be used to change the mapping of coordinate systems between syris and collada scenes. Standard is 'xxyzz-y' to make z (collada) point upwards in syris (-y). Options are 'xxyyzz' and 'xxyzz-y'. *iterations* is passed to all mesh objects. Only geometry is imported, i.e there is currently no support for animated objects.""" e = xml.etree.ElementTree.parse(filename).getroot() ns = {'co': 'http://www.collada.org/2005/11/COLLADASchema'} scene_units = float(e.findall('co:asset/co:unit', ns)[0].get("meter")) * q.m geometries = e.findall('co:library_geometries/co:geometry', ns) visual_scene = e.find('co:library_visual_scenes/co:visual_scene', ns) #animations = e.find('cp:library_animations/co:animation') Meshes = [] for g in geometries: geom_name = g.get("id")[:-5] m = g.find('co:mesh', ns) arrays = m.findall("co:source/co:float_array",ns) pattern = re.compile(r'(?P<x>[0-9e.-]*) (?P<y>[0-9e.-]*) (?P<z>[0-9e.-]*) ') vstr = arrays[0].text + " " vertices = np.array(re.findall(pattern, vstr)).astype(np.float32) polylistr = m.find('co:polylist/co:p', ns).text + " " faces = np.array(polylistr.split()[::2]).astype(np.int) triangles = vertices[faces] if(mapping == 'xxyzz-y'): # mapping corresponds to rotation around x-axis by 90 deg. mat_mapping = geom.rotate(90* q.deg, geom.X_AX) elif(mapping == 'xxyyzz'): mat_mapping = np.identity(4) else: raise ValueError('Invalid mapping option for collada import.') # above vertices are stored with respect to their object origin, # transform them to obtain global vertex coordinates # there are two possible ways to specify transformations in collada, matrix and transloc: # find out which one was used and apply transformations arg = "co:node[@name='" + geom_name + "']" trafos = visual_scene.find(arg,ns) if(trafos.find("co:rotate[@sid='rotationZ']", ns) is not None): # TransLoc format rotZ = float(trafos.find("co:rotate[@sid='rotationZ']", ns).text.split()[-1]) rotY = float(trafos.find("co:rotate[@sid='rotationY']", ns).text.split()[-1]) rotX = float(trafos.find("co:rotate[@sid='rotationX']", ns).text.split()[-1]) scale = map(float, trafos.find("co:scale[@sid='scale']", ns).text.split()) str_origin = trafos.find("co:translate[@sid='location']", ns).text.split() origin = map(float, str_origin) * q.dimensionless matr_x = geom.rotate(rotX * q.deg, geom.X_AX) matr_y = geom.rotate(rotY * q.deg, geom.Y_AX) matr_z = geom.rotate(rotZ * q.deg, geom.Z_AX) mat_trans = geom.translate(origin) mat_scale = geom.scale(scale) # build transformation matrix mat = np.dot(mat_mapping, mat_trans) mat = np.dot(mat, mat_scale) mat = np.dot(mat, matr_z) mat = np.dot(mat, matr_y) mat = np.dot(mat, matr_x) elif (trafos.find("co:matrix[@sid='transform']", ns) is not None): # Matrix format str_mat = trafos.find("co:matrix[@sid='transform']", ns).text.split() mat = np.dot(mat_mapping, np.array(str_mat, dtype = float).reshape(4,4)) else: raise RuntimeError("Transformation type in collada file could not be determined.") # apply transformation to vertices for i, vert in enumerate(triangles): vert = (tuple(vert) + (1,)) triangles[i] = np.dot(mat, vert)[:-1] triangles = triangles.transpose() # handle materials material = m.find('co:polylist', ns).get("material")[:-9] + ".mat" matname = os.path.join(os.path.dirname(filename), material) if(not os.path.isfile(matname)): raise RuntimeError("Materialfile {} not found. Files have to be in the same "\ "directory as the corresponding collada scene file.".format(matname)) m = make_fromfile(matname) # create and add Mesh object tr = geom.Trajectory(scene_origin) mesh = Mesh(triangles * scene_units , tr, material = m, center = None, orientation = orientation, iterations = iterations) Meshes.extend([ mesh ]) return Meshes