/* * 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.face.HumanFace; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.core.MeshPoint; import cz.fidentis.analyst.procrustes.utils.ProcrustesAnalysisUtils; import org.ejml.simple.SimpleMatrix; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Holds important face attributes that are required for procrustes analysis. * * @author Jakub Kolman */ public class ProcrustesAnalysisFaceModel { private final HumanFace humanFace; private HashMap<Integer, FeaturePoint> featurePointsMap; // sorted by feature point type private List<MeshPoint> vertices; private SimpleMatrix verticesMatrix; private MeshModel meshModel; private final HashMap<Integer, Integer> featurePointTypeCorrespondence; 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()); // 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( ProcrustesAnalysisUtils.sortListByFeaturePointType(modifiableFeaturePointList)); this.featurePointTypeCorrespondence = createFeaturePointTypeCorrespondence(face.getFeaturePoints()); this.verticesMatrix = ProcrustesAnalysisUtils.createMatrixFromList(modifiableVertices); // this.featurePointMatrix = ProcrustesAnalysisUtils.createMatrixFromList(modifiableFeaturePointList); } /** * 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; this.humanFace.setFeaturePoints(getFeaturePointValues()); } public MeshModel getMeshModel() { return meshModel; } public List<FeaturePoint> getFeaturePointValues() { return new ArrayList<>(this.getFeaturePointsMap().values()); } public List<MeshPoint> getVertices() { return vertices; } public HashMap<Integer, FeaturePoint> getFeaturePointsMap() { return featurePointsMap; } /** * sets vertices map and also sets feature point on human face for visualisation * * @param verticesMatrix */ public void setVerticesMatrix(SimpleMatrix verticesMatrix) { this.verticesMatrix = verticesMatrix; changeVerticesValues(verticesMatrix); } public SimpleMatrix getVerticesMatrix() { return verticesMatrix; } private void changeVerticesValues(SimpleMatrix matrix) { for (int i = 0; i < vertices.size(); i++) { vertices.get(i).getPosition().x = (float) matrix.get(i, 0); vertices.get(i).getPosition().y = (float) matrix.get(i, 1); vertices.get(i).getPosition().z = (float) matrix.get(i, 2); } } private HashMap<Integer, FeaturePoint> createFeaturePointMap(List<FeaturePoint> featurePointList) { HashMap<Integer, FeaturePoint> map = new HashMap<>(); for (FeaturePoint fp: featurePointList) { map.put(fp.getFeaturePointType().getType(), fp); } return map; } public HashMap<Integer, Integer> getFeaturePointTypeCorrespondence() { return featurePointTypeCorrespondence; } /** * Creates corresponding key value pair of matrix row index and a feature point type value. * It is used in {@link cz.fidentis.analyst.procrustes.utils.ProcrustesAnalysisUtils#createFeaturePointMapFromMatrix} * so we can get back type of feature point after working with matrices where the type is not stored, * but instead are used matrix indexes. * * @param fpList * @return */ private HashMap<Integer, Integer> createFeaturePointTypeCorrespondence(List<FeaturePoint> fpList) { HashMap<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < fpList.size(); i++) { map.put(i, fpList.get(i).getFeaturePointType().getType()); } return map; } }