python读取点云文件(.stl文件、.obj文件)(以及转换为obj方法)

.1 文本方式读取 

代码如下

stl_path='/home/pxing/codes/point_improve/data/003_cracker_box/0.stl'



points=[]
f = open(stl_path)
lines = f.readlines()
prefix='vertex'
num=3
for line in lines:
    #print (line)

    if line.startswith(prefix):

        values = line.strip().split()
        #print(values[1:4])
        if num%3==0:
          points.append(values[1:4])
          num=0
        num+=1
    #print(type(line))
print(points)
f.close()

该代码可以直接将stl文件中对点直接都输出

改进版本

import numpy as np

stl_path='/home/pxing/codes/point_improve/data/003_cracker_box/0.stl'
points=[]
f = open(stl_path)
lines = f.readlines()
prefix='vertex'
num=3
for line in lines:
    #print (line)

    if line.startswith(prefix):

        values = line.strip().split()
        #print(values[1:4])
        if num%3==0:
          points.append(values[1:4])
          num=0
        num+=1
    #print(type(line))
points=np.array(points)
f.close()
print(points.shape)
np.save("/home/pxing/codes/point_improve/feature_get/point_get/test.npy", points)

把输出的点转换为npy并且保存

1.1 stl解析

.stl文件格式如下图所示:

那么读取该文件就需要知道stl的构成

stl是一种表示三角网格的文件格式

STL只能用来表示封闭的面或者体,stl文件有两种:一种是ASCII明码格式,另一种是二进制格式

ASCII明码格式:

STL文件的首行给出了文件路径及文件名

STL三维模型就是由一系列这样的三角面片构成

三角面片的信息单元 facet 是一个带矢量方向的三角面片

每一个facet由7 行数据组成:

facet normal 是三角面片指向实体外部的法矢量坐标

outer loop 代表随后的3行数据分别是三角面片的3个顶点坐标

3顶点沿指向实体外部的法矢量方向逆时针排列

solid [filename] //文件名,可以是任何字符

facet normal [i j k] //面的法线,i、j、k为三个分量,各分量之间用空格隔开,不能用逗号隔开

outor loop

vertex [x y z] //三角面片的第一个点,x、y、z三个坐标之间要用空格隔开

vertex [x y z] //三角面片的第二个点

vertex [x y z] //三角面片的第三个点

endloop

endfacet //完成一个三角面片的定义

、、、、 //其他facet

endsolid [filename] //完成一个stl文件的定义

示例:

在电脑上新建一个txt文件,然后编辑。编辑完了之后保存,并将文件后缀名改为stl,即可完成一个创建了一个stl文件。如下图,利用文本编辑器将一个四面体的几何数据保存到文件中

效果如下图所示:

1.2 stl创建 

创建一个三角形面片

solid   mystl    
facet   normal  0 -1 0
outor   loop
vertex  -100 0 0 
vertex  100 0 0
vertex  0 0 -100 
endloop
endfacet 
end solid mystl

1.3 stl分割

完成了stl分割

stl_path='/home/harry/projects/spoon_to_scoop/object_process/spilt/decomp.stl'
with open(stl_path, "r") as f:
    lines = f.readlines()
    target_end = "endsolid" 
    i=0
    for line in lines:
            with open('/home/harry/projects/spoon_to_scoop/object_process/spilt/'+'bow_'+str(i)+".stl", "a") as new_f:
                new_f.write(line)
            if target_end in line:
                i+=1

1.4 obj读取

def read_obj_vertices(file_path):
    vertices = []

    with open(file_path, 'r') as file:
        for line in file:
            if line.startswith('v '):
                vertex = line.strip().split(' ')[1:]
                vertex = [float(coord) for coord in vertex]
                vertices.append(vertex)

    return vertices


if __name__=='__main__':
    obj_file_path = './object/nontextured.obj'
    vertices = read_obj_vertices(obj_file_path)

    list=[]

    for vertex in vertices:
        list.append(vertex)
    print(list[0])

.2 把点转换为.stl

import numpy as np
import sys
sys.path.append('/home/pxing/codes/grasp_ROI_get/')
from gripper_area import area_get

arr=np.array(area_get.main())
#print(arr[0,0:3])
with open('stl_process/data/test1.stl','a') as file0:
    print('solid   mystl ',file=file0)
    print('facet   normal' ,0,0,0,file=file0)
    print('outor   loop',file=file0)
    
    print('vertex',arr[0,0],arr[0,1],arr[0,2 ],file=file0)
    print('vertex',arr[1,0],arr[1,1],arr[1,2 ],file=file0)
    print('vertex',arr[2,0],arr[2,1],arr[2,2 ],file=file0)
    
    print('endloop\nendfacet',file=file0)
    print('end solid mystl',file=file0)

.3 stl组装

import os
import numpy as np

def stl_get(stl_path):
    points=[]
    f = open(stl_path)
    lines = f.readlines()
    prefix='vertex'
    num=3
    for line in lines:
        #print (line)

        if line.startswith(prefix):
            values = line.strip().split()
            #print(values[1:4])
            if num%3==0:
                points.append([values[1],values[2],values[3]])
                num=0
            num+=1
        #print(type(line))
    points=np.array(points,dtype='float64')

    #points=points*1000#3d打印用

    
    f.close()
    #print(points.shape)
    #np.save("/home/pxing/codes/point_improve/feature_get/point_get/index_mm_level.npy", t)
    return points

def stl_generate(arr,stl_path):
    with open(stl_path,'a') as file0:
        print('solid   mystl ',file=file0)
        for i in range((arr.shape[0]-3)):
            print('facet   normal' ,0,0,0,file=file0)
            print('outor   loop',file=file0)
            print('vertex',arr[i,0],arr[i,1],arr[i,2 ],file=file0)
            print('vertex',arr[i+1,0],arr[i+1,1],arr[i+1,2 ],file=file0)
            print('vertex',arr[i+2,0],arr[i+2,1],arr[i+2,2 ],file=file0)
            print('endloop\nendfacet',file=file0)
        
        print('end solid mystl',file=file0)
    print('generate success')

def mkdir(path):
 
	folder = os.path.exists(path)

	if not folder:#判断是否存在文件夹如果不存在则创建为文件夹
		os.makedirs(path) #makedirs 创建文件时如果路径不存在会创建这个路径




file_path='/home/pxing/codes/point_improve/data/process_projection/'#stl储存的位置
goods_list=os.listdir(file_path)
for i in goods_list:
    #对所有0子文件夹进行组装
    index=0
    file_stl_path=file_path+i+'/'+str(index)
    stl_list=os.listdir(file_stl_path)
    
    if stl_list:
        arr_assembly=np.array([[0,0,0]])#创建一个空数组来组成后面的元素
        for j in stl_list:
            print(stl_list)
            stl_path=file_stl_path+'/'+j
            arr=stl_get(stl_path)
            arr_assembly=np.concatenate((arr_assembly,arr),axis=0)
        
        arr_assembly=np.delete(arr_assembly,[0,0],axis=0)
        file_save_path='/home/pxing/codes/point_improve/data/auto_assembly_data/'+i+'/'+str(index)
        mkdir(file_save_path)
        stl_save_path=file_save_path+'/'+str(index)+'.stl'
        stl_generate(arr_assembly,stl_save_path)
            
        
    else:
        pass

.4 stl转obj(带f法向量的obj)

import numpy as np



def stl_get(stl_path):
    points=[]
    f = open(stl_path)
    lines = f.readlines()
    prefix='vertex'
    num=3
    for line in lines:
        #print (line)

        if line.startswith(prefix):
            values = line.strip().split()
            #print(values[1:4])
            if num%3==0:
                points.append([values[1],values[2],values[3]])
                num=0
            num+=1
        #print(type(line))
    points=np.array(points,dtype='float64')

    #points=points*1000#3d打印用

    
    f.close()
    #print(points.shape)
    #np.save("/home/pxing/codes/point_improve/feature_get/point_get/index_mm_level.npy", t)
    return points

# 点云数据

stl_path='/home/pxing/codes/point_improve/data/rotation_data/assembly_projection_isaac.stl'
points = stl_get(stl_path)

# 计算点云的法向量
def compute_normals(points):
    normals = []
    for i, p0 in enumerate(points):
        v1 = points[(i+1) % len(points)] - p0
        v2 = points[(i+2) % len(points)] - p0
        normals.append(np.cross(v1, v2))
    return normals

normals = compute_normals(points)

# 将点云和法向量保存为OBJ格式文件
with open('/home/pxing/codes/point_improve/data/obj/point_f_assembly.obj', 'w') as f:
    for i, p in enumerate(points):
        f.write(f'v {p[0]} {p[1]} {p[2]}\n')
        n = normals[i]
        f.write(f'vn {n[0]} {n[1]} {n[2]}\n')

生成带面的obj

import numpy as np



def stl_get(stl_path):
    points=[]
    f = open(stl_path)
    lines = f.readlines()
    prefix='vertex'
    num=3
    for line in lines:
        #print (line)

        if line.startswith(prefix):
            values = line.strip().split()
            #print(values[1:4])
            if num%3==0:
                points.append([values[1],values[2],values[3]])
                num=0
            num+=1
        #print(type(line))
    points=np.array(points,dtype='float64')

    #points=points*1000#3d打印用

    
    f.close()
    #print(points.shape)
    #np.save("/home/pxing/codes/point_improve/feature_get/point_get/index_mm_level.npy", t)
    return points

# 点云数据

stl_path='/home/pxing/codes/point_improve/data/rotation_data/assembly_projection_isaac.stl'
points = stl_get(stl_path)
 

# 计算点云的法向量
def compute_normals(points):
    normals = []
    for i, p0 in enumerate(points):
        v1 = points[(i+1) % len(points)] - p0
        v2 = points[(i+2) % len(points)] - p0
        normals.append(np.cross(v1, v2))
    return normals

normals = compute_normals(points)

# 将点云和法向量保存为OBJ格式文件
with open('/home/pxing/codes/point_improve/data/obj/point_f_assembly.obj', 'w') as f:
    for i, p in enumerate(points):
        f.write(f'v {p[0]} {p[1]} {p[2]}\n')
        n = normals[i]
        f.write(f'vn {n[0]} {n[1]} {n[2]}\n')

    # 将点云转换为面信息
    for i in range(0, len(points), 3):
        f.write(f'f {i+1}//{i+1} {i+2}//{i+2} {i+3}//{i+3}\n')

.5 ply生成

import numpy as np

def stl_get(stl_path):
    points=[]
    f = open(stl_path)
    lines = f.readlines()
    prefix='vertex'
    num=3
    for line in lines:
        #print (line)

        if line.startswith(prefix):
            values = line.strip().split()
            #print(values[1:4])
            if num%3==0:
                points.append([values[1],values[2],values[3]])
                num=0
            num+=1
        #print(type(line))
    points=np.array(points,dtype='float64')

    #points=points*1000#3d打印用

    
    f.close()
    #print(points.shape)
    #np.save("/home/pxing/codes/point_improve/feature_get/point_get/index_mm_level.npy", t)
    return points

# 点云数据

stl_path='/home/pxing/codes/point_improve/data/rotation_data/assembly_projection_isaac.stl'
points = stl_get(stl_path)

# 将点云保存为含有顶点和面信息的PLY格式文件
with open('/home/pxing/codes/point_improve/data/obj/point_cloud.ply', 'w') as f:
    # 写入PLY文件头
    f.write('ply\n')
    f.write('format ascii 1.0\n')
    f.write(f'element vertex {len(points)}\n')
    f.write('property float x\n')
    f.write('property float y\n')
    f.write('property float z\n')
    f.write(f'element face {len(points)}\n')
    f.write('property list uchar int vertex_indices\n')
    f.write('end_header\n')

    # 写入点云数据
    for p in points:
        f.write(f'{p[0]} {p[1]} {p[2]}\n')

    # 写入面数据
    for i in range(len(points)):
        f.write(f'3 {i} {i} {i}\n')

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年11月9日
下一篇 2023年11月9日

相关推荐