Task 521: .PCD File Format

Task 521: .PCD File Format

First, the file format specifications for the .PCL file format: The .PCL file format refers to the Point Cloud Data (PCD) format used in the Point Cloud Library (PCL), where the extension .pcl is sometimes used interchangeably with .pcd for storing 3D point cloud data. It consists of an ASCII header followed by the point data in ASCII, binary, or binary_compressed format. The header defines the structure and metadata of the point cloud.

  1. List of all the properties of this file format intrinsic to its file system:
  • VERSION: Specifies the PCD file version (e.g., 0.7).
  • FIELDS: Specifies the name of each dimension/field for a point (space-separated, e.g., x y z rgb).
  • SIZE: Specifies the size in bytes of each dimension (space-separated, corresponding to FIELDS, e.g., 4 4 4 4).
  • TYPE: Specifies the type of each dimension (space-separated, corresponding to FIELDS; I for signed integer, U for unsigned integer, F for floating point, e.g., F F F F).
  • COUNT: Specifies the number of elements per dimension (space-separated, corresponding to FIELDS; default 1 if omitted, e.g., 1 1 1 1).
  • WIDTH: Specifies the width of the point cloud in points (for organized datasets: points per row; for unorganized: total points).
  • HEIGHT: Specifies the height of the point cloud in points (for organized datasets: number of rows; for unorganized: 1).
  • VIEWPOINT: Specifies the acquisition viewpoint as translation (tx ty tz) + quaternion (qw qx qy qz), space-separated (default: 0 0 0 1 0 0 0).
  • POINTS: Specifies the total number of points in the cloud.
  • DATA: Specifies the data storage type (ascii, binary, or binary_compressed).
  1. Two direct download links for files of format .PCL:
  1. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .PCL and it will dump to screen all these properties:
PCL File Parser
Drag and drop .PCL file here
  1. Python class that can open any file of format .PCL and decode read and write and print to console all the properties from the above list:
import os

class PCLParser:
    def __init__(self, filepath=None):
        self.properties = {}
        self.data = None
        self.filepath = filepath
        if filepath:
            self.read(filepath)

    def read(self, filepath):
        with open(filepath, 'r') as f:
            content = f.read()
        lines = content.split('\n')
        header_end = False
        header_lines = []
        for line in lines:
            if line.startswith('DATA'):
                header_lines.append(line)
                header_end = True
                break
            if line and not line.startswith('#'):
                header_lines.append(line)
        for line in header_lines:
            parts = line.split()
            key = parts[0]
            value = ' '.join(parts[1:])
            self.properties[key] = value
        # For simplicity, store remaining data (but don't parse points here)
        self.data = '\n'.join(lines[len(header_lines):])

    def print_properties(self):
        for key, value in self.properties.items():
            print(f"{key}: {value}")

    def write(self, output_filepath, new_properties=None, new_data=None):
        if new_properties:
            self.properties.update(new_properties)
        data_to_write = new_data if new_data else self.data
        with open(output_filepath, 'w') as f:
            for key in ['VERSION', 'FIELDS', 'SIZE', 'TYPE', 'COUNT', 'WIDTH', 'HEIGHT', 'VIEWPOINT', 'POINTS', 'DATA']:
                if key in self.properties:
                    f.write(f"{key} {self.properties[key]}\n")
            f.write(data_to_write)

# Example usage:
# parser = PCLParser('example.pcl')
# parser.print_properties()
# parser.write('new.pcl')
  1. Java class that can open any file of format .PCL and decode read and write and print to console all the properties from the above list:
import java.io.*;
import java.util.*;

public class PCLParser {
    private Map<String, String> properties = new HashMap<>();
    private String data = "";

    public PCLParser(String filepath) throws IOException {
        read(filepath);
    }

    public void read(String filepath) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String line;
            StringBuilder header = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("DATA")) {
                    header.append(line).append("\n");
                    break;
                }
                if (!line.startsWith("#") && !line.isEmpty()) {
                    header.append(line).append("\n");
                    String[] parts = line.split(" ", 2);
                    properties.put(parts[0], parts[1]);
                }
            }
            StringBuilder dataBuilder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                dataBuilder.append(line).append("\n");
            }
            data = dataBuilder.toString();
        }
    }

    public void printProperties() {
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public void write(String outputFilepath, Map<String, String> newProperties) throws IOException {
        if (newProperties != null) {
            properties.putAll(newProperties);
        }
        try (PrintWriter writer = new PrintWriter(new File(outputFilepath))) {
            String[] keys = {"VERSION", "FIELDS", "SIZE", "TYPE", "COUNT", "WIDTH", "HEIGHT", "VIEWPOINT", "POINTS", "DATA"};
            for (String key : keys) {
                if (properties.containsKey(key)) {
                    writer.println(key + " " + properties.get(key));
                }
            }
            writer.print(data);
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     PCLParser parser = new PCLParser("example.pcl");
    //     parser.printProperties();
    //     parser.write("new.pcl", null);
    // }
}
  1. Javascript class that can open any file of format .PCL and decode read and write and print to console all the properties from the above list:
const fs = require('fs'); // For Node.js environment

class PCLParser {
    constructor(filepath = null) {
        this.properties = {};
        this.data = '';
        if (filepath) {
            this.read(filepath);
        }
    }

    read(filepath) {
        const content = fs.readFileSync(filepath, 'utf8');
        const lines = content.split('\n');
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i].trim();
            if (line.startsWith('DATA')) {
                const parts = line.split(' ');
                this.properties.DATA = parts[1];
                this.data = lines.slice(i + 1).join('\n');
                break;
            }
            if (line && !line.startsWith('#')) {
                const parts = line.split(' ');
                const key = parts[0];
                const value = parts.slice(1).join(' ');
                this.properties[key] = value;
            }
        }
    }

    printProperties() {
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${value}`);
        }
    }

    write(outputFilepath, newProperties = null) {
        if (newProperties) {
            Object.assign(this.properties, newProperties);
        }
        let header = '';
        const keys = ['VERSION', 'FIELDS', 'SIZE', 'TYPE', 'COUNT', 'WIDTH', 'HEIGHT', 'VIEWPOINT', 'POINTS', 'DATA'];
        for (const key of keys) {
            if (this.properties[key]) {
                header += `${key} ${this.properties[key]}\n`;
            }
        }
        fs.writeFileSync(outputFilepath, header + this.data);
    }
}

// Example usage:
// const parser = new PCLParser('example.pcl');
// parser.printProperties();
// parser.write('new.pcl');
  1. C class that can open any file of format .PCL and decode read and write and print to console all the properties from the above list:
    (Note: Using C++ for class support, as pure C does not have native classes.)
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <string>
#include <vector>

class PCLParser {
private:
    std::map<std::string, std::string> properties;
    std::string data;

public:
    PCLParser(const std::string& filepath = "") {
        if (!filepath.empty()) {
            read(filepath);
        }
    }

    void read(const std::string& filepath) {
        std::ifstream file(filepath);
        if (!file.is_open()) {
            std::cerr << "Error opening file" << std::endl;
            return;
        }
        std::string line;
        std::vector<std::string> header_lines;
        while (std::getline(file, line)) {
            if (line.find("DATA") == 0) {
                header_lines.push_back(line);
                break;
            }
            if (!line.empty() && line[0] != '#') {
                header_lines.push_back(line);
            }
        }
        for (const auto& hline : header_lines) {
            std::istringstream iss(hline);
            std::string key;
            iss >> key;
            std::string value;
            std::getline(iss, value);
            properties[key] = value.erase(0, 1); // Remove leading space
        }
        std::ostringstream data_ss;
        while (std::getline(file, line)) {
            data_ss << line << "\n";
        }
        data = data_ss.str();
        file.close();
    }

    void printProperties() const {
        for (const auto& pair : properties) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
    }

    void write(const std::string& output_filepath, const std::map<std::string, std::string>& new_properties = {}) {
        if (!new_properties.empty()) {
            for (const auto& np : new_properties) {
                properties[np.first] = np.second;
            }
        }
        std::ofstream file(output_filepath);
        if (!file.is_open()) {
            std::cerr << "Error opening output file" << std::endl;
            return;
        }
        std::vector<std::string> keys = {"VERSION", "FIELDS", "SIZE", "TYPE", "COUNT", "WIDTH", "HEIGHT", "VIEWPOINT", "POINTS", "DATA"};
        for (const auto& key : keys) {
            if (properties.find(key) != properties.end()) {
                file << key << " " << properties.at(key) << "\n";
            }
        }
        file << data;
        file.close();
    }
};

// Example usage:
// int main() {
//     PCLParser parser("example.pcl");
//     parser.printProperties();
//     parser.write("new.pcl");
//     return 0;
// }