简体   繁体   中英

Smoothing STL file

So in our 3D Scan application, I should scan a foambox and save the result as an STL file.

In order to keep only the foot print part, I remove some vertexes which is above a Z value using CropStl method in the class.

At the end of the CropStl method and the brut stl goes from img1 to img2. But as you can see on the images, the border of the result is not smooth.

在此处输入图像描述 在此处输入图像描述

Is there a way to smooth the border of the second stl in C# or is there a tool for this?

Note: I use IxMilia and geometry3Sharp whici I Installed from NuGet.

  public class STLEditor
  {
    //Takes the path of the brut stl file.
    string stlPath;
    public STLEditor(string _stlPath)
    {
        stlPath = _stlPath;
    }


    internal void CropStl()
    {
        try
        {
            using (FileStream fs = new FileStream(stlPath, FileMode.Open))
            {
                //Load the stl file
                var stl = IxMilia.Stl.StlFile.Load(fs);

                //Gets all triangles of the stl file into a list.
                var triangles = stl.Triangles.ToList();
                stl.Triangles.Clear();

                //Removes vertexes which have the Z value > -15
                Predicate<IxMilia.Stl.StlTriangle> predicate = FindTriangle;
                triangles.RemoveAll(predicate);


                stl.Triangles.AddRange(triangles);

                using (FileStream fsSave = new FileStream(System.IO.Path.GetDirectoryName(stlPath) + "\\croped.stl", FileMode.Create))
                {
                    stl.Save(fsSave, false);
                }

                System.Threading.Thread.Sleep(500);

                //Tried some smoothing methods but it doesn't work as expected.
                GeometricOperations();

                System.IO.File.Delete(System.IO.Path.GetDirectoryName(stlPath) + "\\croped.stl");
            }
        }
        catch (Exception ex)
        {
            UserMethods.ParseError(ex, "CropSTL");
        }
    }

    //Gets the croped stl and smooths it. (It doesn't change the result).
    private void GeometricOperations()
    {
        g3.ReadOptions optRead = new g3.ReadOptions();
        g3.WriteOptions optWrite = new g3.WriteOptions();
        optWrite.bWriteBinary = true;
        g3.DMesh3Builder meshBuilder = new g3.DMesh3Builder();

        g3.StandardMeshReader.ReadFile(System.IO.Path.GetDirectoryName(stlPath) + "\\croped.stl", optRead, meshBuilder);

        var mesh = meshBuilder.Meshes[0];

        mesh = SmoothMesh(mesh);


        using (g3.StandardMeshWriter mr = new g3.StandardMeshWriter())
        {
            g3.STLWriter sr = new g3.STLWriter();

            List<g3.WriteMesh> wMeshList = new List<g3.WriteMesh>();
            g3.WriteMesh wMesh = new g3.WriteMesh(meshBuilder.Meshes[0]);
            wMeshList.Add(wMesh);
            mr.Write(System.IO.Path.GetDirectoryName(stlPath) + "\\smoothed.stl", wMeshList, optWrite);
        }
    }

    private DMesh3 SmoothMesh(DMesh3 mesh)
    {
        Remesher r = new Remesher(mesh);
        r.SetTargetEdgeLength(0.0240);

        for (int k = 0; k < 5; ++k)
            r.BasicRemeshPass();

        return mesh;
    }

    public static bool FindTriangle(IxMilia.Stl.StlTriangle triangle)
    {
        return triangle.Vertex1.Z > -15;
    }
}

As I understood that it was not a easy task, I tried many ways and ended by finding the solution.

I want to share my experience.

The best way I found is applying a laplacian smoothing. To do this, I installed Meshlab which is a free and incredibly nice tool.

Using Meshlab server, it is possible to select the boundaries of a 3D object and apply a laplacian smoothing like a magic touch.

To do this, you need an.mlx file to tell to the Meshlab server which operation you want to process.

Here is the content of my.mlx file:

<!DOCTYPE FilterScript>
<FilterScript>
  <filter name="Select Border"/>
  <filter name="Laplacian Smooth">
  <Param description="Smoothing steps" name="stepSmoothNum" value="72" isxmlparam="0" 
   tooltip="The number of times that the whole algorithm (normal smoothing + vertex 
   fitting) is iterated." type="RichInt"/>
  <Param description="1D Boundary Smoothing" name="Boundary" value="true" 
  isxmlparam="0" tooltip="Smooth boundary edges only by themselves (e.g. the polyline 
  forming the boundary of the mesh is independently smoothed). This can reduce the 
  shrinking on the border but can have strange effects on very small boundaries." 
  type="RichBool"/>
  <Param description="Cotangent weighting" name="cotangentWeight" value="true" 
  isxmlparam="0" tooltip="Use cotangent weighting scheme for the averaging of the 
  position. Otherwise the simpler umbrella scheme (1 if the edge is present) is used." 
  type="RichBool"/>
  <Param description="Affect only selection" name="Selected" value="true" 
  isxmlparam="0" tooltip="If checked the filter is performed only on the selected area" 
 type="RichBool"/>
 </filter>
</FilterScript>

This filter script tells which operation to do exactly to Meshlab. The parameter stepSmoothNum is to precise how many times to apply the smoothing.

Briefly, this filter script serves to select the boundary of the 3D object and apply a laplacian smoothing 72 times to only the selected faces. The objectif of smoothing only the boundaries is not loosing the details of the scan of the surface.

And calling this method in C# opens the 3D object in Meshlab, smoothes the boundaries and saves it to the folder precised in the method:

  //input => the path of the 3D object to smooth
  //output => the path where the smoothed object will be saved.
  public static bool BoundrySmoothing(string input, string output)
    {
        bool retVal = true;
        try
        {
            string strCmdText;
            string mlxPath = Tools.MeshLabRoot + "BoundrySmoothing.mlx";
            strCmdText = "/C " + Tools.MeshLabRoot +
                @"meshlabserver " +
                @"-i " + input + " " +
                @"-o " + output + " -m wt -s " +
                mlxPath;

            System.Diagnostics.Process process = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            startInfo.FileName = "cmd.exe";
            startInfo.Arguments = strCmdText;
            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo = startInfo;

            process.Start();

            process.WaitForExit();
        }
        catch (Exception ex)
        {
            UserMethods.ParseError(ex, "BoundrySmoothing");
            retVal = false;
        }

        return retVal;
    }

And the result is incredibly fine!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM