Loading Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java +38 −30 Original line number Diff line number Diff line Loading @@ -3,12 +3,9 @@ package cz.fidentis.analyst.face; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.icp.IcpTransformer; import cz.fidentis.analyst.icp.Quaternion; import cz.fidentis.analyst.procrustes.ProcrustesAnalysisFaceModel; import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.visitors.mesh.sampling.PointSampling; import cz.fidentis.analyst.visitors.procrustes.ProcrustesVisitor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; Loading @@ -18,7 +15,6 @@ import javax.vecmath.Matrix4d; import javax.vecmath.Point3d; import javax.vecmath.Tuple3d; import javax.vecmath.Vector3d; import org.ejml.simple.SimpleMatrix; /** * A utility class for operations (visitors) applied onto the whole human faces. Loading Loading @@ -367,9 +363,20 @@ public class HumanFaceUtils { return new Plane(retPlane.getNormal(), dist); } /** * 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. * * @param secondFace * @param movedFeaturePoints */ private static void moveFeaturePoints(HumanFace secondFace, HashMap<Integer, FeaturePoint> movedFeaturePoints) { secondFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = movedFeaturePoints.get(fp.getFeaturePointType().getType()); if (movedFp != null) { if (fp.getFeaturePointType().getType() != movedFp.getFeaturePointType().getType()) { throw new RuntimeException("Types do not correspond"); Loading @@ -377,6 +384,7 @@ public class HumanFaceUtils { fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); } }); } Loading Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesAnalysis.java +50 −52 Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ import cz.fidentis.analyst.Logger; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.feature.api.IPosition; import cz.fidentis.analyst.mesh.core.MeshPoint; import org.ejml.simple.SimpleMatrix; import org.ejml.simple.SimpleSVD; Loading @@ -19,7 +18,6 @@ import javax.swing.JOptionPane; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import cz.fidentis.analyst.procrustes.ProcrustesAnalysisFaceModel; import java.util.Comparator; /** Loading Loading @@ -49,11 +47,12 @@ public class ProcrustesAnalysis { ProcrustesAnalysisFaceModel model1; ProcrustesAnalysisFaceModel model2; // check if feature points lists of both faces have the same size and same types // if not, than we will be working with subset or cancel the analysis if (humanFace1.getFeaturePoints().size() != humanFace2.getFeaturePoints().size() || !checkFeaturePointsType( sortListByFeaturePointType(humanFace1.getFeaturePoints()), sortListByFeaturePointType(humanFace1.getFeaturePoints()))) { // int n = 0; Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog( Loading @@ -70,7 +69,7 @@ public class ProcrustesAnalysis { model1 = new ProcrustesAnalysisFaceModel(humanFace1, viablePoints); model2 = new ProcrustesAnalysisFaceModel(humanFace2, viablePoints); Logger.print("Yes"); Logger.print(Integer.valueOf(n).toString()); Logger.print(Integer.toString(n)); } else { JOptionPane.showMessageDialog(new JFrame("Procrustes cancelled"), "Lists of feature points do not have the same size and work on subset was cancelled"); Loading @@ -81,11 +80,12 @@ public class ProcrustesAnalysis { model2 = new ProcrustesAnalysisFaceModel(humanFace2); } this.modelCentroid1 = findCentroidOfFeaturePoints(model1.getFeaturePointValues()); this.modelCentroid2 = findCentroidOfFeaturePoints(model2.getFeaturePointValues()); this.faceModel1 = model1; this.faceModel2 = model2; this.modelCentroid1 = findCentroidOfFeaturePoints(model1.getFeaturePointValues()); this.modelCentroid2 = findCentroidOfFeaturePoints(model2.getFeaturePointValues()); } /** Loading Loading @@ -137,15 +137,13 @@ public class ProcrustesAnalysis { // calculation of rotation matrix transformation.setRotationMatrix(this.rotate()); // move faces back to so the centroid of vertices is in the origin point // move face vertices back, so the original place, // but set feture points map to already superimposed position moveFaceModel(faceModel1, new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); // moveFaceModel(faceModel2, new Vector3d(this.modelCentroid2.x, this.modelCentroid2.y, this.modelCentroid2.z)); moveFaceModel(faceModel2, new Vector3d(this.modelCentroid2.x, this.modelCentroid2.y, this.modelCentroid2.z), new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); // move featurepoints stored in map to superimposed true position // moveFeaturePoints(faceModel2, new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); transformation.setFaceModel(faceModel2); } else { Loading @@ -154,12 +152,12 @@ public class ProcrustesAnalysis { return transformation; } private Vector3d getPointDistance(Point3d point1, Point3d point2) { if (point1 == null || point2 == null) { return null; } return new Vector3d((point2.x - point1.x), (point2.y - point1.y), (point2.z - point1.z)); } // private Vector3d getPointDistance(Point3d point1, Point3d point2) { // if (point1 == null || point2 == null) { // return null; // } // return new Vector3d((point2.x - point1.x), (point2.y - point1.y), (point2.z - point1.z)); // } /** * Moves all vertices and feature points of a face by given vector value Loading @@ -168,12 +166,12 @@ public class ProcrustesAnalysis { * @param vector vector its values are used to move a face */ private void moveFaceModel(ProcrustesAnalysisFaceModel faceModel, Vector3d vector) { for (FeaturePoint fp : faceModel.getFeaturePointsMap().values()) { faceModel.getFeaturePointsMap().values().forEach(fp -> { movePoint(fp, vector); } for (MeshPoint v : faceModel.getVertices()) { }); faceModel.getVertices().forEach(v -> { movePoint(v, vector); } }); } /** Loading @@ -187,16 +185,16 @@ public class ProcrustesAnalysis { * @param featurePointVector feature points adjustment */ private void moveFaceModel(ProcrustesAnalysisFaceModel faceModel, Vector3d vertexVector, Vector3d featurePointVector) { for (FeaturePoint fp : faceModel.getFeaturePointsMap().values()) { faceModel.getFeaturePointsMap().values().forEach(fp -> { movePoint(fp, featurePointVector); } for (MeshPoint v : faceModel.getVertices()) { }); faceModel.getVertices().forEach(v -> { movePoint(v, vertexVector); } }); } /** * Moves point by given vector value * Moves point by given vector value. * * @param <T> * @param point Loading @@ -209,7 +207,7 @@ public class ProcrustesAnalysis { } /** * By rotation of matrices solves orthogonal procrustes problem * By rotation of matrices solves orthogonal procrustes problem. */ private SimpleMatrix rotate() { SimpleMatrix primaryMatrix = createMatrixFromList(this.faceModel2.getFeaturePointValues()); Loading Loading @@ -276,10 +274,10 @@ public class ProcrustesAnalysis { * @param faceModel * @param scaleFactor */ private void scaleFace(ProcrustesAnalysisFaceModel faceModel, double scaleFactor) { calculateScaledList(faceModel.getVertices(), scaleFactor); calculateScaledList(faceModel.getFeaturePointValues(), scaleFactor); } // private void scaleFace(ProcrustesAnalysisFaceModel faceModel, double scaleFactor) { // calculateScaledList(faceModel.getVertices(), scaleFactor); // calculateScaledList(faceModel.getFeaturePointValues(), scaleFactor); // } /** * Scales each given point from list by multiplying its position coordinates Loading @@ -306,13 +304,13 @@ public class ProcrustesAnalysis { */ // if rotated vertices are drawn immediately it is better to set them after rotating them all // so it would be drawn just once private void rotateVertices(List<MeshPoint> vertices, SimpleMatrix matrix) { if (vertices != null) { for (int i = 0; i < vertices.size(); i++) { rotateVertex(vertices.get(i), matrix); } } } // private void rotateVertices(List<MeshPoint> vertices, SimpleMatrix matrix) { // if (vertices != null) { // for (int i = 0; i < vertices.size(); i++) { // rotateVertex(vertices.get(i), matrix); // } // } // } /** * Rotates vertex v by simulating matrix multiplication with given matrix Loading @@ -320,20 +318,20 @@ public class ProcrustesAnalysis { * @param v * @param matrix */ private static void rotateVertex(MeshPoint v, SimpleMatrix matrix) { double x = ((v.getX() * matrix.get(0, 0)) + (v.getY() * matrix.get(1, 0)) + (v.getZ() * matrix.get(2, 0))); double y = ((v.getX() * matrix.get(0, 1)) + (v.getY() * matrix.get(1, 1)) + (v.getZ() * matrix.get(2, 1))); double z = ((v.getX() * matrix.get(0, 2)) + (v.getY() * matrix.get(1, 2)) + (v.getZ() * matrix.get(2, 2))); v.getPosition().x = x; v.getPosition().y = y; v.getPosition().z = z; } // private static void rotateVertex(MeshPoint v, SimpleMatrix matrix) { // double x = ((v.getX() * matrix.get(0, 0)) // + (v.getY() * matrix.get(1, 0)) // + (v.getZ() * matrix.get(2, 0))); // double y = ((v.getX() * matrix.get(0, 1)) // + (v.getY() * matrix.get(1, 1)) // + (v.getZ() * matrix.get(2, 1))); // double z = ((v.getX() * matrix.get(0, 2)) // + (v.getY() * matrix.get(1, 2)) // + (v.getZ() * matrix.get(2, 2))); // v.getPosition().x = x; // v.getPosition().y = y; // v.getPosition().z = z; // } /** * Scales position of given point by multiplying its coordinates with given Loading Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesAnalysisFaceModel.java +95 −31 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ public class ProcrustesAnalysisFaceModel { private final HumanFace humanFace; private HashMap<Integer, FeaturePoint> featurePointsMap; // sorted by feature point type private List<MeshPoint> vertices; private MeshModel meshModel; private final MeshModel meshModel; private final HashMap<Integer, Integer> featurePointTypeCorrespondence; /** Loading Loading @@ -57,7 +57,7 @@ public class ProcrustesAnalysisFaceModel { List<FeaturePoint> modifiableFeaturePointList = getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints); // Currently set feature points is not working as inteded because gui doesn't repaint them after changing values face.setFeaturePoints(modifiableFeaturePointList); // face.setFeaturePoints(modifiableFeaturePointList); // To be able to move vertices we have to make a copy of them because getFacets() returns unmodifiable List List<MeshPoint> modifiableVertices = new ArrayList<>(face.getMeshModel().getFacets().get(0).getVertices()); Loading @@ -70,15 +70,43 @@ public class ProcrustesAnalysisFaceModel { } /** * sets feature points map and also sets feature point on human face for * visualisation * Use this constructor instead of the * {@link #ProcrustesAnalysisFaceModel(cz.fidentis.analyst.face.HumanFace, java.util.List)} * until the * {@link cz.fidentis.analyst.face.HumanFace#setFeaturePoints(java.util.List)} * is fixed and fires event to render in GUI a new set of feature points. * * Feature points that are not used in subset are moved to position of * modelCentroid. * * @param humanFace1 * @param viablePoints * @param modelCentroid1 */ // ProcrustesAnalysisFaceModel(HumanFace face, ArrayList<Integer> viablePoints, Point3d modelCentroid) { // this.humanFace = face; // // getFeaturePoints() returns unmodifiable List. To sort it we need to make copy first // List<FeaturePoint> modifiableFeaturePointList = getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints); // // // To be able to move vertices we have to make a copy of them because getFacets() returns unmodifiable List // List<MeshPoint> modifiableVertices = new ArrayList<>(face.getMeshModel().getFacets().get(0).getVertices()); // // this.vertices = modifiableVertices; // this.meshModel = face.getMeshModel(); // this.featurePointsMap = createFeaturePointMap( // sortListByFeaturePointType(modifiableFeaturePointList)); // this.featurePointTypeCorrespondence = createFeaturePointTypeCorrespondence(face.getFeaturePoints()); // } /** * Sets feature points map and also sets feature point on human face for * visualisation. * * @param featurePointsMap */ public void setFeaturePointsMap(HashMap<Integer, FeaturePoint> featurePointsMap) { this.featurePointsMap = featurePointsMap; readjustFeaturePoints(featurePointsMap); // this.humanFace.setFeaturePoints(getFeaturePointValues()); } Loading Loading @@ -106,6 +134,15 @@ public class ProcrustesAnalysisFaceModel { return featurePointTypeCorrespondence; } /** * Creates a subset of selected feature points that can be used for * procrustes analysis. Each of the feature point types contained in the * subset is contained in both faces. * * @param featurePoints * @param viablePoints * @return */ private List<FeaturePoint> getSelectionOfFeaturePoints(List<FeaturePoint> featurePoints, List<Integer> viablePoints) { ArrayList<FeaturePoint> selection = new ArrayList<>(); featurePoints.forEach(fp -> { Loading @@ -116,6 +153,30 @@ public class ProcrustesAnalysisFaceModel { return selection; } /** * {@link #getSelectionOfFeaturePoints(java.util.List, java.util.List)} * Feature points that are not in subset are moved to position of * modelCentroid. * * @param featurePoints * @param viablePoints * @param modelCentroid * @return */ // private List<FeaturePoint> getSelectionOfFeaturePoints(List<FeaturePoint> featurePoints, ArrayList<Integer> viablePoints, Point3d modelCentroid) { // ArrayList<FeaturePoint> selection = new ArrayList<>(); // featurePoints.forEach(fp -> { // if (viablePoints.contains(fp.getFeaturePointType().getType())) { // selection.add(fp); // } else { // fp.getPosition().x = modelCentroid.x; // fp.getPosition().y = modelCentroid.y; // fp.getPosition().z = modelCentroid.z; // } // }); // return selection; // } /** * Creates corresponding key value pair of matrix row index and a feature * point type value. It is used so we can get back type of feature point Loading Loading @@ -163,28 +224,9 @@ public class ProcrustesAnalysisFaceModel { } private void readjustFeaturePoints(HashMap<Integer, FeaturePoint> featurePointsMap) { if (featurePointsMap.size() != this.humanFace.getFeaturePoints().size()) { readjustSelection(featurePointsMap); } else { this.humanFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); if (fp.getFeaturePointType().getType() != movedFp.getFeaturePointType().getType()) { throw new RuntimeException("Types do not correspond"); } fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); }); } } /** * Moves subset of feature points to their new position. If point doesn't belong to subset it is moved to (0,0,0) instead. * * @param featurePointsMap */ private void readjustSelection(HashMap<Integer, FeaturePoint> featurePointsMap) { // if (featurePointsMap.size() != this.humanFace.getFeaturePoints().size()) { // readjustSelection(featurePointsMap); // } else { this.humanFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); if (movedFp != null) { Loading @@ -195,12 +237,34 @@ public class ProcrustesAnalysisFaceModel { fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); } else { fp.getPosition().x = 0; fp.getPosition().y = 0; fp.getPosition().z = 0; } }); // } } // /** // * Moves subset of feature points to their new position. If point doesn't // * belong to subset it is moved to (0,0,0) instead. // * // * @param featurePointsMap // */ // private void readjustSelection(HashMap<Integer, FeaturePoint> featurePointsMap) { // this.humanFace.getFeaturePoints().forEach(fp -> { // FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); // if (movedFp != null) { // if (fp.getFeaturePointType().getType() // != movedFp.getFeaturePointType().getType()) { // throw new RuntimeException("Types do not correspond"); // } // fp.getPosition().x = movedFp.getX(); // fp.getPosition().y = movedFp.getY(); // fp.getPosition().z = movedFp.getZ(); // } else { // fp.getPosition().x = 0; // fp.getPosition().y = 0; // fp.getPosition().z = 0; // } // }); // } } Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesTransformation.java +1 −6 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package cz.fidentis.analyst.procrustes; import cz.fidentis.analyst.icp.Quaternion; Loading @@ -11,7 +6,7 @@ import org.ejml.simple.SimpleMatrix; /** * Class used to store information about transformation that needs to be applied * to a second face when computing procrustes analysis * to a second face when computing procrustes analysis. * * @author Jakub Kolman */ Loading Comparison/src/main/java/cz/fidentis/analyst/visitors/procrustes/ProcrustesVisitor.java +0 −5 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package cz.fidentis.analyst.visitors.procrustes; import cz.fidentis.analyst.face.HumanFace; Loading Loading
Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java +38 −30 Original line number Diff line number Diff line Loading @@ -3,12 +3,9 @@ package cz.fidentis.analyst.face; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.icp.IcpTransformer; import cz.fidentis.analyst.icp.Quaternion; import cz.fidentis.analyst.procrustes.ProcrustesAnalysisFaceModel; import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.visitors.mesh.sampling.PointSampling; import cz.fidentis.analyst.visitors.procrustes.ProcrustesVisitor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; Loading @@ -18,7 +15,6 @@ import javax.vecmath.Matrix4d; import javax.vecmath.Point3d; import javax.vecmath.Tuple3d; import javax.vecmath.Vector3d; import org.ejml.simple.SimpleMatrix; /** * A utility class for operations (visitors) applied onto the whole human faces. Loading Loading @@ -367,9 +363,20 @@ public class HumanFaceUtils { return new Plane(retPlane.getNormal(), dist); } /** * 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. * * @param secondFace * @param movedFeaturePoints */ private static void moveFeaturePoints(HumanFace secondFace, HashMap<Integer, FeaturePoint> movedFeaturePoints) { secondFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = movedFeaturePoints.get(fp.getFeaturePointType().getType()); if (movedFp != null) { if (fp.getFeaturePointType().getType() != movedFp.getFeaturePointType().getType()) { throw new RuntimeException("Types do not correspond"); Loading @@ -377,6 +384,7 @@ public class HumanFaceUtils { fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); } }); } Loading
Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesAnalysis.java +50 −52 Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ import cz.fidentis.analyst.Logger; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.feature.api.IPosition; import cz.fidentis.analyst.mesh.core.MeshPoint; import org.ejml.simple.SimpleMatrix; import org.ejml.simple.SimpleSVD; Loading @@ -19,7 +18,6 @@ import javax.swing.JOptionPane; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import cz.fidentis.analyst.procrustes.ProcrustesAnalysisFaceModel; import java.util.Comparator; /** Loading Loading @@ -49,11 +47,12 @@ public class ProcrustesAnalysis { ProcrustesAnalysisFaceModel model1; ProcrustesAnalysisFaceModel model2; // check if feature points lists of both faces have the same size and same types // if not, than we will be working with subset or cancel the analysis if (humanFace1.getFeaturePoints().size() != humanFace2.getFeaturePoints().size() || !checkFeaturePointsType( sortListByFeaturePointType(humanFace1.getFeaturePoints()), sortListByFeaturePointType(humanFace1.getFeaturePoints()))) { // int n = 0; Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog( Loading @@ -70,7 +69,7 @@ public class ProcrustesAnalysis { model1 = new ProcrustesAnalysisFaceModel(humanFace1, viablePoints); model2 = new ProcrustesAnalysisFaceModel(humanFace2, viablePoints); Logger.print("Yes"); Logger.print(Integer.valueOf(n).toString()); Logger.print(Integer.toString(n)); } else { JOptionPane.showMessageDialog(new JFrame("Procrustes cancelled"), "Lists of feature points do not have the same size and work on subset was cancelled"); Loading @@ -81,11 +80,12 @@ public class ProcrustesAnalysis { model2 = new ProcrustesAnalysisFaceModel(humanFace2); } this.modelCentroid1 = findCentroidOfFeaturePoints(model1.getFeaturePointValues()); this.modelCentroid2 = findCentroidOfFeaturePoints(model2.getFeaturePointValues()); this.faceModel1 = model1; this.faceModel2 = model2; this.modelCentroid1 = findCentroidOfFeaturePoints(model1.getFeaturePointValues()); this.modelCentroid2 = findCentroidOfFeaturePoints(model2.getFeaturePointValues()); } /** Loading Loading @@ -137,15 +137,13 @@ public class ProcrustesAnalysis { // calculation of rotation matrix transformation.setRotationMatrix(this.rotate()); // move faces back to so the centroid of vertices is in the origin point // move face vertices back, so the original place, // but set feture points map to already superimposed position moveFaceModel(faceModel1, new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); // moveFaceModel(faceModel2, new Vector3d(this.modelCentroid2.x, this.modelCentroid2.y, this.modelCentroid2.z)); moveFaceModel(faceModel2, new Vector3d(this.modelCentroid2.x, this.modelCentroid2.y, this.modelCentroid2.z), new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); // move featurepoints stored in map to superimposed true position // moveFeaturePoints(faceModel2, new Vector3d(this.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z)); transformation.setFaceModel(faceModel2); } else { Loading @@ -154,12 +152,12 @@ public class ProcrustesAnalysis { return transformation; } private Vector3d getPointDistance(Point3d point1, Point3d point2) { if (point1 == null || point2 == null) { return null; } return new Vector3d((point2.x - point1.x), (point2.y - point1.y), (point2.z - point1.z)); } // private Vector3d getPointDistance(Point3d point1, Point3d point2) { // if (point1 == null || point2 == null) { // return null; // } // return new Vector3d((point2.x - point1.x), (point2.y - point1.y), (point2.z - point1.z)); // } /** * Moves all vertices and feature points of a face by given vector value Loading @@ -168,12 +166,12 @@ public class ProcrustesAnalysis { * @param vector vector its values are used to move a face */ private void moveFaceModel(ProcrustesAnalysisFaceModel faceModel, Vector3d vector) { for (FeaturePoint fp : faceModel.getFeaturePointsMap().values()) { faceModel.getFeaturePointsMap().values().forEach(fp -> { movePoint(fp, vector); } for (MeshPoint v : faceModel.getVertices()) { }); faceModel.getVertices().forEach(v -> { movePoint(v, vector); } }); } /** Loading @@ -187,16 +185,16 @@ public class ProcrustesAnalysis { * @param featurePointVector feature points adjustment */ private void moveFaceModel(ProcrustesAnalysisFaceModel faceModel, Vector3d vertexVector, Vector3d featurePointVector) { for (FeaturePoint fp : faceModel.getFeaturePointsMap().values()) { faceModel.getFeaturePointsMap().values().forEach(fp -> { movePoint(fp, featurePointVector); } for (MeshPoint v : faceModel.getVertices()) { }); faceModel.getVertices().forEach(v -> { movePoint(v, vertexVector); } }); } /** * Moves point by given vector value * Moves point by given vector value. * * @param <T> * @param point Loading @@ -209,7 +207,7 @@ public class ProcrustesAnalysis { } /** * By rotation of matrices solves orthogonal procrustes problem * By rotation of matrices solves orthogonal procrustes problem. */ private SimpleMatrix rotate() { SimpleMatrix primaryMatrix = createMatrixFromList(this.faceModel2.getFeaturePointValues()); Loading Loading @@ -276,10 +274,10 @@ public class ProcrustesAnalysis { * @param faceModel * @param scaleFactor */ private void scaleFace(ProcrustesAnalysisFaceModel faceModel, double scaleFactor) { calculateScaledList(faceModel.getVertices(), scaleFactor); calculateScaledList(faceModel.getFeaturePointValues(), scaleFactor); } // private void scaleFace(ProcrustesAnalysisFaceModel faceModel, double scaleFactor) { // calculateScaledList(faceModel.getVertices(), scaleFactor); // calculateScaledList(faceModel.getFeaturePointValues(), scaleFactor); // } /** * Scales each given point from list by multiplying its position coordinates Loading @@ -306,13 +304,13 @@ public class ProcrustesAnalysis { */ // if rotated vertices are drawn immediately it is better to set them after rotating them all // so it would be drawn just once private void rotateVertices(List<MeshPoint> vertices, SimpleMatrix matrix) { if (vertices != null) { for (int i = 0; i < vertices.size(); i++) { rotateVertex(vertices.get(i), matrix); } } } // private void rotateVertices(List<MeshPoint> vertices, SimpleMatrix matrix) { // if (vertices != null) { // for (int i = 0; i < vertices.size(); i++) { // rotateVertex(vertices.get(i), matrix); // } // } // } /** * Rotates vertex v by simulating matrix multiplication with given matrix Loading @@ -320,20 +318,20 @@ public class ProcrustesAnalysis { * @param v * @param matrix */ private static void rotateVertex(MeshPoint v, SimpleMatrix matrix) { double x = ((v.getX() * matrix.get(0, 0)) + (v.getY() * matrix.get(1, 0)) + (v.getZ() * matrix.get(2, 0))); double y = ((v.getX() * matrix.get(0, 1)) + (v.getY() * matrix.get(1, 1)) + (v.getZ() * matrix.get(2, 1))); double z = ((v.getX() * matrix.get(0, 2)) + (v.getY() * matrix.get(1, 2)) + (v.getZ() * matrix.get(2, 2))); v.getPosition().x = x; v.getPosition().y = y; v.getPosition().z = z; } // private static void rotateVertex(MeshPoint v, SimpleMatrix matrix) { // double x = ((v.getX() * matrix.get(0, 0)) // + (v.getY() * matrix.get(1, 0)) // + (v.getZ() * matrix.get(2, 0))); // double y = ((v.getX() * matrix.get(0, 1)) // + (v.getY() * matrix.get(1, 1)) // + (v.getZ() * matrix.get(2, 1))); // double z = ((v.getX() * matrix.get(0, 2)) // + (v.getY() * matrix.get(1, 2)) // + (v.getZ() * matrix.get(2, 2))); // v.getPosition().x = x; // v.getPosition().y = y; // v.getPosition().z = z; // } /** * Scales position of given point by multiplying its coordinates with given Loading
Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesAnalysisFaceModel.java +95 −31 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ public class ProcrustesAnalysisFaceModel { private final HumanFace humanFace; private HashMap<Integer, FeaturePoint> featurePointsMap; // sorted by feature point type private List<MeshPoint> vertices; private MeshModel meshModel; private final MeshModel meshModel; private final HashMap<Integer, Integer> featurePointTypeCorrespondence; /** Loading Loading @@ -57,7 +57,7 @@ public class ProcrustesAnalysisFaceModel { List<FeaturePoint> modifiableFeaturePointList = getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints); // Currently set feature points is not working as inteded because gui doesn't repaint them after changing values face.setFeaturePoints(modifiableFeaturePointList); // face.setFeaturePoints(modifiableFeaturePointList); // To be able to move vertices we have to make a copy of them because getFacets() returns unmodifiable List List<MeshPoint> modifiableVertices = new ArrayList<>(face.getMeshModel().getFacets().get(0).getVertices()); Loading @@ -70,15 +70,43 @@ public class ProcrustesAnalysisFaceModel { } /** * sets feature points map and also sets feature point on human face for * visualisation * Use this constructor instead of the * {@link #ProcrustesAnalysisFaceModel(cz.fidentis.analyst.face.HumanFace, java.util.List)} * until the * {@link cz.fidentis.analyst.face.HumanFace#setFeaturePoints(java.util.List)} * is fixed and fires event to render in GUI a new set of feature points. * * Feature points that are not used in subset are moved to position of * modelCentroid. * * @param humanFace1 * @param viablePoints * @param modelCentroid1 */ // ProcrustesAnalysisFaceModel(HumanFace face, ArrayList<Integer> viablePoints, Point3d modelCentroid) { // this.humanFace = face; // // getFeaturePoints() returns unmodifiable List. To sort it we need to make copy first // List<FeaturePoint> modifiableFeaturePointList = getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints); // // // To be able to move vertices we have to make a copy of them because getFacets() returns unmodifiable List // List<MeshPoint> modifiableVertices = new ArrayList<>(face.getMeshModel().getFacets().get(0).getVertices()); // // this.vertices = modifiableVertices; // this.meshModel = face.getMeshModel(); // this.featurePointsMap = createFeaturePointMap( // sortListByFeaturePointType(modifiableFeaturePointList)); // this.featurePointTypeCorrespondence = createFeaturePointTypeCorrespondence(face.getFeaturePoints()); // } /** * Sets feature points map and also sets feature point on human face for * visualisation. * * @param featurePointsMap */ public void setFeaturePointsMap(HashMap<Integer, FeaturePoint> featurePointsMap) { this.featurePointsMap = featurePointsMap; readjustFeaturePoints(featurePointsMap); // this.humanFace.setFeaturePoints(getFeaturePointValues()); } Loading Loading @@ -106,6 +134,15 @@ public class ProcrustesAnalysisFaceModel { return featurePointTypeCorrespondence; } /** * Creates a subset of selected feature points that can be used for * procrustes analysis. Each of the feature point types contained in the * subset is contained in both faces. * * @param featurePoints * @param viablePoints * @return */ private List<FeaturePoint> getSelectionOfFeaturePoints(List<FeaturePoint> featurePoints, List<Integer> viablePoints) { ArrayList<FeaturePoint> selection = new ArrayList<>(); featurePoints.forEach(fp -> { Loading @@ -116,6 +153,30 @@ public class ProcrustesAnalysisFaceModel { return selection; } /** * {@link #getSelectionOfFeaturePoints(java.util.List, java.util.List)} * Feature points that are not in subset are moved to position of * modelCentroid. * * @param featurePoints * @param viablePoints * @param modelCentroid * @return */ // private List<FeaturePoint> getSelectionOfFeaturePoints(List<FeaturePoint> featurePoints, ArrayList<Integer> viablePoints, Point3d modelCentroid) { // ArrayList<FeaturePoint> selection = new ArrayList<>(); // featurePoints.forEach(fp -> { // if (viablePoints.contains(fp.getFeaturePointType().getType())) { // selection.add(fp); // } else { // fp.getPosition().x = modelCentroid.x; // fp.getPosition().y = modelCentroid.y; // fp.getPosition().z = modelCentroid.z; // } // }); // return selection; // } /** * Creates corresponding key value pair of matrix row index and a feature * point type value. It is used so we can get back type of feature point Loading Loading @@ -163,28 +224,9 @@ public class ProcrustesAnalysisFaceModel { } private void readjustFeaturePoints(HashMap<Integer, FeaturePoint> featurePointsMap) { if (featurePointsMap.size() != this.humanFace.getFeaturePoints().size()) { readjustSelection(featurePointsMap); } else { this.humanFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); if (fp.getFeaturePointType().getType() != movedFp.getFeaturePointType().getType()) { throw new RuntimeException("Types do not correspond"); } fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); }); } } /** * Moves subset of feature points to their new position. If point doesn't belong to subset it is moved to (0,0,0) instead. * * @param featurePointsMap */ private void readjustSelection(HashMap<Integer, FeaturePoint> featurePointsMap) { // if (featurePointsMap.size() != this.humanFace.getFeaturePoints().size()) { // readjustSelection(featurePointsMap); // } else { this.humanFace.getFeaturePoints().forEach(fp -> { FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); if (movedFp != null) { Loading @@ -195,12 +237,34 @@ public class ProcrustesAnalysisFaceModel { fp.getPosition().x = movedFp.getX(); fp.getPosition().y = movedFp.getY(); fp.getPosition().z = movedFp.getZ(); } else { fp.getPosition().x = 0; fp.getPosition().y = 0; fp.getPosition().z = 0; } }); // } } // /** // * Moves subset of feature points to their new position. If point doesn't // * belong to subset it is moved to (0,0,0) instead. // * // * @param featurePointsMap // */ // private void readjustSelection(HashMap<Integer, FeaturePoint> featurePointsMap) { // this.humanFace.getFeaturePoints().forEach(fp -> { // FeaturePoint movedFp = featurePointsMap.get(fp.getFeaturePointType().getType()); // if (movedFp != null) { // if (fp.getFeaturePointType().getType() // != movedFp.getFeaturePointType().getType()) { // throw new RuntimeException("Types do not correspond"); // } // fp.getPosition().x = movedFp.getX(); // fp.getPosition().y = movedFp.getY(); // fp.getPosition().z = movedFp.getZ(); // } else { // fp.getPosition().x = 0; // fp.getPosition().y = 0; // fp.getPosition().z = 0; // } // }); // } }
Comparison/src/main/java/cz/fidentis/analyst/procrustes/ProcrustesTransformation.java +1 −6 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package cz.fidentis.analyst.procrustes; import cz.fidentis.analyst.icp.Quaternion; Loading @@ -11,7 +6,7 @@ import org.ejml.simple.SimpleMatrix; /** * Class used to store information about transformation that needs to be applied * to a second face when computing procrustes analysis * to a second face when computing procrustes analysis. * * @author Jakub Kolman */ Loading
Comparison/src/main/java/cz/fidentis/analyst/visitors/procrustes/ProcrustesVisitor.java +0 −5 Original line number Diff line number Diff line /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package cz.fidentis.analyst.visitors.procrustes; import cz.fidentis.analyst.face.HumanFace; Loading