Exemple #1
0
def _get_root_tile(tileset, filename):
    folder = os.path.dirname(filename)

    pnts_filename = os.path.join(
        folder,
        tileset['root']['content']['uri'])

    return TileContentReader.read_file(pnts_filename)
Exemple #2
0
def main(args):
    tile = TileContentReader.read_file(args.filename)
    magic = tile.header.magic_value

    if magic == "pnts":
        print_pnts_info(tile)
    elif magic == "b3dm":
        print_b3dm_info(tile)
    else:
        raise RuntimeError("Unsupported format " + magic)
Exemple #3
0
def write_tileset(in_folder, out_folder, octree_metadata, offset, scale, projection, rotation_matrix, include_rgb):
    # compute tile transform matrix
    if rotation_matrix is None:
        transform = np.identity(4)
    else:
        transform = inverse_matrix(rotation_matrix)
    transform = np.dot(transform, scale_matrix(1.0 / scale[0]))
    transform = np.dot(translation_matrix(offset), transform)

    # build fake points
    if True:
        root_node = Node('', octree_metadata.aabb, octree_metadata.spacing * 2)
        root_node.children = []
        inv_aabb_size = (1.0 / (octree_metadata.aabb[1] - octree_metadata.aabb[0])).astype(np.float32)
        for child in ['0', '1', '2', '3', '4', '5', '6', '7']:
            ondisk_tile = name_to_filename(out_folder, child.encode('ascii'), '.pnts')
            if os.path.exists(ondisk_tile):
                tile_content = TileContentReader.read_file(ondisk_tile)
                fth = tile_content.body.feature_table.header
                xyz = tile_content.body.feature_table.body.positions_arr.view(np.float32).reshape((fth.points_length, 3))
                if include_rgb:
                    rgb = tile_content.body.feature_table.body.colors_arr.reshape((fth.points_length, 3))
                else:
                    rgb = np.zeros(xyz.shape, dtype=np.uint8)

                root_node.grid.insert(
                    octree_metadata.aabb[0].astype(np.float32),
                    inv_aabb_size,
                    xyz.copy(),
                    rgb)

        pnts_writer.node_to_pnts(''.encode('ascii'), root_node, out_folder, include_rgb)

    executor = concurrent.futures.ProcessPoolExecutor()
    root_tileset = Node.to_tileset(executor, ''.encode('ascii'), octree_metadata.aabb, octree_metadata.spacing, out_folder, scale)
    executor.shutdown()

    root_tileset['transform'] = transform.T.reshape(16).tolist()
    root_tileset['refine'] = 'REPLACE'
    for child in root_tileset['children']:
        child['refine'] = 'ADD'

    tileset = {
        'asset': {
            'version': '1.0',
        },
        'geometricError': np.linalg.norm(
            octree_metadata.aabb[1] - octree_metadata.aabb[0]) / scale[0],
        'root': root_tileset,
    }

    with open('{}/tileset.json'.format(out_folder), 'w') as f:
        f.write(json.dumps(tileset))
Exemple #4
0
    def test_read(self):
        tile = TileContentReader().read_file('tests/dragon_low.b3dm')

        self.assertEqual(tile.header.version, 1.0)
        self.assertEqual(tile.header.tile_byte_length, 47246)
        self.assertEqual(tile.header.ft_json_byte_length, 20)
        self.assertEqual(tile.header.ft_bin_byte_length, 0)
        self.assertEqual(tile.header.bt_json_byte_length, 0)
        self.assertEqual(tile.header.bt_bin_byte_length, 0)

        with open('tests/dragon_low_gltf_header.json', 'r') as f:
            gltf_header = json.loads(f.read())
        self.assertDictEqual(gltf_header, tile.body.glTF.header)
Exemple #5
0
    def test_read(self):
        tile = TileContentReader().read_file('tests/pointCloudRGB.pnts')

        self.assertEqual(tile.header.version, 1.0)
        self.assertEqual(tile.header.tile_byte_length, 15176)
        self.assertEqual(tile.header.ft_json_byte_length, 148)
        self.assertEqual(tile.header.ft_bin_byte_length, 15000)
        self.assertEqual(tile.header.bt_json_byte_length, 0)
        self.assertEqual(tile.header.bt_bin_byte_length, 0)

        feature_table = tile.body.feature_table
        feature = feature_table.feature(0)
        dcol_res = {'Red': 44, 'Blue': 209, 'Green': 243}
        self.assertDictEqual(dcol_res, feature.colors)
Exemple #6
0
    def test_build(self):
        tread = TileContentReader().read_file('tests/pointCloudRGB.pnts')

        # numpy dtype for positions and colors
        pdt = np.dtype([('X', '<f4'), ('Y', '<f4'), ('Z', '<f4')])
        cdt = np.dtype([('Red', 'u1'), ('Green', 'u1'), ('Blue', 'u1')])

        # create features
        features = []
        for i in range(0, tread.body.feature_table.header.points_length):
            f = tread.body.feature_table.feature(i)
            p = f.positions
            c = f.colors
            pos = np.array([(p['X'], p['Y'], p['Z'])], dtype=pdt).view('uint8')
            col = np.array([(c['Red'], c['Green'], c['Blue'])],
                           dtype=cdt).view('uint8')
            newf = Feature.from_array(pdt, pos, cdt, col)
            features.append(newf)

        # create a tile
        t = Pnts.from_features(pdt, cdt, features)

        # configure the tile
        rtc = [1215012.8828876738, -4736313.051199594, 4081605.22126042]
        t.body.feature_table.header.rtc = rtc

        # get an array
        tile_arr = t.to_array()
        t2 = Pnts.from_array(tile_arr)
        self.assertEqual(t2.header.version, 1.0)
        self.assertEqual(t2.header.tile_byte_length, 15176)
        self.assertEqual(t2.header.ft_json_byte_length, 148)
        self.assertEqual(t2.header.ft_bin_byte_length, 15000)
        self.assertEqual(t2.header.bt_json_byte_length, 0)
        self.assertEqual(t2.header.bt_bin_byte_length, 0)

        feature_table = t.body.feature_table
        feature = feature_table.feature(0)
        dcol_res = {'Red': 44, 'Blue': 209, 'Green': 243}
        self.assertDictEqual(dcol_res, feature.colors)
Exemple #7
0
    def test_build_without_colors(self):
        tread = TileContentReader().read_file('tests/pointCloudRGB.pnts')
        f0_ref = tread.body.feature_table.feature(0).positions

        # numpy dtype for positions and colors
        pdt = np.dtype([('X', '<f4'), ('Y', '<f4'), ('Z', '<f4')])

        # create features
        features = []
        for i in range(0, tread.body.feature_table.header.points_length):
            f = tread.body.feature_table.feature(i)
            p = f.positions
            pos = np.array([(p['X'], p['Y'], p['Z'])], dtype=pdt).view('uint8')
            newf = Feature.from_array(pdt, pos)
            features.append(newf)

        # create a tile
        t = Pnts.from_features(pdt, None, features)

        # configure the tile
        rtc = [1215012.8828876738, -4736313.051199594, 4081605.22126042]
        t.body.feature_table.header.rtc = rtc

        # get an array
        tile_arr = t.to_array()
        t2 = Pnts.from_array(tile_arr)
        self.assertEqual(t2.header.version, 1.0)
        self.assertEqual(t2.header.tile_byte_length, 12152)
        self.assertEqual(t2.header.ft_json_byte_length, 124)
        self.assertEqual(t2.header.ft_bin_byte_length, 12000)
        self.assertEqual(t2.header.bt_json_byte_length, 0)
        self.assertEqual(t2.header.bt_bin_byte_length, 0)

        feature_table = t.body.feature_table
        f0 = feature_table.feature(0).positions

        self.assertAlmostEqual(f0_ref['X'], f0['X'])
        self.assertAlmostEqual(f0_ref['Y'], f0['Y'])
        self.assertAlmostEqual(f0_ref['Z'], f0['Z'])
Exemple #8
0
    def to_tileset(executor, name, parent_aabb, parent_spacing, folder, scale):
        node = node_from_name(name, parent_aabb, parent_spacing)
        aabb = node.aabb
        ondisk_tile = name_to_filename(folder, name, '.pnts')
        xyz, rgb = None, None

        # Read tile's pnts file, if existing, we'll need it for:
        #   - computing the real AABB (instead of the one based on the octree)
        #   - merging this tile's small (<100 points) children
        if os.path.exists(ondisk_tile):
            tile = TileContentReader.read_file(ondisk_tile)
            fth = tile.body.feature_table.header
            xyz = tile.body.feature_table.body.positions_arr
            if fth.colors != SemanticPoint.NONE:
                rgb = tile.body.feature_table.body.colors_arr
            xyz_float = xyz.view(np.float32).reshape((fth.points_length, 3))
            # update aabb based on real values
            aabb = np.array(
                [np.amin(xyz_float, axis=0),
                 np.amax(xyz_float, axis=0)])

        # geometricError is in meters, so we divide it by the scale
        tileset = {'geometricError': 10 * node.spacing / scale[0]}

        children = []
        tile_needs_rewrite = False
        if os.path.exists(ondisk_tile):
            tileset['content'] = {'uri': os.path.relpath(ondisk_tile, folder)}
        for child in ['0', '1', '2', '3', '4', '5', '6', '7']:
            child_name = '{}{}'.format(name.decode('ascii'),
                                       child).encode('ascii')
            child_ondisk_tile = name_to_filename(folder, child_name, '.pnts')

            if os.path.exists(child_ondisk_tile):
                # See if we should merge this child in tile
                if xyz is not None:
                    # Read pnts content
                    tile = TileContentReader.read_file(child_ondisk_tile)
                    fth = tile.body.feature_table.header

                    # If this child is small enough, merge in the current tile
                    if fth.points_length < 100:
                        xyz = np.concatenate(
                            (xyz, tile.body.feature_table.body.positions_arr))

                        if fth.colors != SemanticPoint.NONE:
                            rgb = np.concatenate(
                                (rgb, tile.body.feature_table.body.colors_arr))

                        # update aabb
                        xyz_float = tile.body.feature_table.body.positions_arr.view(
                            np.float32).reshape((fth.points_length, 3))

                        aabb[0] = np.amin(
                            [aabb[0], np.min(xyz_float, axis=0)], axis=0)
                        aabb[1] = np.amax(
                            [aabb[1], np.max(xyz_float, axis=0)], axis=0)

                        tile_needs_rewrite = True
                        os.remove(child_ondisk_tile)
                        continue

                # Add child to the to-be-processed list if it hasn't been merged
                if executor is not None:
                    children += [(child_name, node.aabb, node.spacing, folder,
                                  scale)]
                else:
                    children += [
                        Node.to_tileset(None, child_name, node.aabb,
                                        node.spacing, folder, scale)
                    ]

        # If we merged at least one child tile in the current tile
        # the pnts file needs to be rewritten.
        if tile_needs_rewrite:
            os.remove(ondisk_tile)
            count, filename = points_to_pnts(name, np.concatenate((xyz, rgb)),
                                             folder, rgb is not None)

        center = ((aabb[0] + aabb[1]) * 0.5).tolist()
        half_size = ((aabb[1] - aabb[0]) * 0.5).tolist()
        tileset['boundingVolume'] = {
            'box': [
                center[0], center[1], center[2], half_size[0], 0, 0, 0,
                half_size[1], 0, 0, 0, half_size[2]
            ]
        }

        if executor is not None:
            children = [t for t in executor.map(node_to_tileset, children)]

        if children:
            tileset['children'] = children
        else:
            tileset['geometricError'] = 0.0

        if len(name) > 0 and children:
            if len(json.dumps(tileset)) > 100000:
                tile_root = {
                    'asset': {
                        'version': '1.0',
                    },
                    'refine': 'ADD',
                    'geometricError': tileset['geometricError'],
                    'root': tileset
                }
                tileset_name = 'tileset.{}.json'.format(name.decode('ascii'))
                with open('{}/{}'.format(folder, tileset_name), 'w') as f:
                    f.write(json.dumps(tile_root))
                tileset['content'] = {'uri': tileset_name}
                tileset['children'] = []

        return tileset