Ejemplo n.º 1
0
def pcap_read_packets(
        pcap_path: str,
        metadata_path: str,
        num: int = 0  # not used in this examples
) -> None:
    """Basic read packets example from pcap file (*pcap_path*)

    Args:
        pcap_path: path to the pcap file
        metadata_path: path to the .json with metadata (aka :class:`.SensorInfo`)
    """

    metadata = read_metadata(metadata_path)
    source = pcap.Pcap(pcap_path, metadata)

    # [doc-stag-pcap-read-packets]
    for packet in source:
        if isinstance(packet, client.LidarPacket):
            # Now we can process the LidarPacket. In this case, we access
            # the encoder_counts, timestamps, and ranges
            encoder_counts = packet.header(client.ColHeader.ENCODER_COUNT)
            timestamps = packet.header(client.ColHeader.TIMESTAMP)
            ranges = packet.field(client.ChanField.RANGE)
            print(f'  encoder counts = {encoder_counts.shape}')
            print(f'  timestamps = {timestamps.shape}')
            print(f'  ranges = {ranges.shape}')

        if isinstance(packet, client.ImuPacket):
            # and access ImuPacket content
            print(f'  acceleration = {packet.accel}')
            print(f'  angular_velocity = {packet.angular_vel}')
Ejemplo n.º 2
0
def packet(real_pcap_path: str, meta: client.SensorInfo) -> client.LidarPacket:
    # note: don't want to depend on the pcap fixture, since this consumes the
    # iterator and it can be shared
    with closing(pcap.Pcap(real_pcap_path, meta)) as real_pcap:
        for p in real_pcap:
            if isinstance(p, client.LidarPacket):
                return p
        raise RuntimeError("Failed to find lidar packet in test fixture")
Ejemplo n.º 3
0
def test_pcap_read_wrong_ports(fake_meta, fake_pcap_path) -> None:
    """Check specifying wrong ports."""
    fake_pcap = pcap.Pcap(fake_pcap_path,
                          fake_meta,
                          lidar_port=7505,
                          imu_port=7506)
    assert fake_pcap.ports == (7505, 7506)
    assert fake_pcap._guesses == []
    assert list(fake_pcap) == []
Ejemplo n.º 4
0
def test_pcap_guess_real(meta: client.SensorInfo, real_pcap_path: str) -> None:
    """Check that lidar port for real data can inferred."""

    meta_no_ports = copy(meta)
    meta_no_ports.udp_port_lidar = 0
    meta_no_ports.udp_port_imu = 0

    real_pcap = pcap.Pcap(real_pcap_path, meta_no_ports)
    assert real_pcap.ports[0] == 7502
Ejemplo n.º 5
0
def test_pcap_infer_one_port(fake_meta, fake_pcap_path) -> None:
    """Check that a matching port is inferred when one is specified. """
    fake_pcap = pcap.Pcap(fake_pcap_path,
                          fake_meta,
                          lidar_port=0,
                          imu_port=7503)
    assert fake_pcap._guesses == [(7502, 7503)]
    assert fake_pcap.ports == (7502, 7503)
    assert len(list(fake_pcap)) == 10
Ejemplo n.º 6
0
def main() -> None:
    descr = """Visualize pcap or sensor data using simple viz bindings."""

    epilog = """When reading data from a sensor, this will autoconfigure the udp
        destination unless -x is used."""

    parser = argparse.ArgumentParser(description=descr, epilog=epilog)

    required = parser.add_argument_group('one of the following is required')
    group = required.add_mutually_exclusive_group(required=True)
    group.add_argument('--sensor', metavar='HOST', help='sensor hostname')
    group.add_argument('--pcap', metavar='PATH', help='path to pcap file')
    parser.add_argument('--meta', metavar='PATH', help='path to metadata json')
    parser.add_argument('--lidar-port', type=int, help='lidar port for sensor')
    parser.add_argument('-x',
                        '--no-auto-dest',
                        action='store_true',
                        help='do not auto configure udp destination')

    args = parser.parse_args()

    if args.sensor:
        hostname = args.sensor
        if args.lidar_port or (not args.no_auto_dest):
            config = client.SensorConfig()
            if args.lidar_port:
                config.udp_port_lidar = args.lidar_port
            print("Configuring sensor...")
            client.set_config(hostname,
                              config,
                              udp_dest_auto=(not args.no_auto_dest))
        config = client.get_config(hostname)

        print("Initializing...")
        scans = client.Scans.stream(hostname,
                                    config.udp_port_lidar or 7502,
                                    complete=False)
        rate = None

    elif args.pcap:
        import ouster.pcap as pcap

        if args.meta:
            metadata_path = args.meta
        else:
            print("Deducing metadata based on pcap name. "
                  "To provide a different metadata path, use --meta")
            metadata_path = os.path.splitext(args.pcap)[0] + ".json"

        with open(metadata_path) as json:
            info = client.SensorInfo(json.read())
        scans = client.Scans(pcap.Pcap(args.pcap, info))
        rate = 1.0

    SimpleViz(scans.metadata, rate).run(scans)
Ejemplo n.º 7
0
def test_read_write_lidar_imu(n_lidar, n_imu, fake_meta, tmpdir) -> None:
    """Test that random packets read back from pcap are identical."""
    in_packets = list(fake_packets(fake_meta, n_lidar, n_imu))
    file_path = path.join(tmpdir, "pcap_test.pcap")

    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, fake_meta))
    out_bufs = [bytes(p._data) for p in out_packets]
    in_bufs = [bytes(p._data) for p in in_packets]

    assert in_bufs == out_bufs
Ejemplo n.º 8
0
def test_pcap_guess_one_port_valid(fake_meta, fake_pcap_path) -> None:
    """Check that an unpaired port can be infered.

    Capture contains just lidar data on 7502, and user expects imu on 7503.
    """
    fake_pcap = pcap.Pcap(fake_pcap_path,
                          fake_meta,
                          lidar_port=0,
                          imu_port=7503)
    assert fake_pcap._guesses == [(7502, 0)]  # no imu packets, no guess
    assert fake_pcap.ports == (7502, 7503)
    assert len(list(fake_pcap)) == 10
Ejemplo n.º 9
0
def test_pcap_guess_one_port_invalid(fake_meta, fake_pcap_path) -> None:
    """Check that a port belonging to another pair isn't inferred.

    Capture contains data on (7502, 7503), but user expects lidar data on 7505.
    """
    fake_pcap = pcap.Pcap(fake_pcap_path,
                          fake_meta,
                          lidar_port=7505,
                          imu_port=0)
    assert fake_pcap._guesses == []
    assert fake_pcap.ports == (7505, 0)
    assert list(fake_pcap) == []
Ejemplo n.º 10
0
def main():
    """Pcap examples runner."""
    examples = {
        "plot-xyz-points": pcap_display_xyz_points,
        "2d-viewer": pcap_2d_viewer,
        "read-packets": pcap_read_packets,
        "plot-one-scan": pcap_show_one_scan,
        "pcap-to-csv": pcap_to_csv,
        "pcap-to-pcd": pcap_to_pcd,
        "pcap-to-las": pcap_to_las,
        "open3d-one-scan": pcap_3d_one_scan,
    }

    description = "Ouster Python SDK Pcap examples. The EXAMPLE must be one of:\n" + str.join(
        '\n  ', examples.keys())

    parser = argparse.ArgumentParser(
        description=description, formatter_class=argparse.RawTextHelpFormatter)

    parser.add_argument('pcap_path', metavar='PCAP', help='path to pcap file')
    parser.add_argument('metadata_path',
                        metavar='METADATA',
                        help='path to metadata json')
    parser.add_argument('example',
                        metavar='EXAMPLE',
                        choices=examples.keys(),
                        help='name of the example to run')
    parser.add_argument('--scan-num',
                        type=int,
                        default=1,
                        help='index of scan to use')
    args = parser.parse_args()

    try:
        example = examples[args.example]
    except KeyError:
        print(f"No such example: {args.example}")
        print(description)
        exit(1)

    if not args.metadata_path or not os.path.exists(args.metadata_path):
        print(f"Metadata file does not exist: {args.metadata_path}")
        exit(1)

    print(f'example: {args.example}')

    with open(args.metadata_path, 'r') as f:
        metadata = client.SensorInfo(f.read())
    source = pcap.Pcap(args.pcap_path, metadata)

    with closing(source):
        example(source, metadata, args.scan_num)  # type: ignore
Ejemplo n.º 11
0
def test_timestamp_read_write(fake_meta, tmpdir) -> None:
    """Check that timestamps are preserved by a round trip."""
    in_packets = list(
        fake_packets(fake_meta, n_lidar=10, n_imu=10, timestamped=True))
    file_path = path.join(tmpdir, "pcap_test.pcap")

    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, fake_meta))
    out_timestamps = [p.capture_timestamp for p in out_packets]
    in_timestamps = [p.capture_timestamp for p in in_packets]

    assert len(in_timestamps) == len(out_timestamps)
    assert in_timestamps == pytest.approx(out_timestamps)
Ejemplo n.º 12
0
def test_read_write_lidar_imu(n_lidar, n_imu, metadata, tmpdir):
    """Test that random packets read back from pcap are identical."""
    lidar_packets = islice(random_lidar_packets(metadata), n_lidar)
    imu_packets = islice(random_imu_packets(metadata), n_imu)
    in_packets = list(chain(lidar_packets, imu_packets))

    shuffle(in_packets)

    file_path = os.path.join(tmpdir, "pcap_test.pcap")

    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, metadata))
    out_bufs = [bytes(p._data) for p in out_packets]
    in_bufs = [bytes(p._data) for p in in_packets]
    assert in_bufs == out_bufs
Ejemplo n.º 13
0
def test_imu_guess_error(metadata, tmpdir):
    packets = islice(random_imu_packets(metadata), 2)
    file_path = os.path.join(tmpdir, "pcap_test.pcap")

    buf_size = 2**16
    handle = _pcap.record_initialize(file_path, "127.0.0.1", "127.0.0.1",
                                     buf_size)
    try:
        _pcap.record_packet(handle, 7502, 7502, (next(packets))._data, 1)
        _pcap.record_packet(handle, 7503, 7503, (next(packets))._data, 2)
    finally:
        _pcap.record_uninitialize(handle)

    with pytest.raises(ValueError):
        pcap.Pcap(file_path, metadata)
Ejemplo n.º 14
0
def test_no_timestamp_read_write(fake_meta, tmpdir) -> None:
    """Check that capture timestamps are set when recording."""
    in_packets = list(
        fake_packets(fake_meta, n_lidar=10, n_imu=10, timestamped=False))
    file_path = path.join(tmpdir, "pcap_test.pcap")

    current_timestamp = time.time()
    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, fake_meta))
    out_timestamps = [p.capture_timestamp for p in out_packets]
    in_timestamps = [p.capture_timestamp for p in in_packets]

    assert len(in_timestamps) == len(out_timestamps)
    assert all(ts is None for ts in in_timestamps)
    assert all(ts == pytest.approx(current_timestamp, abs=1.0)
               for ts in out_timestamps)
Ejemplo n.º 15
0
def main() -> None:
    import argparse
    import os
    import ouster.pcap as pcap

    descr = """Example visualizer using the open3d library.

    Visualize either pcap data (specified using --pcap) or a running sensor
    (specified using --sensor). If no metadata file is specified, this will look
    for a file with the same name as the pcap with the '.json' extension, or
    query it directly from the sensor.

    Visualizing a running sensor requires the sensor to be configured and
    sending lidar data to the default UDP port (7502) on the host machine.
    """

    parser = argparse.ArgumentParser(description=descr)
    parser.add_argument('--pause', action='store_true', help='start paused')
    parser.add_argument('--start', type=int, help='skip to frame number')
    parser.add_argument('--meta', metavar='PATH', help='path to metadata json')

    required = parser.add_argument_group('one of the following is required')
    group = required.add_mutually_exclusive_group(required=True)
    group.add_argument('--sensor', metavar='HOST', help='sensor hostname')
    group.add_argument('--pcap', metavar='PATH', help='path to pcap file')

    args = parser.parse_args()

    if args.sensor:
        scans = client.Scans.stream(args.sensor, metadata=args.meta)
    elif args.pcap:
        pcap_path = args.pcap
        metadata_path = args.meta or os.path.splitext(pcap_path)[0] + ".json"

        with open(metadata_path, 'r') as f:
            metadata = client.SensorInfo(f.read())

        source = pcap.Pcap(pcap_path, metadata)
        scans = client.Scans(source)
        consume(scans, args.start or 0)

    try:
        viewer_3d(scans, paused=args.pause)
    except (KeyboardInterrupt, StopIteration):
        pass
    finally:
        scans.close()
Ejemplo n.º 16
0
def pcap_show_one_scan(pcap_path: str,
                       metadata_path: str,
                       num: int = 0,
                       destagger: bool = True) -> None:
    """Show all 4 channels of one scan (*num*) form pcap file (*pcap_path*)

    Args:
        pcap_path: path to the pcap file
        metadata_path: path to the .json with metadata (aka :class:`.SensorInfo`)
        num: scan number in a given pcap file (satrs from *0*)
    """
    import matplotlib.pyplot as plt  # type: ignore

    # [doc-stag-pcap-show-one]
    metadata = read_metadata(metadata_path)

    def prepare_field_image(scan, key, metadata, destagger=True):
        f = ae(scan.field(key))
        if destagger:
            return client.destagger(metadata, f)
        return f

    show_fields = [('range', client.ChanField.RANGE),
                   ('signal', client.ChanField.SIGNAL),
                   ('near_ir', client.ChanField.NEAR_IR),
                   ('reflectivity', client.ChanField.REFLECTIVITY)]

    with closing(pcap.Pcap(pcap_path, metadata)) as source:
        scan = nth(client.Scans(source), num)
        if not scan:
            return

        fields_images = [(sf[0],
                          prepare_field_image(scan, sf[1], source.metadata))
                         for sf in show_fields]

        fig = plt.figure(constrained_layout=True)

        axs = fig.subplots(len(fields_images), 1, sharey=True)

        for ax, field in zip(axs, fields_images):
            ax.set_title(field[0], fontdict={'fontsize': 10})
            ax.imshow(field[1], cmap='gray', resample=False)
            ax.set_yticklabels([])
            ax.set_yticks([])
            ax.set_xticks([0, scan.w])
        plt.show()
Ejemplo n.º 17
0
def test_imu_guess_ambiguous(fake_meta, tmpdir) -> None:
    """Test reading when there's more than one possible imu port."""
    packets = fake_packets(fake_meta, n_imu=2)
    file_path = path.join(tmpdir, "pcap_test.pcap")

    buf_size = 2**16
    handle = _pcap.record_initialize(file_path, "127.0.0.1", "127.0.0.1",
                                     buf_size)
    try:
        _pcap.record_packet(handle, 7502, 7502, (next(packets))._data, 1)
        _pcap.record_packet(handle, 7503, 7503, (next(packets))._data, 2)
    finally:
        _pcap.record_uninitialize(handle)

    source = pcap.Pcap(file_path, fake_meta)
    assert len(source._guesses) > 1
    assert source.ports == (0, 7503)  # arbitrary but deterministic
    assert len(list(source)) == 1
Ejemplo n.º 18
0
def pcap_display_xyz_points(pcap_path: str,
                            metadata_path: str,
                            num: int = 0) -> None:
    """Display range from a specified scan number (*num*) as 3D points from
    pcap file located at *pcap_path*

    Args:
        pcap_path: path to the pcap file
        metadata_path: path to the .json with metadata (aka :class:`.SensorInfo`)
        num: scan number in a given pcap file (satrs from *0*)
    """
    import matplotlib.pyplot as plt  # type: ignore

    # [doc-stag-pcap-plot-xyz-points]
    metadata = read_metadata(metadata_path)
    source = pcap.Pcap(pcap_path, metadata)

    # get single scan
    scans = client.Scans(source)
    scan = nth(scans, num)
    if not scan:
        print(f'ERROR: Scan # {num} in not present in pcap file: {pcap_path}')
        return

    # set up figure
    plt.figure()
    ax = plt.axes(projection='3d')
    r = 6
    ax.set_xlim3d([-r, r])
    ax.set_ylim3d([-r, r])
    ax.set_zlim3d([-r, r])

    plt.title("3D Points XYZ for scan")

    # transform data to 3d points and graph
    xyzlut = client.XYZLut(metadata)
    xyz = xyzlut(scan)

    key = scan.field(client.ChanField.SIGNAL)

    [x, y, z] = [c.flatten() for c in np.dsplit(xyz, 3)]
    ax.scatter(x, y, z, c=ae(key.flatten()), s=0.2)
    plt.show()
Ejemplo n.º 19
0
def test_timestamp_float_read_write(mode, metadata, tmpdir):
    lidar_packets = islice(random_lidar_packets(metadata, random_time=mode),
                           10)
    imu_packets = islice(random_imu_packets(metadata, random_time=mode), 10)
    in_packets = list(chain(lidar_packets, imu_packets))

    file_path = os.path.join(tmpdir, "pcap_test.pcap")

    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, metadata))
    out_timestamps = []
    in_timestamps = []

    out_timestamps = [p.capture_timestamp for p in out_packets]
    in_timestamps = [p.capture_timestamp for p in in_packets]

    assert len(in_timestamps) == len(out_timestamps)
    for i, o in zip(in_timestamps, out_timestamps):
        # Make sure to deal with float rounding issues in the compare
        assert i == pytest.approx(o, abs=1e-6)
Ejemplo n.º 20
0
def test_no_timestamp_read_write(metadata, tmpdir):
    mode = NO_RANDOM_TIME
    current_timestamp = time.time()
    lidar_packets = islice(random_lidar_packets(metadata, random_time=mode),
                           10)
    imu_packets = islice(random_imu_packets(metadata, random_time=mode), 10)
    in_packets = list(chain(lidar_packets, imu_packets))

    file_path = os.path.join(tmpdir, "pcap_test.pcap")

    pcap.record(in_packets, file_path)
    out_packets = list(pcap.Pcap(file_path, metadata))
    out_timestamps = []
    in_timestamps = []

    out_timestamps = [p.capture_timestamp for p in out_packets]
    in_timestamps = [p.capture_timestamp for p in in_packets]

    assert len(in_timestamps) == len(out_timestamps)
    for i, o in zip(in_timestamps, out_timestamps):
        assert i is None
        assert current_timestamp == pytest.approx(o, abs=5e-1)
Ejemplo n.º 21
0
def test_pcap_info_10(pcap_path, metadata) -> None:
    """Check that reading a test pcap produces the right number of packets."""
    res = pcap.Pcap(pcap_path, metadata)
    ports = {}
    sizes = {}
    encap = {}
    net = {}
    af = {}
    for item in pcap._pcap_info(pcap_path):
        if item.dst_port not in ports:
            ports[item.dst_port] = 0
        ports[item.dst_port] += 1

        if item.payload_size not in sizes:
            sizes[item.payload_size] = 0
        sizes[item.payload_size] += 1

        if item.encapsulation_protocol not in encap:
            encap[item.encapsulation_protocol] = 0
        encap[item.encapsulation_protocol] += 1

        if item.network_protocol not in net:
            net[item.network_protocol] = 0
        net[item.network_protocol] += 1

        if item.ip_version not in af:
            af[item.ip_version] = 0
        af[item.ip_version] += 1
    # default ports
    assert res._lidar_port == 7502

    # roundrobin -> 5 of each
    assert ports == {7502: 5, 7503: 5}
    assert sizes == {6464: 5, 48: 5}
    assert encap == {ETH_PROTO: 10}
    assert net == {UDP_PROTO: 10}
    assert af == {4: 10}
Ejemplo n.º 22
0
def pcap_obj(metadata, pcap_path):
    pc = pcap.Pcap(pcap_path, metadata)
    yield pc
    pc.close()
Ejemplo n.º 23
0
def main() -> None:
    descr = """Visualize pcap or sensor data using simple viz bindings."""

    epilog = """When reading data from a sensor, this will currently not
    configure the sensor or query it for the port to listen on. You will need to
    set the sensor port and distination settings separately.
    """

    parser = argparse.ArgumentParser(description=descr, epilog=epilog)

    required = parser.add_argument_group('one of the following is required')
    group = required.add_mutually_exclusive_group(required=True)
    group.add_argument('--sensor', metavar='HOST', help='sensor hostname')
    group.add_argument('--pcap', metavar='PATH', help='path to pcap file')

    parser.add_argument('--meta', metavar='PATH', help='path to metadata json')
    parser.add_argument('--lidar-port', type=int, default=7502)

    args = parser.parse_args()

    if args.sensor:
        print("Initializing...")
        scans = client.Scans.stream(args.sensor,
                                    args.lidar_port,
                                    complete=False)
    elif args.pcap:
        import ouster.pcap as pcap

        if args.meta:
            metadata_path = args.meta
        else:
            print("Deducing metadata based on pcap name. "
                  "To provide a different metadata path, use --meta")
            metadata_path = os.path.splitext(args.pcap)[0] + ".json"

        with open(metadata_path) as json:
            info = client.SensorInfo(json.read())
        scans = client.Scans(
            pcap.Pcap(args.pcap, info, rate=1.0, lidar_port=args.lidar_port))

    viz = PyViz(scans.metadata)

    def run() -> None:
        try:
            for scan in scans:
                viz.draw(scan)
        finally:
            # signal main thread to exit
            viz.quit()

    try:
        print("Starting client thread...")
        client_thread = threading.Thread(target=run, name="Client")
        client_thread.start()

        print("Starting rendering loop...")
        viz.loop()
    finally:
        scans.close()
        client_thread.join()

    print("Done")
Ejemplo n.º 24
0
def main():
    """PointViz visualizer examples."""

    parser = argparse.ArgumentParser(
        description=main.__doc__,
        formatter_class=argparse.RawTextHelpFormatter)

    parser.add_argument('pcap_path',
                        nargs='?',
                        metavar='PCAP',
                        help='path to pcap file')
    parser.add_argument('meta_path',
                        nargs='?',
                        metavar='METADATA',
                        help='path to metadata json')

    args = parser.parse_args()

    pcap_path = os.getenv("SAMPLE_DATA_PCAP_PATH", args.pcap_path)
    meta_path = os.getenv("SAMPLE_DATA_JSON_PATH", args.meta_path)

    if not pcap_path or not meta_path:
        print("ERROR: Please add SAMPLE_DATA_PCAP_PATH and SAMPLE_DATA_JSON_PATH to" +
            " environment variables or pass <pcap_path> and <meta_path>")
        sys.exit()

    print(f"Using:\n\tjson: {meta_path}\n\tpcap: {pcap_path}")

    # Getting data sources
    meta = client.SensorInfo(open(meta_path).read())
    packets = pcap.Pcap(pcap_path, meta)
    scans = iter(client.Scans(packets))

    # ==============================
    print("Ex 0: Empty Point Viz")

    # [doc-stag-empty-pointviz]
    # Creating a point viz instance
    point_viz = viz.PointViz("Example Viz")
    viz.add_default_controls(point_viz)

    # ... add objects here

    # update internal objects buffers and run visualizer
    point_viz.update()
    point_viz.run()
    # [doc-etag-empty-pointviz]


    # =========================================================================
    print("Ex 1.0:\tImages and Labels: the Image object and 2D Image set_position() - height-normalized screen coordinates")

    label_top = viz.Label("[0, 1]", 0.5, 0.0, align_top=True)
    label_top.set_scale(2)
    point_viz.add(label_top)

    label_bot = viz.Label("[0, -1]", 0.5, 1, align_top=False)
    label_bot.set_scale(2)
    point_viz.add(label_bot)

    # [doc-stag-image-pos-center]
    img = viz.Image()
    img.set_image(np.full((10, 10), 0.5))
    img.set_position(-0.5, 0.5, -0.5, 0.5)
    point_viz.add(img)
    # [doc-etag-image-pos-center]

    # visualize
    point_viz.update()
    point_viz.run()

    # =========================================================================
    print("Ex 1.1:\tImages and Labels: Window-aligned images with 2D Image set_hshift() - width-normalized [-1, 1] horizontal shift")

    # [doc-stag-image-pos-left]
    # move img to the left
    img.set_position(0, 1, -0.5, 0.5)
    img.set_hshift(-1)
    # [doc-etag-image-pos-left]

    # visualize
    point_viz.update()
    point_viz.run()

    # [doc-stag-image-pos-right]
    # move img to the right
    img.set_position(-1, 0, -0.5, 0.5)
    img.set_hshift(1)
    # [doc-etag-image-pos-right]

    # visualize
    point_viz.update()
    point_viz.run()

    # [doc-stag-image-pos-right-bottom]
    # move img to the right bottom
    img.set_position(-1, 0, -1, 0)
    img.set_hshift(1)
    # [doc-etag-image-pos-right-bottom]

    # visualize
    point_viz.update()
    point_viz.run()


    # remove_objs(point_viz, [label_top, label_mid, label_bot, img])
    remove_objs(point_viz, [label_top, label_bot, img])

    # =======================================
    print("Ex 1.2:\tImages and Labels: Lidar Scan Fields as Images")

    # [doc-stag-scan-fields-images]
    scan = next(scans)

    img_aspect = (meta.beam_altitude_angles[0] -
                  meta.beam_altitude_angles[-1]) / 360.0
    img_screen_height = 0.4 # [0..2]
    img_screen_len = img_screen_height / img_aspect

    # prepare field data
    ranges = scan.field(client.ChanField.RANGE)
    ranges = client.destagger(meta, ranges)
    ranges = np.divide(ranges, np.amax(ranges), dtype=np.float32)

    signal = scan.field(client.ChanField.SIGNAL)
    signal = client.destagger(meta, signal)
    signal = np.divide(signal, np.amax(signal), dtype=np.float32)

    # creating Image viz elements
    range_img = viz.Image()
    range_img.set_image(ranges)
    # top center position
    range_img.set_position(-img_screen_len / 2, img_screen_len / 2,
                           1 - img_screen_height, 1)
    point_viz.add(range_img)

    signal_img = viz.Image()
    signal_img.set_image(signal)
    img_aspect = (meta.beam_altitude_angles[0] -
                meta.beam_altitude_angles[-1]) / 360.0
    img_screen_height = 0.4 # [0..2]
    img_screen_len = img_screen_height / img_aspect
    # bottom center position
    signal_img.set_position(-img_screen_len / 2, img_screen_len / 2, -1,
                            -1 + img_screen_height)
    point_viz.add(signal_img)
    # [doc-etag-scan-fields-images]

    # visualize
    point_viz.update()
    point_viz.run()

    print("Ex 1.3:\tImages and Labels: Adding labels")

    # [doc-stag-scan-fields-images-labels]
    range_label = viz.Label(str(client.ChanField.RANGE), 0.5, 0, align_top=True)
    range_label.set_scale(1)
    point_viz.add(range_label)

    signal_label = viz.Label(str(client.ChanField.SIGNAL),
                            0.5, 1 - img_screen_height / 2,
                            align_top=True)
    signal_label.set_scale(1)
    point_viz.add(signal_label)
    # [doc-etag-scan-fields-images-labels]

    # visualize
    point_viz.update()
    point_viz.run()

    # ===============================================================
    print("Ex 2.0:\tPoint Clouds: As Structured Points")

    # [doc-stag-scan-structured]
    cloud_scan = viz.Cloud(meta)
    cloud_scan.set_range(scan.field(client.ChanField.RANGE))
    cloud_scan.set_key(signal)
    point_viz.add(cloud_scan)
    # [doc-etag-scan-structured]

    # visualize
    point_viz.update()
    point_viz.run()

    remove_objs(point_viz, [cloud_scan])

    # ===============================================================
    print("Ex 2.1:\tPoint Clouds: As Unstructured Points")

    # [doc-stag-scan-unstructured]
    # transform scan data to 3d points
    xyzlut = client.XYZLut(meta)
    xyz = xyzlut(scan.field(client.ChanField.RANGE))

    cloud_xyz = viz.Cloud(xyz.shape[0] * xyz.shape[1])
    cloud_xyz.set_xyz(np.reshape(xyz, (-1, 3)))
    cloud_xyz.set_key(signal.ravel())
    point_viz.add(cloud_xyz)
    # [doc-etag-scan-unstructured]

    point_viz.camera.dolly(150)

    # visualize
    point_viz.update()
    point_viz.run()

    # =======================================================
    print("Ex 2.2:\tPoint Clouds: Custom Axes Helper as Unstructured Points")

    # [doc-stag-axes-helper]
    # basis vectors
    x_ = np.array([1, 0, 0]).reshape((-1, 1))
    y_ = np.array([0, 1, 0]).reshape((-1, 1))
    z_ = np.array([0, 0, 1]).reshape((-1, 1))

    axis_n = 100
    line = np.linspace(0, 1, axis_n).reshape((1, -1))

    # basis vector to point cloud
    axis_points = np.hstack((x_ @ line, y_ @ line, z_ @ line)).transpose()

    # colors for basis vectors
    axis_color_mask = np.vstack((
        np.full((axis_n, 4), [1, 0.1, 0.1, 1]),
        np.full((axis_n, 4), [0.1, 1, 0.1, 1]),
        np.full((axis_n, 4), [0.1, 0.1, 1, 1])))

    cloud_axis = viz.Cloud(axis_points.shape[0])
    cloud_axis.set_xyz(axis_points)
    cloud_axis.set_key(np.full(axis_points.shape[0], 0.5))
    cloud_axis.set_mask(axis_color_mask)
    cloud_axis.set_point_size(3)
    point_viz.add(cloud_axis)
    # [doc-etag-axes-helper]

    point_viz.camera.dolly(50)

    # visualize
    point_viz.update()
    point_viz.run()

    remove_objs(point_viz, [
        range_img, range_label, signal_img, signal_label, cloud_axis, cloud_xyz
    ])

    # ===============================================================
    print("Ex 2.3:\tPoint Clouds: the LidarScanViz class")

    # [doc-stag-lidar-scan-viz]
    # Creating LidarScan visualizer (3D point cloud + field images on top)
    ls_viz = viz.LidarScanViz(meta, point_viz)

    # adding scan to the lidar scan viz
    ls_viz.scan = scan

    # refresh viz data
    ls_viz.draw()

    # visualize
    # update() is not needed for LidatScanViz because it's doing it internally
    point_viz.run()
    # [doc-etag-lidar-scan-viz]

    # ===================================================
    print("Ex 3.0:\tAugmenting point clouds with 3D Labels")

    # [doc-stag-lidar-scan-viz-labels]
    # Adding 3D Labels
    label1 = viz.Label("Label1: [1, 2, 4]", 1, 2, 4)
    point_viz.add(label1)

    label2 = viz.Label("Label2: [2, 1, 4]", 2, 1, 4)
    label2.set_scale(2)
    point_viz.add(label2)

    label3 = viz.Label("Label3: [4, 2, 1]", 4, 2, 1)
    label3.set_scale(3)
    point_viz.add(label3)
    # [doc-etag-lidar-scan-viz-labels]

    point_viz.camera.dolly(-100)

    # visualize
    point_viz.update()
    point_viz.run()


    # ===============================================
    print("Ex 4.0:\tOverlay 2D Images and 2D Labels")

    # [doc-stag-overlay-images-labels]
    # Adding image 1 with aspect ratio preserved
    img = viz.Image()
    img_data = make_checker_board(10, (2, 4))
    mask_data = np.zeros((30, 30, 4))
    mask_data[:15, :15] = np.array([1, 0, 0, 1])
    img.set_mask(mask_data)
    img.set_image(img_data)
    ypos = (0, 0.5)
    xlen = (ypos[1] - ypos[0]) * img_data.shape[1] / img_data.shape[0]
    xpos = (0, xlen)
    img.set_position(*xpos, *ypos)
    img.set_hshift(-0.5)
    point_viz.add(img)

    # Adding Label for image 1: positioned at bottom left corner
    img_label = viz.Label("ARRrrr!", 0.25, 0.5)
    img_label.set_rgba((1.0, 1.0, 0.0, 1))
    img_label.set_scale(2)
    point_viz.add(img_label)

    # Adding image 2: positioned to the right of the window
    img2 = viz.Image()
    img_data2 = make_checker_board(10, (4, 2))
    mask_data2 = np.zeros((30, 30, 4))
    mask_data2[15:25, 15:25] = np.array([0, 1, 0, 0.5])
    img2.set_mask(mask_data2)
    img2.set_image(img_data2)
    ypos2 = (0, 0.5)
    xlen2 = (ypos2[1] - ypos2[0]) * img_data2.shape[1] / img_data2.shape[0]
    xpos2 = (-xlen2, 0)
    img2.set_position(*xpos2, *ypos2)
    img2.set_hshift(1.0)
    point_viz.add(img2)

    # Adding Label for image 2: positioned at top left corner
    img_label2 = viz.Label("Second", 1.0, 0.25, align_top=True, align_right=True)
    img_label2.set_rgba((0.0, 1.0, 1.0, 1))
    img_label2.set_scale(1)
    point_viz.add(img_label2)
    # [doc-etag-overlay-images-labels]

    # visualize
    point_viz.update()
    point_viz.run()


    # ===============================================================
    print("Ex 5.0:\tAdding key handlers: 'R' for random camera dolly")

    # [doc-stag-key-handlers]
    def handle_dolly_random(ctx, key, mods) -> bool:
        if key == 82:  # key R
            dolly_num = random.randrange(-15, 15)
            print(f"Random Dolly: {dolly_num}")
            point_viz.camera.dolly(dolly_num)
            point_viz.update()
        return True

    point_viz.push_key_handler(handle_dolly_random)
    # [doc-etag-key-handlers]

    # visualize
    point_viz.update()
    point_viz.run()
Ejemplo n.º 25
0
def pcap_to_csv(pcap_path: str,
                metadata_path: str,
                num: int = 0,
                csv_dir: str = ".",
                csv_prefix: str = "pcap_out",
                csv_ext: str = "csv") -> None:
    """Write scans from pcap file (*pcap_path*) to plain csv files (one per
    lidar scan).

    If the *csv_ext* ends in ``.gz``, the file is automatically saved in
    compressed gzip format. :func:`.numpy.loadtxt` can be used to read gzipped
    files transparently back to :class:`.numpy.ndarray`.

    Number of saved lines per csv file is always [H x W], which corresponds
    to a full 2D image representation of a lidar scan.

    Each line in a csv file is:

        RANGE (mm), SIGNAL, NEAR_IR, REFLECTIVITY, X (m), Y (m), Z (m)

    Args:
        pcap_path: path to the pcap file
        metadata_path: path to the .json with metadata (aka :class:`.SensorInfo`)
        num: number of scans to save from pcap to csv files
        csv_dir: path to the directory where csv files will be saved
        csv_prefix: the filename prefix that will be appended with frame number
                    and *csv_ext*
        csv_ext: file extension to use. If it ends with ``.gz`` the output is
                 gzip compressed

    """
    from itertools import islice

    # ensure that base csv_dir exists
    if not os.path.exists(csv_dir):
        os.makedirs(csv_dir)

    metadata = read_metadata(metadata_path)
    source = pcap.Pcap(pcap_path, metadata)

    # [doc-stag-pcap-to-csv]
    field_names = 'RANGE (mm), SIGNAL, NEAR_IR, REFLECTIVITY, X (m), Y (m), Z (m)'
    field_fmts = ['%d', '%d', '%d', '%d', '%.8f', '%.8f', '%.8f']

    channels = [
        client.ChanField.RANGE, client.ChanField.SIGNAL,
        client.ChanField.NEAR_IR, client.ChanField.REFLECTIVITY
    ]

    with closing(pcap.Pcap(pcap_path, metadata)) as source:

        # precompute xyzlut to save computation in a loop
        xyzlut = client.XYZLut(metadata)

        # create an iterator of LidarScans from pcap and bound it if num is specified
        scans = iter(client.Scans(source))
        if num:
            scans = islice(scans, num)

        for idx, scan in enumerate(scans):

            fields_values = [scan.field(ch) for ch in channels]
            xyz = xyzlut(scan)

            # get lidar data as one frame of [H x W x 7], "fat" 2D image
            frame = np.dstack((*fields_values, xyz))
            frame = client.destagger(metadata, frame)

            csv_path = os.path.join(csv_dir,
                                    f'{csv_prefix}_{idx:06d}.{csv_ext}')

            header = '\n'.join([
                f'pcap file: {pcap_path}', f'frame num: {idx}',
                f'metadata file: {metadata_path}', field_names
            ])

            print(f'write frame #{idx}, to file: {csv_path}')

            np.savetxt(csv_path,
                       np.reshape(frame, (-1, frame.shape[2])),
                       fmt=field_fmts,
                       delimiter=',',
                       header=header)
Ejemplo n.º 26
0
def packets(real_pcap_path: str,
            meta: client.SensorInfo) -> client.PacketSource:
    with closing(pcap.Pcap(real_pcap_path, meta)) as real_pcap:
        ps = list(real_pcap)
        return client.Packets(ps, meta)
Ejemplo n.º 27
0
def pcap_2d_viewer(
        pcap_path: str,
        metadata_path: str,
        num: int = 0,  # not used in this example
        rate: float = 0.0) -> None:
    """Simple sensor field visualization pipeline as 2D images from pcap file
    (*pcap_path*)

    Args:
        pcap_path: path to the pcap file
        metadata_path: path to the .json with metadata (aka :class:`.SensorInfo`)
        rate: read speed of packets from the pcap file (**1.0** - corresponds to
              real-time by packets timestamp, **0.0** - as fast as it reads from
              file without any delay)

    """
    import cv2  # type: ignore

    # [doc-stag-pcap-display-live]
    metadata = read_metadata(metadata_path)

    source = pcap.Pcap(pcap_path, metadata, rate=rate)

    with closing(source) as source:
        scans = iter(client.Scans(source))

        print("press ESC from visualization to exit")

        channels = [
            client.ChanField.RANGE, client.ChanField.SIGNAL,
            client.ChanField.NEAR_IR, client.ChanField.REFLECTIVITY
        ]

        paused = False
        destagger = True
        num = 0
        scan = next(scans, None)
        while scan:
            print("frame id: {}, num = {}".format(scan.frame_id, num))

            fields_values = [scan.field(ch) for ch in channels]

            if destagger:
                fields_values = [
                    client.destagger(metadata, field_val)
                    for field_val in fields_values
                ]

            fields_images = [ae(field_val) for field_val in fields_values]

            combined_images = np.vstack(
                [np.pad(img, 2, constant_values=1.0) for img in fields_images])

            cv2.imshow("4 channels: ", combined_images)

            key = cv2.waitKey(1) & 0xFF
            # 100 is d
            if key == 100:
                destagger = not destagger
            # 32 is SPACE
            if key == 32:
                paused = not paused
            # 27 is ESC
            elif key == 27:
                break

            if not paused:
                scan = next(scans, None)
                num += 1

        cv2.destroyAllWindows()
Ejemplo n.º 28
0
- separate set scan / update is annoying
- a proxy run()/quit() on ls_viz would be useful
- maybe: ls_viz could initialize underlying viz + expose it
- point_viz.run() twice is broken
- ideally, run() would open/close window
- auto camera movement example?
"""

from ouster import client, pcap
from ouster.sdk import viz

meta_path = "/mnt/aux/test_drives/OS1_128_2048x10.json"
pcap_path = "/mnt/aux/test_drives/OS1_128_2048x10.pcap"

meta = client.SensorInfo(open(meta_path).read())
packets = pcap.Pcap(pcap_path, meta)
scans = iter(client.Scans(packets))

point_viz = viz.PointViz("Example Viz")
ls_viz = viz.LidarScanViz(meta, point_viz)

ls_viz.scan = next(scans)
ls_viz.draw()
print("Showing first frame, close visuzlier window to continue")
point_viz.run()

ls_viz.scan = next(scans)
ls_viz.draw()
print("Showing second frame, close visuzlier window to continue")
point_viz.run()
Ejemplo n.º 29
0
def main():
    """Pcap examples runner."""
    examples = {
        "open3d-one-scan": pcap_3d_one_scan,
        "plot-xyz-points": pcap_display_xyz_points,
        "pcap-to-csv": pcap_to_csv,
        "pcap-to-las": pcap_to_las,
        "pcap-to-pcd": pcap_to_pcd,
        "pcap-to-ply": pcap_to_ply,
        "query-scan": pcap_query_scan,
        "read-packets": pcap_read_packets,
    }

    description = "Ouster Python SDK Pcap examples. The EXAMPLE must be one of:\n  " + str.join(
        '\n  ', examples.keys())

    parser = argparse.ArgumentParser(
        description=description, formatter_class=argparse.RawTextHelpFormatter)

    parser.add_argument('pcap_path', metavar='PCAP', help='path to pcap file')
    parser.add_argument('metadata_path',
                        metavar='METADATA',
                        help='path to metadata json')
    parser.add_argument('example',
                        metavar='EXAMPLE',
                        choices=examples.keys(),
                        help='name of the example to run')
    parser.add_argument('--scan-num',
                        type=int,
                        default=1,
                        help='index of scan to use')
    args = parser.parse_args()

    try:
        example = examples[args.example]
    except KeyError:
        print(f"No such example: {args.example}")
        print(description)
        exit(1)

    if not args.metadata_path or not os.path.exists(args.metadata_path):
        print(f"Metadata file does not exist: {args.metadata_path}")
        exit(1)

    with open(args.metadata_path, 'r') as f:
        metadata = client.SensorInfo(f.read())

    if (metadata.format.udp_profile_lidar !=
            client.UDPProfileLidar.PROFILE_LIDAR_LEGACY
            and metadata.format.udp_profile_lidar !=
            client.UDPProfileLidar.PROFILE_LIDAR_RNG19_RFL8_SIG16_NIR16
            and args.example != 'query-scan'):
        print(
            f"This pcap example is only for pcaps of sensors in LEGACY or SINGLE RETURN mode. Exiting..."
        )
        exit(1)

    print(f'example: {args.example}')

    source = pcap.Pcap(args.pcap_path, metadata)

    with closing(source):
        example(source, metadata, args.scan_num)  # type: ignore
Ejemplo n.º 30
0
def real_pcap(real_pcap_path: str,
              meta: client.SensorInfo) -> Iterator[pcap.Pcap]:
    pcap_obj = pcap.Pcap(real_pcap_path, meta)
    yield pcap_obj
    pcap_obj.close()