Commit 6a03e367 authored by Adam Majzlík's avatar Adam Majzlík Committed by Radek Ošlejšek
Browse files

Introduce SymmetryManager

parent 563f5d26
Loading
Loading
Loading
Loading
+0 −13
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import cz.fidentis.analyst.data.mesh.measurement.MeshDistances;
import cz.fidentis.analyst.engines.AcaGeometryEngines;
import cz.fidentis.analyst.engines.face.impl.FaceStateServicesImpl;
import cz.fidentis.analyst.engines.sampling.PointSamplingConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryConfig;

/**
 * Services for managing a state (internal elements) of a single human face.
@@ -98,18 +97,6 @@ public interface FaceStateServices {
        impl().updateLandmarksVicinity(face, mode);
    }

    /**
     * Computes symmetry plane from mesh or landmarks.
     *
     * @param face Human face
     * @param mode Operation to be performed
     * @param meshSymmetryConfig Configuration of the mesh symmetry calculation (when needed).
     *                           If {@code null}, then the symmetry plane is computed from landmarks.
     */
    static void updateSymmetryPlane(HumanFace face, Mode mode, SymmetryConfig meshSymmetryConfig) {
        impl().updateSymmetryPlane(face, mode, meshSymmetryConfig);
    }

    /**
     * Measures the symmetry by reflecting the mesh over the symmetry plane, (optionally) registering the reflected mesh
     * to the original surface, and then measuring distances of the original mesh towards the reflected mesh
+1 −46
Original line number Diff line number Diff line
@@ -23,12 +23,9 @@ import cz.fidentis.analyst.engines.glyphs.GlyphServices;
import cz.fidentis.analyst.engines.glyphs.GlyphsConfig;
import cz.fidentis.analyst.engines.icp.IcpConfig;
import cz.fidentis.analyst.engines.icp.IcpServices;
import cz.fidentis.analyst.engines.landmarks.LandmarkServices;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceConfig;
import cz.fidentis.analyst.engines.point2surface.PointToSurfaceDistanceServices;
import cz.fidentis.analyst.engines.sampling.PointSamplingConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@@ -42,13 +39,11 @@ import java.util.Collection;
@Service
public class FaceStateServicesImpl implements FaceStateServices {

    private SymmetryServices symmetryServices;
    private IcpServices icpServices;
    private GlyphServices glyphServices;

    @Autowired
    public FaceStateServicesImpl(SymmetryServices symmetryServices, IcpServices icpServices, GlyphServices glyphServices) {
        this.symmetryServices = symmetryServices;
    public FaceStateServicesImpl(IcpServices icpServices, GlyphServices glyphServices) {
        this.icpServices = icpServices;
        this.glyphServices = glyphServices;
    }
@@ -226,46 +221,6 @@ public class FaceStateServicesImpl implements FaceStateServices {
        }
    }

    /**
     * Computes symmetry plane from mesh or landmarks.
     *
     * @param face               Human face
     * @param mode               Operation to be performed
     * @param meshSymmetryConfig Configuration of the mesh symmetry calculation (when needed).
     *                           If {@code null}, then the symmetry plane is computed from landmarks.
     */
    public void updateSymmetryPlane(HumanFace face, Mode mode, SymmetryConfig meshSymmetryConfig) {
        switch (mode) {
            case RECOMPUTE_IF_PRESENT -> {
                if (face.hasSymmetryPlane()) {
                    if (meshSymmetryConfig != null) {
                        face.setSymmetryPlane(symmetryServices.estimate(face.getMeshModel(), meshSymmetryConfig));
                    } else {
                        face.setSymmetryPlane(LandmarkServices.computeSymmetryPlane(face.getLandmarks().getAllLandmarks()));
                    }
                }
            }
            case COMPUTE_IF_ABSENT -> {
                if (!face.hasSymmetryPlane()) {
                    if (meshSymmetryConfig != null) {
                        face.setSymmetryPlane(symmetryServices.estimate(face.getMeshModel(), meshSymmetryConfig));
                    } else {
                        face.setSymmetryPlane(LandmarkServices.computeSymmetryPlane(face.getLandmarks().getAllLandmarks()));
                    }
                }
            }
            case COMPUTE_ALWAYS -> {
                if (meshSymmetryConfig != null) {
                    face.setSymmetryPlane(symmetryServices.estimate(face.getMeshModel(), meshSymmetryConfig));
                } else {
                    face.setSymmetryPlane(LandmarkServices.computeSymmetryPlane(face.getLandmarks().getAllLandmarks()));
                }
            }
            case DELETE -> face.setSymmetryPlane(null);
            default -> throw new IllegalStateException("Unexpected value: " + mode);
        }
    }

    /**
     * Measures the symmetry by reflecting the mesh over the symmetry plane, (optionally) registering the reflected mesh
     * to the original surface, and then measuring distances of the original mesh towards the reflected mesh
+5 −0
Original line number Diff line number Diff line
@@ -98,6 +98,11 @@
            <artifactId>FaceEngines</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>Managers</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.vecmath</groupId>
            <artifactId>vecmath</artifactId>
+6 −8
Original line number Diff line number Diff line
@@ -6,12 +6,11 @@ import cz.fidentis.analyst.data.face.HumanFaceFactory;
import cz.fidentis.analyst.data.landmarks.Landmark;
import cz.fidentis.analyst.data.mesh.MeshPoint;
import cz.fidentis.analyst.data.ray.Ray;
import cz.fidentis.analyst.data.shapes.Plane;
import cz.fidentis.analyst.engines.face.FaceFrontalDirectionServices;
import cz.fidentis.analyst.engines.sampling.PointSamplingConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryServices;
import cz.fidentis.analyst.gui.task.batch.Stopwatch;
import cz.fidentis.analyst.managers.symmetry.SymmetryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -51,6 +50,7 @@ import java.util.stream.Collectors;
})
@ComponentScan(basePackages = {
        "cz.fidentis.analyst.engines",
        "cz.fidentis.analyst.managers",
        "cz.fidentis.analyst.data"
})
@EnableJpaRepositories(basePackages = "cz.fidentis.analyst.data")
@@ -67,11 +67,11 @@ public class FaceFrontalDirectionStats implements CommandLineRunner {
    private static final Stopwatch SYMMETRY_TIME = new Stopwatch("Symmetry plane time:\t");
    private static final Stopwatch DETECTION_TIME = new Stopwatch("Detection time:\t");

    private final SymmetryServices symmetryServices;
    private final SymmetryManager symmetryManager;

    @Autowired
    public FaceFrontalDirectionStats(SymmetryServices symmetryServices) {
        this.symmetryServices = symmetryServices;
    public FaceFrontalDirectionStats(SymmetryManager symmetryManager) {
        this.symmetryManager = symmetryManager;
    }

    public static void main(String[] args) {
@@ -405,12 +405,10 @@ public class FaceFrontalDirectionStats implements CommandLineRunner {

    void setUpSymmetryPlane(HumanFace face) {
        SymmetryConfig symmetryConfig = new SymmetryConfig(
                SymmetryConfig.Method.ROBUST_MESH,
                new PointSamplingConfig(PointSamplingConfig.Method.UNIFORM_SPACE, 200),
                1000
        );
        Plane symmetryPlane = symmetryServices.estimate(face.getMeshModel(), symmetryConfig);
        face.setSymmetryPlane(symmetryPlane);
        symmetryManager.estimate(face, symmetryConfig, SymmetryManager.Method.ROBUST_MESH, SymmetryManager.UpdateMode.COMPUTE_ALWAYS);
    }

    private static Point3d getPronasaleCorrect(HumanFace face) {
+9 −8
Original line number Diff line number Diff line
@@ -12,8 +12,8 @@ import cz.fidentis.analyst.engines.face.FaceDistanceServices;
import cz.fidentis.analyst.engines.face.FaceStateServices;
import cz.fidentis.analyst.engines.sampling.PointSamplingConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryConfig;
import cz.fidentis.analyst.engines.symmetry.SymmetryServices;
import cz.fidentis.analyst.gui.task.batch.Stopwatch;
import cz.fidentis.analyst.managers.symmetry.SymmetryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -50,7 +50,8 @@ import java.util.stream.Collectors;
})
@ComponentScan(basePackages = {
        "cz.fidentis.analyst.engines",
        "cz.fidentis.analyst.data"
        "cz.fidentis.analyst.data",
        "cz.fidentis.analyst.managers"
})
@EnableJpaRepositories(basePackages = "cz.fidentis.analyst.data")
@EntityScan(basePackages = "cz.fidentis.analyst.data")
@@ -69,7 +70,7 @@ public class SymmetryComputationStats implements CommandLineRunner {

    // Experiment settings
    private static final int CALCULATION_REPS = 40; // number of experiment repetitions
    private static final SymmetryConfig.Method SYMMETRY_METHOD = SymmetryConfig.Method.ROBUST_POINT_CLOUD; // symmetry method used in experiments
    private static final SymmetryManager.Method SYMMETRY_METHOD = SymmetryManager.Method.ROBUST_POINT_CLOUD; // symmetry method used in experiments
    private static final List<Integer> SEARCH_DENSITY_VALUES = new ArrayList<>(List.of( // search density values used in experiments
            100, 200, 300, 500, 800));
    private static final List<Integer> PRUNING_DENSITY_VALUES = new ArrayList<>(List.of( // pruning density values used in experiments
@@ -85,11 +86,11 @@ public class SymmetryComputationStats implements CommandLineRunner {
    private static CSVWriterService symmetryStatsWriter;
    private static CSVWriterService avgPlanesWriter;

    private final SymmetryServices symmetryServices;
    private final SymmetryManager symmetryManager;

    @Autowired
    public SymmetryComputationStats(SymmetryServices symmetryServices) {
        this.symmetryServices = symmetryServices;
    public SymmetryComputationStats(SymmetryManager symmetryManager) {
        this.symmetryManager = symmetryManager;
    }

    /**
@@ -172,11 +173,11 @@ public class SymmetryComputationStats implements CommandLineRunner {
                        repNumber, subsamplingStrategy.name(), densitySearchValue, densityPruningValue);

                PointSamplingConfig samplingStrategy0 = new PointSamplingConfig(subsamplingStrategy, densitySearchValue);
                SymmetryConfig estimator0 = new SymmetryConfig(SYMMETRY_METHOD, samplingStrategy0, densityPruningValue);
                SymmetryConfig estimator0 = new SymmetryConfig(samplingStrategy0, densityPruningValue);

                COMPUTATION_TIME_SW.start();
                // Computation of symmetry plane
                face.setSymmetryPlane(symmetryServices.estimate(face.getMeshModel(), estimator0));
                symmetryManager.estimate(face, estimator0, SYMMETRY_METHOD, SymmetryManager.UpdateMode.COMPUTE_IF_ABSENT);
                COMPUTATION_TIME_SW.stop();

                // Computation of average plane
Loading