Loading Comparison/src/main/java/cz/fidentis/analyst/Project.java +30 −0 Original line number Diff line number Diff line Loading @@ -111,4 +111,34 @@ public class Project { return null; } /** * Checks whether model saved in this project has in the same directory * file with feature points * @param name String name of face * @return true if feature points file was found, false otherwise */ public boolean hasFPByName(String name) { Path path = this.getCfg().getPathToFaceByName(name); if (path != null) { String filePath = path.toString().split(".obj")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } filePath = path.toString().split("_ECA")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } filePath = path.toString().split("_CA")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } } return false; } } Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +94 −109 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import cz.fidentis.analyst.visitors.mesh.CurvatureCalculator; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; import java.util.Collections; Loading @@ -30,11 +29,10 @@ import java.util.Objects; * <p> * Changes in the human face and its data structures (e.g., mesh model, etc.) * can be monitored by listeners. Listeners have to implement the * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they * have to be registered using the * {@link cz.fidentis.analyst.face.HumanFace#registerListener} method. Then they * are informed about changes in the human automatically via methods prescribed * by the interface. * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they have to be * registered using the {@link cz.fidentis.analyst.face.HumanFace#registerListener} method. * Then they are informed about changes in the human automatically via methods * prescribed by the interface. * </p> * * @author Radek Oslejsek Loading @@ -45,8 +43,8 @@ public class HumanFace implements Serializable { private MeshModel meshModel; /** * {@code KdTree} is marked as transient because the Kryo library is not * able to handle the reference of {@code KdNode} to {@code MeshModel}s. * {@code KdTree} is marked as transient because the Kryo library is not able * to handle the reference of {@code KdNode} to {@code MeshModel}s. */ private transient KdTree kdTree; Loading @@ -69,9 +67,10 @@ public class HumanFace implements Serializable { * Fast (de)serialization handler */ //private static final FSTConfiguration FST_CONF = FSTConfiguration.createDefaultConfiguration(); /** * Reads a 3D human face from the given OBJ file. Use * {@link restoreFromFile} to restore the human face from a dump file. * Reads a 3D human face from the given OBJ file. * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @param loadLandmarks If {@code true}, then the constructor aims to load Loading @@ -80,7 +79,7 @@ public class HumanFace implements Serializable { * @throws IOException on I/O failure */ public HumanFace(File file, boolean loadLandmarks) throws IOException { meshModel = MeshObjLoader.read(new FileInputStream(file)); meshModel = MeshObjLoader.read(file); meshModel.simplifyModel(); this.id = file.getCanonicalPath(); Loading @@ -104,9 +103,9 @@ public class HumanFace implements Serializable { } /** * Reads a 3D human face from the given OBJ file. Also loads landmarks * (feature points) if appropriate file is found. Use * {@link restoreFromFile} to restore the human face from a dump file. * Reads a 3D human face from the given OBJ file. * Also loads landmarks (feature points) if appropriate file is found. * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @throws IOException on I/O failure Loading @@ -116,8 +115,8 @@ public class HumanFace implements Serializable { } /** * Creates a human face from existing mesh model. The mesh model is stored * directly (not copied). * Creates a human face from existing mesh model. The mesh model is * stored directly (not copied). * * @param model Mesh model * @param id Canonical path to the OBJ file Loading Loading @@ -169,9 +168,8 @@ public class HumanFace implements Serializable { } /** * Registers listeners (objects concerned in the human face changes) to * receive events. If listener is {@code null}, no exception is thrown and * no action is taken. * Registers listeners (objects concerned in the human face changes) to receive events. * If listener is {@code null}, no exception is thrown and no action is taken. * * @param listener Listener concerned in the human face changes. */ Loading Loading @@ -216,8 +214,7 @@ public class HumanFace implements Serializable { } /** * Sets the symmetry plane. If the input argument is {@code null}, then * removes the plane. * Sets the symmetry plane. If the input argument is {@code null}, then removes the plane. * * @param plane The new symmetry plane; Must not be {@code null} */ Loading @@ -235,7 +232,6 @@ public class HumanFace implements Serializable { /** * Returns {@code true} if the face has the symmetry plane computed. * * @return {@code true} if the face has the symmetry plane computed. */ public boolean hasSymmetryPlane() { Loading @@ -244,7 +240,6 @@ public class HumanFace implements Serializable { /** * Returns bounding box of this face. * * @return bounding box of this face. */ public BBox getBoundingBox() { Loading @@ -263,8 +258,7 @@ public class HumanFace implements Serializable { /** * Computes curvature * * @param force If {@code} then the curvature is re-computed even if it * already exists. * @param force If {@code} then the curvature is re-computed even if it already exists. */ public void computeCurvature(boolean force) { if (force || !hasCurvature) { Loading @@ -279,7 +273,7 @@ public class HumanFace implements Serializable { */ @Deprecated public void setFeaturePoints(List<FeaturePoint> points) { this.featurePoints = points; featurePoints = points; } /** Loading Loading @@ -307,7 +301,6 @@ public class HumanFace implements Serializable { /** * Checks if HumanFace has feature points * * @return true if yes and false if not */ public boolean hasFeaturePoints() { Loading @@ -325,7 +318,6 @@ public class HumanFace implements Serializable { /** * Returns canonical path to the face file * * @return canonical path to the face file */ public String getPath() { Loading @@ -333,9 +325,7 @@ public class HumanFace implements Serializable { } /** * Returns short name of the face without its path in the name. May not be * unique. * * Returns short name of the face without its path in the name. May not be unique. * @return short name of the face without its path in the name */ public String getShortName() { Loading @@ -346,7 +336,6 @@ public class HumanFace implements Serializable { /** * Returns already computed k-d tree of the triangular mesh or {@code null}. * * @return Already computed k-d tree of the triangular mesh or {@code null} */ public KdTree getKdTree() { Loading @@ -355,7 +344,6 @@ public class HumanFace implements Serializable { /** * Checks if HumanFace has KdTree calculated * * @return true if yes and false if not */ public boolean hasKdTree() { Loading @@ -365,9 +353,8 @@ public class HumanFace implements Serializable { /** * Computes new k-d tree or returns the existing one. * * @param recompute If {@code true} and an old k-d tree exists, then it is * recomputed again. Otherwise, the tree is computed only if does not exist * yet. * @param recompute If {@code true} and an old k-d tree exists, then it is recomputed again. * Otherwise, the tree is computed only if does not exist yet. * @return K-d tree with the triangular mesh. */ public KdTree computeKdTree(boolean recompute) { Loading @@ -379,7 +366,6 @@ public class HumanFace implements Serializable { /** * Removes k-d tree from the Human face. * * @return removed k-d tree or {@code null} */ public KdTree removeKdTree() { Loading @@ -389,9 +375,7 @@ public class HumanFace implements Serializable { } /** * Tries to find a file with landmarks definition based on the name of the * face's OBJ file. * * Tries to find a file with landmarks definition based on the name of the face's OBJ file. * @return The file with landmarks or {@code null} */ public final File findLandmarks() { Loading Loading @@ -446,4 +430,5 @@ public class HumanFace implements Serializable { return true; } } Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceFactory.java +3 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ import cz.fidentis.analyst.mesh.core.CornerTableRow; import cz.fidentis.analyst.mesh.core.MeshFacetImpl; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.core.MeshPointImpl; import cz.fidentis.analyst.mesh.material.Material; import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import java.io.File; Loading Loading @@ -118,11 +119,13 @@ public class HumanFaceFactory { HumanFaceFactory.kryo.register(CornerTable.class); HumanFaceFactory.kryo.register(CornerTableRow.class); HumanFaceFactory.kryo.register(BBox.class); HumanFaceFactory.kryo.register(Material.class); HumanFaceFactory.kryo.register(Plane.class); HumanFaceFactory.kryo.register(Point3d.class); HumanFaceFactory.kryo.register(Vector3d.class); HumanFaceFactory.kryo.register(ArrayList.class); HumanFaceFactory.kryo.register(HashMap.class); HumanFaceFactory.kryo.register(String.class); } } } Loading Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java +10 −7 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ public class HumanFaceUtils { boolean recomputeKdTree) { // transform mesh: System.out.println("_AAA " + staticFace.getShortName() + ":" + transformedFace.getShortName()); IcpTransformer icp = new IcpTransformer( staticFace.getMeshModel(), maxIterations, Loading Loading @@ -364,9 +365,10 @@ public class HumanFaceUtils { } /** * Moves feature points to calculated new position by computing procrustes analysis. * {@link cz.fidentis.analyst.procrustes.ProcrustesAnalysis}. If feature point was not * used in the analysis, it's position will be kept as it had in the original list. * Moves feature points to calculated new position by computing procrustes * analysis. {@link cz.fidentis.analyst.procrustes.ProcrustesAnalysis}. If * feature point was not used in the analysis, it's position will be kept as * it had in the original list. * * Move of the feature point is done to remove them from user vision first. * Loading Loading @@ -400,4 +402,5 @@ public class HumanFaceUtils { ); return featurePointList; } } Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java +51 −9 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import cz.fidentis.analyst.mesh.core.MeshPoint; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.sampling.NoSampling; import cz.fidentis.analyst.visitors.mesh.sampling.PointSampling; import cz.fidentis.analyst.visitors.mesh.sampling.RandomSampling; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; Loading Loading @@ -81,6 +82,29 @@ public class IcpTransformer extends MeshVisitor { private final PointSampling samplingStrategy; /** * Constructor for random sampling, which is the best performing downsampling strategy. * * @param mainFacet Primary mesh facet. Must not be {@code null}. * Inspected facets are transformed toward this primary mesh. * @param maxIteration Maximal number of ICP iterations (it includes computing * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param numSamples Number of samples for downsampling. Use 1000 for best performance. Zero = no downsampling * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(MeshFacet mainFacet, int maxIteration, boolean scale, double error, int numSamples) { this(new HashSet<>(Collections.singleton(mainFacet)), maxIteration, scale, error, (numSamples == 0) ? new NoSampling() : new RandomSampling(numSamples)); if (mainFacet == null) { throw new IllegalArgumentException("mainFacet"); } } /** * Constructor. * Loading @@ -90,8 +114,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bigger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading @@ -111,8 +137,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading Loading @@ -142,8 +170,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading @@ -163,7 +193,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. When reached, then the ICP stops. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading Loading @@ -259,6 +292,8 @@ public class IcpTransformer extends MeshVisitor { false // auto crop ); //int numSamples = samplingStrategy.getNumDownsampledPoints(transformedFacet.getNumberOfVertices()); //samplingStrategy.setRequiredSamples(200); MeshFacet reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy); int currentIteration = 0; Loading @@ -284,10 +319,17 @@ public class IcpTransformer extends MeshVisitor { transformation = computeIcpTransformation(nearestPoints, distances, reducedFacet.getVertices()); transformations.get(transformedFacet).add(transformation); applyTransformation(transformedFacet, transformation); if (!samplingStrategy.isBackedByOrigMesh()) { // transform samples as well if (!samplingStrategy.isBackedByOrigMesh()) { // samples have to be transfomed as well applyTransformation(reducedFacet, transformation); } currentIteration++; //if (currentIteration >= 3) { // samplingStrategy.setRequiredSamples(numSamples); // reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy); //} } } Loading Loading
Comparison/src/main/java/cz/fidentis/analyst/Project.java +30 −0 Original line number Diff line number Diff line Loading @@ -111,4 +111,34 @@ public class Project { return null; } /** * Checks whether model saved in this project has in the same directory * file with feature points * @param name String name of face * @return true if feature points file was found, false otherwise */ public boolean hasFPByName(String name) { Path path = this.getCfg().getPathToFaceByName(name); if (path != null) { String filePath = path.toString().split(".obj")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } filePath = path.toString().split("_ECA")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } filePath = path.toString().split("_CA")[0] + "_landmarks.csv"; if ((new File(filePath)).exists()) { return true; } } return false; } }
Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +94 −109 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import cz.fidentis.analyst.visitors.mesh.CurvatureCalculator; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; import java.util.Collections; Loading @@ -30,11 +29,10 @@ import java.util.Objects; * <p> * Changes in the human face and its data structures (e.g., mesh model, etc.) * can be monitored by listeners. Listeners have to implement the * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they * have to be registered using the * {@link cz.fidentis.analyst.face.HumanFace#registerListener} method. Then they * are informed about changes in the human automatically via methods prescribed * by the interface. * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they have to be * registered using the {@link cz.fidentis.analyst.face.HumanFace#registerListener} method. * Then they are informed about changes in the human automatically via methods * prescribed by the interface. * </p> * * @author Radek Oslejsek Loading @@ -45,8 +43,8 @@ public class HumanFace implements Serializable { private MeshModel meshModel; /** * {@code KdTree} is marked as transient because the Kryo library is not * able to handle the reference of {@code KdNode} to {@code MeshModel}s. * {@code KdTree} is marked as transient because the Kryo library is not able * to handle the reference of {@code KdNode} to {@code MeshModel}s. */ private transient KdTree kdTree; Loading @@ -69,9 +67,10 @@ public class HumanFace implements Serializable { * Fast (de)serialization handler */ //private static final FSTConfiguration FST_CONF = FSTConfiguration.createDefaultConfiguration(); /** * Reads a 3D human face from the given OBJ file. Use * {@link restoreFromFile} to restore the human face from a dump file. * Reads a 3D human face from the given OBJ file. * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @param loadLandmarks If {@code true}, then the constructor aims to load Loading @@ -80,7 +79,7 @@ public class HumanFace implements Serializable { * @throws IOException on I/O failure */ public HumanFace(File file, boolean loadLandmarks) throws IOException { meshModel = MeshObjLoader.read(new FileInputStream(file)); meshModel = MeshObjLoader.read(file); meshModel.simplifyModel(); this.id = file.getCanonicalPath(); Loading @@ -104,9 +103,9 @@ public class HumanFace implements Serializable { } /** * Reads a 3D human face from the given OBJ file. Also loads landmarks * (feature points) if appropriate file is found. Use * {@link restoreFromFile} to restore the human face from a dump file. * Reads a 3D human face from the given OBJ file. * Also loads landmarks (feature points) if appropriate file is found. * Use {@link restoreFromFile} to restore the human face from a dump file. * * @param file OBJ file * @throws IOException on I/O failure Loading @@ -116,8 +115,8 @@ public class HumanFace implements Serializable { } /** * Creates a human face from existing mesh model. The mesh model is stored * directly (not copied). * Creates a human face from existing mesh model. The mesh model is * stored directly (not copied). * * @param model Mesh model * @param id Canonical path to the OBJ file Loading Loading @@ -169,9 +168,8 @@ public class HumanFace implements Serializable { } /** * Registers listeners (objects concerned in the human face changes) to * receive events. If listener is {@code null}, no exception is thrown and * no action is taken. * Registers listeners (objects concerned in the human face changes) to receive events. * If listener is {@code null}, no exception is thrown and no action is taken. * * @param listener Listener concerned in the human face changes. */ Loading Loading @@ -216,8 +214,7 @@ public class HumanFace implements Serializable { } /** * Sets the symmetry plane. If the input argument is {@code null}, then * removes the plane. * Sets the symmetry plane. If the input argument is {@code null}, then removes the plane. * * @param plane The new symmetry plane; Must not be {@code null} */ Loading @@ -235,7 +232,6 @@ public class HumanFace implements Serializable { /** * Returns {@code true} if the face has the symmetry plane computed. * * @return {@code true} if the face has the symmetry plane computed. */ public boolean hasSymmetryPlane() { Loading @@ -244,7 +240,6 @@ public class HumanFace implements Serializable { /** * Returns bounding box of this face. * * @return bounding box of this face. */ public BBox getBoundingBox() { Loading @@ -263,8 +258,7 @@ public class HumanFace implements Serializable { /** * Computes curvature * * @param force If {@code} then the curvature is re-computed even if it * already exists. * @param force If {@code} then the curvature is re-computed even if it already exists. */ public void computeCurvature(boolean force) { if (force || !hasCurvature) { Loading @@ -279,7 +273,7 @@ public class HumanFace implements Serializable { */ @Deprecated public void setFeaturePoints(List<FeaturePoint> points) { this.featurePoints = points; featurePoints = points; } /** Loading Loading @@ -307,7 +301,6 @@ public class HumanFace implements Serializable { /** * Checks if HumanFace has feature points * * @return true if yes and false if not */ public boolean hasFeaturePoints() { Loading @@ -325,7 +318,6 @@ public class HumanFace implements Serializable { /** * Returns canonical path to the face file * * @return canonical path to the face file */ public String getPath() { Loading @@ -333,9 +325,7 @@ public class HumanFace implements Serializable { } /** * Returns short name of the face without its path in the name. May not be * unique. * * Returns short name of the face without its path in the name. May not be unique. * @return short name of the face without its path in the name */ public String getShortName() { Loading @@ -346,7 +336,6 @@ public class HumanFace implements Serializable { /** * Returns already computed k-d tree of the triangular mesh or {@code null}. * * @return Already computed k-d tree of the triangular mesh or {@code null} */ public KdTree getKdTree() { Loading @@ -355,7 +344,6 @@ public class HumanFace implements Serializable { /** * Checks if HumanFace has KdTree calculated * * @return true if yes and false if not */ public boolean hasKdTree() { Loading @@ -365,9 +353,8 @@ public class HumanFace implements Serializable { /** * Computes new k-d tree or returns the existing one. * * @param recompute If {@code true} and an old k-d tree exists, then it is * recomputed again. Otherwise, the tree is computed only if does not exist * yet. * @param recompute If {@code true} and an old k-d tree exists, then it is recomputed again. * Otherwise, the tree is computed only if does not exist yet. * @return K-d tree with the triangular mesh. */ public KdTree computeKdTree(boolean recompute) { Loading @@ -379,7 +366,6 @@ public class HumanFace implements Serializable { /** * Removes k-d tree from the Human face. * * @return removed k-d tree or {@code null} */ public KdTree removeKdTree() { Loading @@ -389,9 +375,7 @@ public class HumanFace implements Serializable { } /** * Tries to find a file with landmarks definition based on the name of the * face's OBJ file. * * Tries to find a file with landmarks definition based on the name of the face's OBJ file. * @return The file with landmarks or {@code null} */ public final File findLandmarks() { Loading Loading @@ -446,4 +430,5 @@ public class HumanFace implements Serializable { return true; } }
Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceFactory.java +3 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ import cz.fidentis.analyst.mesh.core.CornerTableRow; import cz.fidentis.analyst.mesh.core.MeshFacetImpl; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.core.MeshPointImpl; import cz.fidentis.analyst.mesh.material.Material; import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import java.io.File; Loading Loading @@ -118,11 +119,13 @@ public class HumanFaceFactory { HumanFaceFactory.kryo.register(CornerTable.class); HumanFaceFactory.kryo.register(CornerTableRow.class); HumanFaceFactory.kryo.register(BBox.class); HumanFaceFactory.kryo.register(Material.class); HumanFaceFactory.kryo.register(Plane.class); HumanFaceFactory.kryo.register(Point3d.class); HumanFaceFactory.kryo.register(Vector3d.class); HumanFaceFactory.kryo.register(ArrayList.class); HumanFaceFactory.kryo.register(HashMap.class); HumanFaceFactory.kryo.register(String.class); } } } Loading
Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java +10 −7 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ public class HumanFaceUtils { boolean recomputeKdTree) { // transform mesh: System.out.println("_AAA " + staticFace.getShortName() + ":" + transformedFace.getShortName()); IcpTransformer icp = new IcpTransformer( staticFace.getMeshModel(), maxIterations, Loading Loading @@ -364,9 +365,10 @@ public class HumanFaceUtils { } /** * Moves feature points to calculated new position by computing procrustes analysis. * {@link cz.fidentis.analyst.procrustes.ProcrustesAnalysis}. If feature point was not * used in the analysis, it's position will be kept as it had in the original list. * Moves feature points to calculated new position by computing procrustes * analysis. {@link cz.fidentis.analyst.procrustes.ProcrustesAnalysis}. If * feature point was not used in the analysis, it's position will be kept as * it had in the original list. * * Move of the feature point is done to remove them from user vision first. * Loading Loading @@ -400,4 +402,5 @@ public class HumanFaceUtils { ); return featurePointList; } }
Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java +51 −9 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import cz.fidentis.analyst.mesh.core.MeshPoint; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.sampling.NoSampling; import cz.fidentis.analyst.visitors.mesh.sampling.PointSampling; import cz.fidentis.analyst.visitors.mesh.sampling.RandomSampling; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; Loading Loading @@ -81,6 +82,29 @@ public class IcpTransformer extends MeshVisitor { private final PointSampling samplingStrategy; /** * Constructor for random sampling, which is the best performing downsampling strategy. * * @param mainFacet Primary mesh facet. Must not be {@code null}. * Inspected facets are transformed toward this primary mesh. * @param maxIteration Maximal number of ICP iterations (it includes computing * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param numSamples Number of samples for downsampling. Use 1000 for best performance. Zero = no downsampling * @throws IllegalArgumentException if some parameter is wrong */ public IcpTransformer(MeshFacet mainFacet, int maxIteration, boolean scale, double error, int numSamples) { this(new HashSet<>(Collections.singleton(mainFacet)), maxIteration, scale, error, (numSamples == 0) ? new NoSampling() : new RandomSampling(numSamples)); if (mainFacet == null) { throw new IllegalArgumentException("mainFacet"); } } /** * Constructor. * Loading @@ -90,8 +114,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bigger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading @@ -111,8 +137,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading Loading @@ -142,8 +170,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading @@ -163,7 +193,10 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. * @param error Acceptable error. A number bugger than or equal to zero. When reached, then the ICP stops. * @param error Acceptable error - a number bigger than or equal to zero. * Mean distance of vertices is computed for each ICP iteration. * If the difference between the previous and current mean distances is less than the error, * then the ICP computation stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong */ Loading Loading @@ -259,6 +292,8 @@ public class IcpTransformer extends MeshVisitor { false // auto crop ); //int numSamples = samplingStrategy.getNumDownsampledPoints(transformedFacet.getNumberOfVertices()); //samplingStrategy.setRequiredSamples(200); MeshFacet reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy); int currentIteration = 0; Loading @@ -284,10 +319,17 @@ public class IcpTransformer extends MeshVisitor { transformation = computeIcpTransformation(nearestPoints, distances, reducedFacet.getVertices()); transformations.get(transformedFacet).add(transformation); applyTransformation(transformedFacet, transformation); if (!samplingStrategy.isBackedByOrigMesh()) { // transform samples as well if (!samplingStrategy.isBackedByOrigMesh()) { // samples have to be transfomed as well applyTransformation(reducedFacet, transformation); } currentIteration++; //if (currentIteration >= 3) { // samplingStrategy.setRequiredSamples(numSamples); // reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy); //} } } Loading