--- name: matlab-read-write-point-cloud-file description: "Read and write 3-D point cloud data using Lidar Toolbox file I/O. Covers PLY, PCD, LAS/LAZ, PCAP (Velodyne/Ouster/Hesai), E57, and IDC (Ibeo) formats. Use when loading point clouds from disk, saving to disk, choosing the correct reader or writer for a file format, extracting or preserving lidar point attributes, reading Ibeo IDC sensor recordings, or converting between formats." license: https://www.mathworks.com/content/dam/mathworks/license/pmrl/license.md metadata: author: MathWorks version: "2.0" --- # Point Cloud File I/O Read and write 3-D point cloud data in MATLAB using Lidar Toolbox file I/O functions, covering PLY, PCD, LAS/LAZ, sensor PCAP, E57, and IDC (Ibeo) formats. ## When to Use - Loading a point cloud file from disk into a `pointCloud` object - Saving a `pointCloud` object to disk in any supported format - Deciding which reader or writer function to use for a given file format - Reading LAS/LAZ files with selective filtering (ROI, classification, GPS time) - Extracting or preserving lidar point attributes (classification, GPS timestamps, scan angle) - Reading Velodyne, Ouster, or Hesai PCAP sensor recordings frame-by-frame - Reading multi-scan E57 files with indexed access - Reading Ibeo IDC sensor recordings with message-based access - Converting between point cloud formats (e.g., LAS to PLY, PCD to LAZ) ## When NOT to Use - Streaming live sensor data in real time (use `velodynelidar`, `ousterlidar`, `sicklidar`) - Processing or filtering point clouds after reading (use `pcdownsample`, `pcdenoise`) - Reading or writing surface meshes (use `readSurfaceMesh`, `writeSurfaceMesh`) - Saving point cloud variables to MAT-files (use `save`) - Visualizing point clouds (use `pcshow`, `pcplayer`, `pcviewer`) ## Must-Follow Rules 1. **Route by file extension, not by habit** — `pcread` ONLY supports `.ply` and `.pcd` files. For `.las`/`.laz` use `lasFileReader` + `readPointCloud`. For `.pcap` use the sensor-specific file reader (`velodyneFileReader`, `ousterFileReader`, or `hesaiFileReader`). For `.e57` use `e57FileReader`. Calling `pcread` on a LAS or PCAP file produces an error, not a warning. Similarly, `pcwrite` ONLY writes PLY and PCD — for LAS/LAZ output use `lasFileWriter` + `writePointCloud`. 2. **PCAP file readers require a mandatory device identifier — never guess it** — `velodyneFileReader` requires a `DeviceModel` string (e.g., `"HDL32E"`). `hesaiFileReader` requires a `DeviceModel` string (e.g., `"PandarXT32"`). `ousterFileReader` requires a `CalibrationFile` path (JSON). If the user has not specified the device model or calibration file, ASK — do not assume a default. There is no default value; omitting it causes an error. 3. **Use two-output syntax to get point attributes from LAS/LAZ** — `[ptCloud, ptAttributes] = readPointCloud(reader)` returns a `lidarPointAttributes` object containing Classification, GPSTimeStamp, LaserReturn, NumReturns, ScanAngle, and more. The single-output form discards these attributes permanently. Intensity is on the `pointCloud` object (`.Intensity` property), NOT on `lidarPointAttributes`. 4. **Preserve attributes with three-argument writePointCloud** — `writePointCloud(writer, ptCloud, ptAttributes)` preserves Classification, GPSTimeStamp, and other lidar attributes in LAS/LAZ output. The two-argument form `writePointCloud(writer, ptCloud)` discards all attributes. If the user has attributes from `lasFileReader`/`readPointCloud`, always pass them through. 5. **PLY only supports ascii and binary encoding** — Calling `pcwrite(ptCloud, "file.ply", Encoding="compressed")` throws an error. Only `"ascii"` and `"binary"` are valid for PLY. The `"compressed"` encoding is exclusive to PCD format. Defaults (R2026a+): PLY=`"binary"`, PCD=`"compressed"`. 6. **Always use string syntax** — Use double-quoted strings (`"text"`) for all literal text arguments (filenames, device models, encoding values, Name=Value values). Use `Name=Value` syntax for all name-value pairs. Never use character vectors (`'text'`) or legacy `'Name','Value'` pair syntax. ### Preflight Procedure 1. List MATLAB functions to call 2. Check `references/INDEX.md` for each (function-level + task-level tables) 3. Read required quick-ref files 4. State at response top: `Preflight: quick-ref/xxx.md, quick-ref/yyy.md` (or `Preflight: none required`) ## Key Functions | Function | Purpose | Format | Key Constraint | |---|---|---|---| | `pcread` | Read point cloud from file | PLY, PCD | Single call, returns `pointCloud` | | `pcwrite` | Write point cloud to file | PLY, PCD | Encoding varies by format | | `lasFileReader` | Create LAS/LAZ reader object | LAS, LAZ | Two-step: create reader, then `readPointCloud` | | `lasFileWriter` | Create LAS/LAZ writer object | LAS, LAZ | Two-step: create writer, then `writePointCloud` | | `velodyneFileReader` | Create Velodyne PCAP reader | PCAP | Mandatory `DeviceModel` (2nd arg) | | `ousterFileReader` | Create Ouster PCAP reader | PCAP | Mandatory `CalibrationFile` (2nd arg) | | `hesaiFileReader` | Create Hesai PCAP reader | PCAP | Mandatory `DeviceModel` (2nd arg) | | `e57FileReader` | Create E57 reader object | E57 | Use `readPointCloud(reader, idx)` for multi-scan | | `ibeoLidarReader` | Create Ibeo IDC reader object | IDC | Use `readMessages` to read scan data | ## Decision Framework ``` READING — What is the file extension? ├── .ply / .pcd → pcread(filename) ├── .las / .laz → lasFileReader(filename) + readPointCloud(reader) ├── .pcap (Velodyne) → velodyneFileReader(filename, deviceModel) ├── .pcap (Ouster) → ousterFileReader(filename, calibrationFile) ├── .pcap (Hesai) → hesaiFileReader(filename, deviceModel) ├── .e57 → e57FileReader(filename) + readPointCloud(reader, idx) └── .idc (Ibeo) → ibeoLidarReader(filename) + readMessages(reader) WRITING — What output format does the user need? ├── .ply → pcwrite(ptCloud, "file.ply") │ Encoding: "ascii" or "binary" (default: binary) ├── .pcd → pcwrite(ptCloud, "file.pcd") │ Encoding: "ascii", "binary", or "compressed" (default: compressed) ├── .las → lasFileWriter("file.las") + writePointCloud(writer, ptCloud) └── .laz → lasFileWriter("file.laz") + writePointCloud(writer, ptCloud) Optional: pass ptAttributes as 3rd arg to preserve attributes ``` **PCAP sensor identification:** If the user says "Velodyne", "Ouster", or "Hesai" — use the matching reader. If they just say "PCAP file" without specifying the sensor, ASK which sensor produced it. **Ibeo IDC files:** If the user has an `.idc` file, use `ibeoLidarReader`. Unlike other readers, it uses `readMessages` (not `readPointCloud` or `readFrame`) and returns message-based scan data. **Velodyne device models:** VLP16, PuckLITE, PuckHiRes, VLP32C, HDL32E, HDL64E, VLS128, VelarrayH800 **Hesai device models:** Pandar128E3X, Pandar64, PandarQT, PandarXT32 ## Gotchas ### `pcread` called on LAS/LAZ file `pcread` only supports PLY and PCD formats. Attempting to use it on LAS, LAZ, PCAP, or E57 files throws an error. ```matlab % WRONG: pcread does not support LAS ptCloud = pcread("survey.las"); % CORRECT: Use lasFileReader for LAS/LAZ reader = lasFileReader("survey.las"); ptCloud = readPointCloud(reader); ``` ### Compressed encoding on PLY file The `"compressed"` encoding is only valid for PCD format. PLY supports only `"ascii"` and `"binary"`. ```matlab % WRONG: compressed not supported for PLY pcwrite(ptCloud, "output.ply", Encoding="compressed"); % CORRECT: use binary for compact PLY pcwrite(ptCloud, "output.ply", Encoding="binary"); % CORRECT: compressed is valid for PCD pcwrite(ptCloud, "output.pcd", Encoding="compressed"); ``` ### Using pcwrite for LAS/LAZ output `pcwrite` does not support LAS or LAZ format. It only handles PLY and PCD. ```matlab % WRONG: pcwrite cannot write LAS pcwrite(ptCloud, "output.las"); % CORRECT: use lasFileWriter for LAS/LAZ writer = lasFileWriter("output.las"); writePointCloud(writer, ptCloud); ``` ### Losing attributes with two-argument writePointCloud When writing LAS/LAZ, the two-argument form discards lidar point attributes. Always pass the attributes object if available. ```matlab % WRONG: attributes are discarded reader = lasFileReader("input.laz"); [ptCloud, ptAttr] = readPointCloud(reader); writer = lasFileWriter("output.laz"); writePointCloud(writer, ptCloud); % ptAttr lost! % CORRECT: preserve attributes with 3-argument form reader = lasFileReader("input.laz"); [ptCloud, ptAttr] = readPointCloud(reader); writer = lasFileWriter("output.laz"); writePointCloud(writer, ptCloud, ptAttr); ``` ### Accessing classification from the wrong object Classification, GPSTimeStamp, LaserReturn, and other lidar-specific attributes are on `lidarPointAttributes`, not on `pointCloud`. The `pointCloud` object holds Intensity (and Location, Color, Normal). ```matlab % WRONG: pointCloud does not have Classification reader = lasFileReader("data.laz"); ptCloud = readPointCloud(reader); labels = ptCloud.Classification; % Error % CORRECT: Use two-output syntax reader = lasFileReader("data.laz"); [ptCloud, ptAttributes] = readPointCloud(reader); labels = ptAttributes.Classification; intensity = ptCloud.Intensity; % Intensity is on pointCloud ``` ### Reading all PCAP frames without a loop PCAP readers are frame-based iterators. There is no single function to load all frames at once. ```matlab % WRONG: No readAll or similar function reader = velodyneFileReader("lidarData_ConstructionRoad.pcap", "HDL32E"); allPoints = readPointCloud(reader); % readPointCloud is not a method % CORRECT: Loop with hasFrame/readFrame reader = velodyneFileReader("lidarData_ConstructionRoad.pcap", "HDL32E"); while hasFrame(reader) ptCloud = readFrame(reader); end ``` ## Patterns ### Read a PLY or PCD file ```matlab ptCloud = pcread("scene.ply"); fprintf("Points: %d\n", ptCloud.Count); fprintf("X range: [%.2f, %.2f]\n", ptCloud.XLimits); ``` ### Read LAS file with classification filtering ```matlab reader = lasFileReader("aerial.laz"); [ptCloud, ptAttributes] = readPointCloud(reader, Classification=[2 6]); labels = ptAttributes.Classification; fprintf("Ground + building points: %d\n", ptCloud.Count); ``` ### Read Velodyne PCAP frames ```matlab reader = velodyneFileReader("lidarData_ConstructionRoad.pcap", "HDL32E"); fprintf("Total frames: %d\n", reader.NumberOfFrames); while hasFrame(reader) ptCloud = readFrame(reader); end ``` ### Read E57 file with multiple scans ```matlab reader = e57FileReader("building.e57"); fprintf("Scans in file: %d\n", reader.NumPointClouds); for idx = 1:reader.NumPointClouds ptCloud = readPointCloud(reader, idx); fprintf("Scan %d: %d points\n", idx, ptCloud.Count); end ``` ### Write point cloud to PLY (binary) ```matlab ptCloud = pointCloud(rand(1000,3), Color=uint8(rand(1000,3)*255)); pcwrite(ptCloud, fullfile(tempdir, "output.ply"), Encoding="binary"); ``` ### Write point cloud to PCD (compressed) ```matlab ptCloud = pcread(fullfile(toolboxdir("lidar"), "lidardata", "highwayScene.pcd")); pcwrite(ptCloud, fullfile(tempdir, "scene_compressed.pcd"), Encoding="compressed"); ``` ### Read LAS and write to LAZ preserving attributes ```matlab reader = lasFileReader("input.las"); [ptCloud, ptAttr] = readPointCloud(reader); writer = lasFileWriter(fullfile(tempdir, "output.laz")); writePointCloud(writer, ptCloud, ptAttr); ``` ### Convert PCD to PLY ```matlab ptCloud = pcread("scene.pcd"); pcwrite(ptCloud, fullfile(tempdir, "scene.ply"), Encoding="binary"); ``` ### Convert LAS to PCD ```matlab reader = lasFileReader("survey.las"); ptCloud = readPointCloud(reader); pcwrite(ptCloud, fullfile(tempdir, "survey.pcd"), Encoding="compressed"); ``` ### Read Ibeo IDC file ```matlab reader = ibeoLidarReader("sensor_data.idc"); fprintf("Message types: %s\n", strjoin(reader.MessageTypes, ", ")); fprintf("Total messages: %d\n", reader.NumMessages); % Read all messages — returns array of pointCloud objects ptClouds = readMessages(reader); % Two-output form: get message metadata (timestamps, labels, plane info) [ptClouds, messageData] = readMessages(reader); % Filter by message type: "Scan" or "PointCloudPlane" ptClouds = readMessages(reader, Messages="Scan"); % Filter by time range tStart = reader.FileInfo.TimeStamps{1}(1); tEnd = tStart + seconds(10); ptClouds = readMessages(reader, Time=[tStart tEnd]); ``` **ibeoLidarReader key details:** - Supports IDC files from Ibeo FUSION SYSTEM/ECU sensors - Two message types: `"Scan"` (data type 0x2205) and `"PointCloudPlane"` (data type 0x7510) - `readMessages` returns an array of `pointCloud` objects (one per message) - Second output `messageData` is a cell array of structs with `MessageType`, `TimeStamp`, and (for PointCloudPlane) `Label`, `ReferencePoint`, `PlaneOrientation` - `FileInfo` property is a table with columns: MessageType, DataType, Description, NumMessages, TimeStamps - All properties are read-only ## Conventions - Use `tempdir` for output paths in examples and tests to avoid permission issues - Default to `Encoding="binary"` for PLY and omit encoding for PCD (default compressed is best) - Always use double-quoted strings (`"text"`) and `Name=Value` syntax — never character vectors or `'Name','Value'` pairs - Include file extension explicitly in filename — format is determined from extension - PLY flattens organized M-by-N-by-3 to unorganized M-by-3; use PCD to preserve organized structure - NaN/Inf values are skipped when writing to PLY - `lasFileWriter` only supports unorganized `pointCloud` objects ## References | Load when... | Reference | |---|---| | Reading or writing LAS/LAZ files, need filtering NV-pairs, attribute details, or writer properties | [references/quick-ref/las-io.md](references/quick-ref/las-io.md) | | Reading PCAP files from Velodyne, Ouster, or Hesai sensors | [references/quick-ref/pcap-readers.md](references/quick-ref/pcap-readers.md) | ---- Copyright 2026 The MathWorks, Inc. ----