Commit 6f18f763 authored by Jakub Kolman's avatar Jakub Kolman
Browse files

[#123] feat: rework of procrustes face model class and simplyfication of analysis

parent e33246e2
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -255,10 +255,10 @@ public class HumanFaceUtils {

        // transform symmetry plane:
        if (secondFace.hasSymmetryPlane()) {
            Vector3d adjustment = pv.getTransformation().getCentroidAdjustment();
            double transformationScaleValue = pv.getTransformation().getScale();
            Quaternion rotation = pv.getTransformation().getMatrixAsQuaternion(
                    pv.getTransformation().getRotationMatrix());
            Vector3d adjustment = pv.getTransformations().get(secondFace).getCentroidAdjustment();
            double transformationScaleValue = pv.getTransformations().get(secondFace).getScale();
            Quaternion rotation = pv.getTransformations().get(secondFace).getMatrixAsQuaternion(
                    pv.getTransformations().get(secondFace).getRotationMatrix());
            secondFace.getFeaturePoints().parallelStream().forEach(fp -> {
                secondFace.setSymmetryPlane(transformPlane(
                        secondFace.getSymmetryPlane(), rotation, adjustment, transformationScaleValue));
@@ -266,8 +266,9 @@ public class HumanFaceUtils {
            secondFace.getFeaturePoints().parallelStream().forEach(fp -> {
                secondFace.setSymmetryPlane(transformPlane(
                        secondFace.getSymmetryPlane(),
                        pv.getTransformation().getMatrixAsQuaternion(pv.getTransformation().getIdentityMatrix()),
                        pv.getTransformation().getSuperImpositionAdjustment(), 1));
                        pv.getTransformations().get(secondFace).getMatrixAsQuaternion(
                                pv.getTransformations().get(secondFace).getIdentityMatrix()),
                        pv.getTransformations().get(secondFace).getSuperImpositionAdjustment(), 1));
            });
        }
        return pv;
+8 −64
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ import org.ejml.simple.SimpleMatrix;
import org.ejml.simple.SimpleSVD;

import java.util.ArrayList;
import static java.util.Collections.list;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -113,19 +114,12 @@ public class ProcrustesAnalysis {
            // calculation of scaling vector
            if (scale) {
                double scaleFactor = this.calculateScalingValue();
                scaleFeaturePoints(faceModel2.getFeaturePointValues(), scaleFactor);
                transformation.setScale(scaleFactor);
                calculateScaledList(faceModel2.getFeaturePointValues(), scaleFactor);
            }
            // calculation of rotation matrix
            transformation.setRotationMatrix(this.rotate());

            // 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.modelCentroid1.x, this.modelCentroid1.y, this.modelCentroid1.z));

            transformation.setFeaturePointsMap(faceModel2.getFeaturePointsMap());

        } else {
            throw new DataFormatException("Faces have less than 3 feature points.");
        }
@@ -167,11 +161,6 @@ public class ProcrustesAnalysis {
        SimpleSVD<SimpleMatrix> singularValueDecomposition = svdMatrix.svd();
        SimpleMatrix transposedU = singularValueDecomposition.getU().transpose();
        SimpleMatrix rotationMatrix = singularValueDecomposition.getV().mult(transposedU);
        primaryMatrix = primaryMatrix.mult(rotationMatrix);

        this.faceModel2.setFeaturePointsMap(
                createFeaturePointMapFromMatrix(
                        primaryMatrix, this.faceModel2));

        return rotationMatrix;
    }
@@ -215,21 +204,6 @@ public class ProcrustesAnalysis {
        return ratioValue / distancesOfList1.length;
    }

    /**
     * Scales each given point from list by multiplying its position coordinates
     * with scaleFactor.
     *
     * @param list
     * @param scaleFactor
     * @param <T> either MeshPoint or FeaturePoint type.
     */
    private <T extends IPosition> void calculateScaledList(List<T> list, double scaleFactor) {
        List<T> scaledList = new ArrayList<>();
        for (T point : list) {
            scaledList.add(ProcrustesUtils.scalePointDistance(point, scaleFactor));
        }
    }

    /**
     * Finds centroid from given feature point List
     *
@@ -248,31 +222,6 @@ public class ProcrustesAnalysis {
        return new Point3d(x / featurePointList.size(), y / featurePointList.size(), z / featurePointList.size());
    }

    /**
     * Creates feature point map HashMap with key FeaturePoint.type and value
     * FeaturePoint back from matrix.
     *
     * @param matrix
     * @param model
     * @return
     */
    private HashMap<Integer, FeaturePoint> createFeaturePointMapFromMatrix(
            SimpleMatrix matrix, ProcrustesAnalysisFaceModel model) {
        HashMap<Integer, FeaturePoint> map = new HashMap<>();
        for (int i = 0; i < matrix.numRows(); i++) {
            FeaturePoint featurePoint = new FeaturePoint(
                    matrix.get(i, 0),
                    matrix.get(i, 1),
                    matrix.get(i, 2),
                    model.getFeaturePointsMap().get(
                            model.getFeaturePointTypeCorrespondence().get(i)
                    ).getFeaturePointType()
            );
            map.put(model.getFeaturePointTypeCorrespondence().get(i), featurePoint);
        }
        return map;
    }

    /**
     * Creates matrix from given feature point list
     *
@@ -312,17 +261,6 @@ public class ProcrustesAnalysis {
        moveFaceModel(this.faceModel1, new Vector3d(-this.modelCentroid1.x, -this.modelCentroid1.y, -this.modelCentroid1.z));
    }

    private HashMap<Integer, FeaturePoint> moveFeaturePoints(ProcrustesAnalysisFaceModel faceModel2, Vector3d pointDistance) {
        HashMap<Integer, FeaturePoint> map = new HashMap<>();
        for (Map.Entry<Integer, FeaturePoint> entry : faceModel2.getFeaturePointsMap().entrySet()) {
            entry.getValue().getPosition().x += pointDistance.x;
            entry.getValue().getPosition().y += pointDistance.y;
            entry.getValue().getPosition().z += pointDistance.z;
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }

    /**
     * Finds corresponding subset of feature points from both faces so the
     * procrustes analysis can be applied on the subset.
@@ -348,4 +286,10 @@ public class ProcrustesAnalysis {
        return vaiablePoints;
    }

    private void scaleFeaturePoints(List<FeaturePoint> list, double scaleFactor) {
        for (FeaturePoint point : list) {
            ProcrustesUtils.scalePointDistance(point, scaleFactor);
        }
    }

}
+7 −29
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@ import java.util.List;
 */
public class ProcrustesAnalysisFaceModel {

//    private final HumanFace humanFace;
    private HashMap<Integer, FeaturePoint> featurePointsMap;        // sorted by feature point type
    private final HashMap<Integer, Integer> featurePointTypeCorrespondence;

@@ -24,10 +23,7 @@ public class ProcrustesAnalysisFaceModel {
     * @param face
     */
    public ProcrustesAnalysisFaceModel(HumanFace face) {
//        this.humanFace = face;
        // getFeaturePoints() returns unmodifiable List. To sort it we need to make copy first
        List<FeaturePoint> modifiableFeaturePointList = new ArrayList<>(face.getFeaturePoints());

        this.featurePointsMap = createFeaturePointMap(
                ProcrustesUtils.sortListByFeaturePointType(modifiableFeaturePointList));
        this.featurePointTypeCorrespondence = createFeaturePointTypeCorrespondence(face.getFeaturePoints());
@@ -41,9 +37,8 @@ public class ProcrustesAnalysisFaceModel {
     * @param viablePoints
     */
    public ProcrustesAnalysisFaceModel(HumanFace face, List<Integer> viablePoints) {
//        this.humanFace = face;
        // getFeaturePoints() returns unmodifiable List. To sort it we need to make copy first
        List<FeaturePoint> modifiableFeaturePointList = getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints);
        List<FeaturePoint> modifiableFeaturePointList = new ArrayList<>(
                getSelectionOfFeaturePoints(face.getFeaturePoints(), viablePoints));

        this.featurePointsMap = createFeaturePointMap(
                ProcrustesUtils.sortListByFeaturePointType(modifiableFeaturePointList));
@@ -59,8 +54,6 @@ public class ProcrustesAnalysisFaceModel {
     */
    public void setFeaturePointsMap(HashMap<Integer, FeaturePoint> featurePointsMap) {
        this.featurePointsMap = featurePointsMap;
//        readjustFeaturePoints(featurePointsMap);
//        this.humanFace.setFeaturePoints(getFeaturePointValues());
    }

    public List<FeaturePoint> getFeaturePointValues() {
@@ -122,28 +115,13 @@ public class ProcrustesAnalysisFaceModel {
    private HashMap<Integer, FeaturePoint> createFeaturePointMap(List<FeaturePoint> featurePointList) {
        HashMap<Integer, FeaturePoint> map = new HashMap<>();
        for (FeaturePoint fp : featurePointList) {
            map.put(fp.getFeaturePointType().getType(), fp);
            map.put(fp.getFeaturePointType().getType(), new FeaturePoint(
                    fp.getX(), 
                    fp.getY(), 
                    fp.getZ(), 
                    fp.getFeaturePointType()));
        }
        return map;
    }

//    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 (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();
//            }
//        });
////    }
//    }

}
+0 −8
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ public class ProcrustesTransformation {
    // used to move face to superimposed poisition over the original human face 
    private Vector3d superImpositionAdjustment;
    private SimpleMatrix rotationMatrix;
    private HashMap<Integer, FeaturePoint> featurePointsMap;

//    /**
//     * constructor
@@ -150,11 +149,4 @@ public class ProcrustesTransformation {
        return r;
   }

    void setFeaturePointsMap(HashMap<Integer, FeaturePoint> featurePointsMap) {
        this.featurePointsMap = featurePointsMap;
    }

    public Map<Integer, FeaturePoint> getFeaturePointsMap() {
        return Collections.unmodifiableMap(this.featurePointsMap);
    }
}
+14 −4
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package cz.fidentis.analyst.visitors.procrustes;

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.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshPoint;
import cz.fidentis.analyst.procrustes.ProcrustesTransformation;
@@ -45,8 +46,8 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
        this.scale = scale;
    }

    public ProcrustesTransformation getTransformation() {
        return this.transformation;
    public Map<HumanFace, ProcrustesTransformation> getTransformations() {
        return this.transformations;
    }

    @Override
@@ -75,7 +76,7 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
        scaleFace(humanFace, transformation.getScale());
        rotateFace(humanFace, transformation.getRotationMatrix());
        moveFace(humanFace, transformation.getSuperImpositionAdjustment());
        moveFeaturePoints(humanFace, transformation.getFeaturePointsMap());
//        moveFeaturePoints(humanFace, transformation.getFeaturePointsMap());
    }

    /**
@@ -91,6 +92,9 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
                ProcrustesUtils.movePoint(v, vector);
            });
        }
        for (FeaturePoint fp : humanFace.getFeaturePoints()) {
            ProcrustesUtils.movePoint(fp, vector);
        }
    }

    /**
@@ -106,6 +110,9 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
                ProcrustesUtils.scalePointDistance(v, scaleFactor);
            });
        }
        for (FeaturePoint fp : humanFace.getFeaturePoints()) {
            ProcrustesUtils.scalePointDistance(fp, scaleFactor);
        }
    }

    /**
@@ -122,6 +129,9 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
                rotateVertex(v, matrix);
            });
        }
        for (FeaturePoint fp : humanFace.getFeaturePoints()) {
            rotateVertex(fp, matrix);
        }
    }

    /**
@@ -130,7 +140,7 @@ public class ProcrustesVisitor extends HumanFaceVisitor {
     * @param v
     * @param matrix
     */
    private void rotateVertex(MeshPoint v, SimpleMatrix matrix) {
    private <T extends IPosition> void rotateVertex(T v, SimpleMatrix matrix) {
        double x = ((v.getX() * matrix.get(0, 0))
                + (v.getY() * matrix.get(1, 0))
                + (v.getZ() * matrix.get(2, 0)));
Loading