[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2051] contrib/py/scripts/addons: Initial import of io_points_pcd, importer for the point cloud data format from pcl (point cloud library).

Aurel W aurel.w at gmail.com
Tue Jun 21 12:47:16 CEST 2011


Revision: 2051
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2051
Author:   aurel
Date:     2011-06-21 10:47:15 +0000 (Tue, 21 Jun 2011)
Log Message:
-----------
Initial import of io_points_pcd, importer for the point cloud data format from pcl (point cloud library).

Added Paths:
-----------
    contrib/py/scripts/addons/io_points_pcd/
    contrib/py/scripts/addons/io_points_pcd/__init__.py
    contrib/py/scripts/addons/io_points_pcd/pcd_utils.py
    contrib/py/scripts/addons/io_points_pcd/pcdparser.py
    contrib/py/scripts/addons/io_points_pcd/test.pcd

Added: contrib/py/scripts/addons/io_points_pcd/__init__.py
===================================================================
--- contrib/py/scripts/addons/io_points_pcd/__init__.py	                        (rev 0)
+++ contrib/py/scripts/addons/io_points_pcd/__init__.py	2011-06-21 10:47:15 UTC (rev 2051)
@@ -0,0 +1,103 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+bl_info = {
+    "name": "PCD",
+    "author": "Aurel Wildfellner",
+    "version": (0, 1),
+    "blender": (2, 5, 7),
+    "api": 37304,
+    "location": "File > Import-Export > Point Cloud Data",
+    "description": "Imports and Exports PCD (Point Cloud Data) files. PCD files are the default format used by  pcl (Point Cloud Library).",
+    "warning": "",
+    "wiki_url": "",
+    "tracker_url": "",
+#    "support": 'OFFICAL',
+    "category": "Import-Export"}
+
+
+if "bpy" in locals():
+    import imp
+    imp.reload(pcd_utils)
+else:
+    from . import pcd_utils
+
+import itertools
+import os
+
+
+import bpy
+from bpy.props import *
+from bpy_extras.io_utils import ExportHelper, ImportHelper
+
+
+class ImportPCD(bpy.types.Operator, ImportHelper):
+    '''Load PCD (Point Cloud Data) files'''
+    bl_idname = "import_points.stl"
+    bl_label = "Import PCD"
+
+    filename_ext = ".pcd"
+
+    filter_glob = StringProperty(default="*.pcd", options={'HIDDEN'})
+
+    files = CollectionProperty(name="File Path",
+                          description="File path used for importing "
+                                      "the PCD file",
+                          type=bpy.types.OperatorFileListElement)
+
+    directory = StringProperty(subtype='DIR_PATH')
+
+    def execute(self, context):
+        paths = [os.path.join(self.directory, name.name) for name in self.files]
+        if not paths:
+            paths.append(self.filepath)
+
+        for path in paths:
+            pcd_utils.import_pcd(path)
+
+        return {'FINISHED'}
+
+
+
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportPCD.bl_idname, text="Point Cloud Data (.pcd)").filepath = "*.pcd"
+
+
+def menu_func_export(self, context):
+    #self.layout.operator(ExportPLY.bl_idname, text="Point Cloud Data (.pcd)")
+    pass
+
+
+def register():
+    bpy.utils.register_module(__name__)
+
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+
+
+if __name__ == "__main__":
+    register()
+

Added: contrib/py/scripts/addons/io_points_pcd/pcd_utils.py
===================================================================
--- contrib/py/scripts/addons/io_points_pcd/pcd_utils.py	                        (rev 0)
+++ contrib/py/scripts/addons/io_points_pcd/pcd_utils.py	2011-06-21 10:47:15 UTC (rev 2051)
@@ -0,0 +1,55 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+from . import pcdparser
+
+
+def create_and_link_mesh(name, points):
+    '''
+    Create a blender mesh and object called name from a list of
+    *points* and link it in the current scene.
+    '''
+
+    mesh = bpy.data.meshes.new(name)
+    mesh.from_pydata(points, [], [])
+
+    # update mesh to allow proper display
+    mesh.validate()
+    mesh.update()
+
+    scene = bpy.context.scene
+
+    obj = bpy.data.objects.new(name, mesh)
+    scene.objects.link(obj)
+    obj.select = True
+
+
+def import_pcd(filepath, name="new_pointcloud"):
+    parser = pcdparser.PCDParser.factory(filepath, pcdparser.PointXYZ)
+    parser.parseFile()
+    points = parser.getPoints()
+
+    blender_points = []
+    for point in points:
+        blender_points.append((point.x, point.y, point.z))
+
+    create_and_link_mesh(name, blender_points)
+  
+

Added: contrib/py/scripts/addons/io_points_pcd/pcdparser.py
===================================================================
--- contrib/py/scripts/addons/io_points_pcd/pcdparser.py	                        (rev 0)
+++ contrib/py/scripts/addons/io_points_pcd/pcdparser.py	2011-06-21 10:47:15 UTC (rev 2051)
@@ -0,0 +1,338 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#   
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+
+import struct
+
+
+def encodeASCIILine(line):
+    return line.decode(encoding='ASCII')
+
+
+
+class Point:
+
+    def __init__(self):
+        pass
+
+
+    def setField(self, fieldname, values):
+        pass
+
+
+
+
+class PointXYZ(Point):
+
+    x = 0
+    y = 0
+    z = 0
+
+    def __init__(self):
+        super().__init__()
+
+
+    def setField(self, fieldname, values):
+        value = values[0]
+        if fieldname == 'x':
+            self.x = value
+        elif fieldname == 'y':
+            self.y = value
+        elif fieldname == 'z':
+            self.z = value
+
+
+
+
+class PCDParser:
+
+    filepath = ''
+    file = None
+
+    points = []
+    PointClass = None
+
+    headerEnd = False
+
+
+    @staticmethod
+    def factory(filepath, PointClass):
+        version = 'NO_VERSION_NUMBER'
+        with open(filepath, 'rb') as f:
+            for b in f:
+                line = encodeASCIILine(b)
+                line_split = line.split()
+                if line_split[0] == 'VERSION' and len(line_split) > 1:
+                    version = line_split[1]
+                    break
+      
+        if version == ".7" or version == "0.7": 
+             return PCDParser_v0_7(filepath, PointClass)
+        else:
+            return None
+
+
+    def __init__(self, filepath, PointClass):
+        self.filepath = filepath
+        self.PointClass = PointClass
+
+        self.file = None
+        self.headerEnd = False
+        self.points = []
+
+
+    def parserWarning(self, msg):
+        print("[WARNING] ", msg)
+    
+
+    def rmComment(self, line):
+       return line[:line.find('#')] 
+
+
+    def parseFile(self):
+        with open(self.filepath, 'rb') as self.file:
+            self.parseHeader()
+            self.parsePoints()
+
+
+    def parseHeader(self):
+        for b in self.file:
+            line = encodeASCIILine(b)
+            line = self.rmComment(line)
+
+            split = line.split()
+            if len(split) > 0:
+                self.parseHeaderLine(split)
+
+            if self.headerEnd:
+                self.finalizeHeader()
+                break
+
+
+    def parseHeaderLine(self, split):
+        keyword = split[0]
+        self.parserWarning("Uknown header Keyword '" + keyword + "' gets ignored")
+
+    
+    def finalizeHeader(self):
+        pass
+
+
+    def parsePoints(self):
+        pass
+
+
+    def getPoints(self):
+        return self.points
+
+
+    def version(self):
+        return 'NO_VERSION_NUMBER'
+
+
+
+
+class PCDParser_v0_7(PCDParser):
+
+    fields = []
+
+    def __init__(self, filepath, PointClass):
+        super().__init__(filepath, PointClass)
+        self.fields = []
+
+
+    def version(self):
+        return '.7'
+
+
+    def parseHeaderLine(self, split):
+        keyword = split[0]
+        if keyword == 'VERSION':
+            self.parseVERSION(split[1:])
+        elif keyword == 'FIELDS':
+            self.parseFIELDS(split[1:])
+        elif keyword == 'SIZE':
+            self.parseSIZE(split[1:])
+        elif keyword == 'TYPE':
+            self.parseTYPE(split[1:])
+        elif keyword == 'COUNT':
+            self.parseCOUNT(split[1:])
+        elif keyword == 'WIDTH':
+            self.parseWIDTH(split[1:])
+        elif keyword == 'HEIGHT':
+            self.parseHEIGHT(split[1:])
+        elif keyword == 'POINTS':
+            self.parsePOINTS(split[1:])
+        elif keyword == 'DATA':
+            self.parseDATA(split[1:])
+        else:
+            super().parseHeaderLine(split)
+
+
+    def parseVERSION(self, split):
+        pass
+
+
+    def parseFIELDS(self, split):
+        print("SPLIT FIELDS:", split)
+        for field in split:
+            self.fields.append([field, None, None, None])
+        print("FIELDS, after parsing:", self.fields)
+
+
+    def parseSIZE(self, split):
+        for i, size in enumerate(split):
+            self.fields[i][1] = int(size)
+
+
+    def parseTYPE(self, split):
+        for i, type in enumerate(split):
+            self.fields[i][2] = type
+
+

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list