通过“面部正常值"阈值选择STL的面部 [英] Selection of Face of a STL by Face Normal value Threshold

查看:144
本文介绍了通过“面部正常值"阈值选择STL的面部的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用Python编写一个脚本,该脚本可以根据Face Normal值条件在STL中生成面部组.例如,提供的是Stl的快照,不同的颜色表示包含满足我的给定脸部法线阈值的三角形脸部的脸部组.有没有简单的方法可以在python中做到这一点? 面板组STL

I want to write a script in Python which can generate facegroups in a STL as per the Face Normal value condition. For example, Provided is the snap of Stl, Different colour signifies the face group containing the triangular faces satisfying my given face normal threshold. Is there any simple way to do this in python? Face Group STL

推荐答案

我确定有一个python库可以加载stl文件,但是我总是自己编写自己的,因为文件格式非常简单(请参见维基百科文章(用于文件格式说明).

I'm sure there's a python library to load stl files, but I've always just written my own, since the file format is pretty simple (see the Wikipedia article for file format description).

这是我读取stl文件的代码:

Here is my code to read the stl file:

import numpy as np
import struct

def Unique(inputList):
      """ 
      Given an M x N list, this function gets the unique rows by treating all
      M Ntuples as single objects. This function also returns the indexing
      to convert the unique returned list back to the original non-unique list.
      """

      hashTable=dict()

      indexList=[]
      uniqueList=[]

      indx=0
      for ntuple in inputList:
            if not ntuple in hashTable:
                hashTable[ntuple]=indx
                indexList.append(indx)
                uniqueList.append(ntuple)
                indx+=1
            else:
                indexList.append(hashTable.get(ntuple))      

      return uniqueList, indexList


def IsBinarySTL(filename):
    try:
        with open(filename,'r') as f:
              test=f.readline()
    except UnicodeDecodeError:
        return True

    if len(test) < 5:
        return True
    elif test[0:5].lower() == 'solid':
        return False  # ASCII STL
    else:
        return True

def ReadSTL(filename):
    """ Returns numpy arrays for vertices and facet indexing """
    def GetListFromASCII(filename):
        """ Returns vertex listing from ASCII STL file """
        outputList=[]

        with open(filename,'r') as f:
            lines=[line.split() for line in f.readlines()]
        for line in lines:
            if line[0] == 'vertex':
                    outputList.append(tuple([float(x) for x in line[1:]]))
        return outputList

    def GetListFromBinary(filename):
        """ Returns vertex listing from binary STL file """
        outputList=[]
        with open(filename,'rb') as f:
            f.seek(80) # skip header
            nFacets=struct.unpack('I',f.read(4))[0] # number of facets in piece

            for i in range(nFacets):
                  f.seek(12,1) # skip normal
                  outputList.append(struct.unpack('fff',f.read(12))) # append each vertex triple to list (each facet has 3 vertices)
                  outputList.append(struct.unpack('fff',f.read(12))) 
                  outputList.append(struct.unpack('fff',f.read(12)))
                  f.seek(2,1) # skip attribute
        return outputList

    if IsBinarySTL(filename):
        vertexList = GetListFromBinary(filename)
    else:
        vertexList = GetListFromASCII(filename)

    coords, tempindxs = Unique(vertexList)

    indxs = list()
    templist = list()
    for i in range(len(tempindxs)):
        if (i > 0 ) and not (i % 3):
            indxs.append(templist)
            templist = list()
        templist.append(tempindxs[i])
    indxs.append(templist)

    return np.array(coords), np.array(indxs)

这是计算构面法线的代码(假设右手法则)

And here is code to compute the facet normals (assuming right-hand-rule)

def GetNormals(vertices, facets):
    """ Returns normals for each facet of mesh """
    u = vertices[facets[:,1],:] - vertices[facets[:,0],:]
    v = vertices[facets[:,2],:] - vertices[facets[:,0],:]
    normals = np.cross(u,v)
    norms = np.sqrt(np.sum(normals*normals, axis=1))
    return normals/norms[:, np.newaxis]

最后,编写出stl文件的代码(假定每个构面的属性列表):

Finally, code to write out the stl file (assuming a list of attributes for each facet):

def WriteSTL(filename, vertices, facets, attributes, header):
    """
    Writes vertices and facets to an stl file. Notes:
    1.) header can not be longer than 80 characters
    2.) length of attributes must be equal to length of facets
    3.) attributes must be integers
    """
    nspaces = 80 - len(header)
    header += nspaces*'\0'

    nFacets = np.shape(facets)[0]
    stl = vertices[facets,:].tolist()

    with open(filename,'wb') as f: # binary
        f.write(struct.pack('80s', header.encode('utf-8'))) # header
        f.write(struct.pack('I',nFacets)) # number of facets
        for i in range(nFacets):
            f.write(struct.pack('fff',0,0,0)) # normals set to 0
            for j in range(3):
                f.write(struct.pack('fff',stl[i][j][0], stl[i][j][1], stl[i][j][2])) # 3 vertices per facet 
            f.write(struct.pack("H", attributes[i])) # 2-byte attribute

将所有内容放在一起,您可以执行以下操作:

Putting this all together, you can do something like the following:

if __name__ == "__main__":
    filename = "bunny.stl"

    vertices, facets = ReadSTL(filename)  # parse stl file
    normals = GetNormals(vertices, facets)  # compute normals

    # Get some value related to normals
    attributes = []
    for i in range(np.shape(normals)[0]):
        attributes.append(int(255*np.sum(normals[i])**2))

    # Write new stl file
    WriteSTL("output.stl", vertices, facets, attributes, "stlheader")

此代码段读取一个stl文件,计算法线,然后根据每个法线的平方和分配属性值(请注意,该属性必须为整数).

this code snippet reads an stl file, computes the normals, and then assigns an attribute value based on the squared-sum of each normal (note that the attribute must be an integer).

此脚本的输入和输出如下所示:

The input and output of this script look like the following:

这篇关于通过“面部正常值"阈值选择STL的面部的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆