From d8de4848ada21a34143fd36eb853d75dc59701e1 Mon Sep 17 00:00:00 2001 From: Daniel Schramm <xschramm@fi.muni.cz> Date: Tue, 31 Aug 2021 23:29:47 +0200 Subject: [PATCH] Feature point weights implemented correctly --- .../face/HausdorffDistancePrioritized.java | 50 ++++++---- .../HausdorffDistancePrioritizedTest.java | 93 ++++++++++++------- 2 files changed, 92 insertions(+), 51 deletions(-) diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java index 0d92bdce..83ed7f1c 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritized.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.IntStream; import javax.vecmath.Point3d; /** @@ -28,7 +29,7 @@ import javax.vecmath.Point3d; * points separately</li> * <li>Priorities of the faces' vertices with respect to all the given types * of feature points merged together</li> - * <li>Weighted Hausdorff distance with respect to the given types of feature + * <li>Average weighted Hausdorff distance with respect to the given types of feature * points for each of the faces' mesh facets</li> * </ul> * This visitor is instantiated with a single k-d tree (either given as the input @@ -220,21 +221,24 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { } /** - * For all visited faces' mesh facets, the method returns the weighted Hausdorff distance - * (total sum of weighted distances of all mesh facet's vertices to the source facets). - * The weighted distances are calculated with respect to the given types of - * feature points - for each feature point type separately. + * For all visited faces' mesh facets, the method returns the average weighted Hausdorff distance + * with respect to the given types of feature points (i.e. the sum of weighted distances + * of the mesh facet's vertices to the source facets divided by the number of vertices + * located within the feature point's priority sphere). + * The average weighted distances are calculated for each type of feature point separately. * * Keys in the map contain human faces whose mesh facets were measured with the * source facets. * For each human face, there is a map of examined types of feature points. * Each feature point type then stores a map of the face's mesh facets together with - * the total sums of weighted distances of all their vertices to the source facets. - * The weighted distances are calculated with respect to the face's feature point + * the average weighted distances of their vertices to the source facets. + * The average weighted distances are calculated with respect to the face's feature point * of the corresponding type. + * <i>If there is no vertex within the priority sphere of a feature point, + * the value of the average weighted Hausdorff distance is {@link Double#NaN}</i> * - * @return Weighted Hausdorff distances with respect to the given types - * of feature points for each of the visited faces' mesh facets + * @return Average weighted Hausdorff distances with respect to the given types + * of feature points */ public Map<HumanFace, Map<FeaturePointType, Map<MeshFacet, Double>>> getFeaturePointWeights() { return Collections.unmodifiableMap(featurePointWeights); @@ -302,6 +306,8 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { // Compute the Hasudorff distance using the 'distanceVisitor' humanFace.getMeshModel().compute(distanceVisitor, inParallel()); + final Map<MeshFacet, List<Double>> hausdorffDistances = distanceVisitor.getDistances(); + // Compute priorities of humanFace's vertices for each of the given feature point types for (final FeaturePointType fpType: featurePointTypes) { final FeaturePoint featurePoint = humanFace.getFeaturePoints().get(fpType.getType()); // Get feature point of desired type @@ -313,24 +319,28 @@ public class HausdorffDistancePrioritized extends HumanFaceVisitor { priorities.computeIfAbsent(humanFace, face -> new HashMap<>()) .computeIfAbsent(fpType, featurePointType -> new HashMap<>()) .putAll(priorityVisitor.getPriorities()); - - // TODO implement featurePointWeights correctly!! - // DO NOT measure distance to feature point - // DO measure distance to source facets - featurePointWeights.computeIfAbsent(humanFace, face -> new HashMap<>()) - .computeIfAbsent(fpType, featurePointType -> new HashMap<>()) - .putAll(priorityVisitor.getWeightedDistances()); } - /* - * Merge priorities computed for the current feature point type with - * the priorities of already computed feature point types. - */ for (final Map.Entry<MeshFacet, List<Double>> entry: priorityVisitor.getPriorities().entrySet()) { final MeshFacet facet = entry.getKey(); final List<Double> facetPriorities = entry.getValue(); synchronized (this) { + /* + * Calculate the average weighted Hausdorff distance for the feature point. + */ + final List<Double> facetDistances = hausdorffDistances.get(facet); + featurePointWeights.computeIfAbsent(humanFace, face -> new HashMap<>()) + .computeIfAbsent(fpType, featurePointType -> new HashMap<>()) + .put(facet, IntStream.range(0, facetDistances.size()) + .filter(i -> facetPriorities.get(i) > 0) // Filter out vertices that are outside of the priority sphere + .mapToDouble(i -> facetDistances.get(i) * facetPriorities.get(i)) + .average() + .orElse(Double.NaN)); // If there is no vertex in the priority sphere + + /* + * Merge priorities computed for the current feature point type with the priorities of already computed feature point types. + */ final List<Double> storedFacetPriorities = mergedPriorities .computeIfAbsent(humanFace, face -> new HashMap<>()) .get(facet); diff --git a/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java b/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java index f7062990..a7315155 100644 --- a/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java +++ b/Comparison/src/test/java/cz/fidentis/analyst/visitors/face/HausdorffDistancePrioritizedTest.java @@ -18,6 +18,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -26,7 +27,7 @@ import org.junit.jupiter.api.Test; public class HausdorffDistancePrioritizedTest { - private static final double DELTA = 1e-11; + private static final double DELTA = 1e-15; private final File boy = new File("src/test/resources/cz/fidentis/analyst/average_boy_17-20.obj"); @@ -40,8 +41,11 @@ public class HausdorffDistancePrioritizedTest { private final MeshFacet facet6 = getTrivialFacet(VERTICES_NUM, 0, 0, -0.1, 0); private final List<MeshFacet> facets = List.of(facet1, facet2, facet3, facet4, facet5, facet6); + private final List<MeshFacet> facets2 = List.of(getTrivialFacet(1, 0, 0, 0, 0)); + private final List<Double> prioritiesListFP1 = List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0d, 0d); private final double weightedDistanceFP1 = 0 + 0.09 + 0.16 + 0.21 + 0.24 + 0.25 + 0.24 + 0.21 + 0.16 + 0.09 + 0 + 0; + private final double averageWeightedDistanceFP1 = weightedDistanceFP1 / 10; // There are 10 vertices inside the priority sphere private final Point3d featurePoint1 = new Point3d(0, 0, 0); private final FeaturePointType fpType1 = new FeaturePointType(0, null, null, null); @@ -51,13 +55,16 @@ public class HausdorffDistancePrioritizedTest { facet4, prioritiesListFP1, facet5, prioritiesListFP1, facet6, prioritiesListFP1); - private final Map<MeshFacet, Double> expectedWeightedDistancesMapFP1 = Map.of(facet1, weightedDistanceFP1, - facet2, weightedDistanceFP1, - facet3, weightedDistanceFP1, - facet4, weightedDistanceFP1, - facet5, weightedDistanceFP1, - facet6, weightedDistanceFP1); - + private final Map<MeshFacet, Double> expectedWeightedDistancesMapFP1 = Map.of(facet1, averageWeightedDistanceFP1, + facet2, averageWeightedDistanceFP1, + facet3, averageWeightedDistanceFP1, + facet4, averageWeightedDistanceFP1, + facet5, -averageWeightedDistanceFP1, + facet6, averageWeightedDistanceFP1); + private final Map<MeshFacet, Double> expectedAbsoluteWeightedDistancesMapFP1 = expectedWeightedDistancesMapFP1 + .entrySet() + .stream() + .collect(Collectors.toMap(entry -> entry.getKey(), entry -> Math.abs(entry.getValue()))); private MeshFacet getTrivialFacet(int count, double xSpace, double ySpace, double zSpace, int offset) { final MeshFacet facet = new MeshFacetImpl(); @@ -207,7 +214,11 @@ public class HausdorffDistancePrioritizedTest { expectedMergedPrioritiesMap.put(facet, prioritiesListFP1); } - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, true, false); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + true, + false); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } @@ -229,9 +240,9 @@ public class HausdorffDistancePrioritizedTest { final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>(); for (final MeshFacet facet: facets) { - expectedWeightedDistancesMapFP2.put(facet, 0d); + expectedWeightedDistancesMapFP2.put(facet, Double.NaN); } - final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1, + final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedAbsoluteWeightedDistancesMapFP1, fpType2, expectedWeightedDistancesMapFP2); final Map<MeshFacet, List<Double>> expectedMergedPrioritiesMap = new HashMap<>(); @@ -239,7 +250,11 @@ public class HausdorffDistancePrioritizedTest { expectedMergedPrioritiesMap.put(facet, prioritiesListFP1); } - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, false, false); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + false, + false); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } @@ -262,9 +277,9 @@ public class HausdorffDistancePrioritizedTest { final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>(); for (final MeshFacet facet: facets) { - expectedWeightedDistancesMapFP2.put(facet, 0d); + expectedWeightedDistancesMapFP2.put(facet, Double.NaN); } - expectedWeightedDistancesMapFP2.put(facet1, 0 + 0.09 + 0.16 + 0.21 + 0.24 + 0.25 + 0.24 + 0.21 + 0.16 + 0.09 + 0 + 0.09); + expectedWeightedDistancesMapFP2.put(facet1, (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11); final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1, fpType2, expectedWeightedDistancesMapFP2); @@ -274,7 +289,11 @@ public class HausdorffDistancePrioritizedTest { } expectedMergedPrioritiesMap.put(facet1, List.of(1d, 0.9, 0.8, 0.7, 0.6, 0.5, 0.6, 0.7, 0.8, 0.9, 1d, 0.9)); - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, true, false); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + true, + false); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } @@ -311,14 +330,14 @@ public class HausdorffDistancePrioritizedTest { final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>(); final Map<MeshFacet, Double> expectedWeightedDistancesMapFP4 = new HashMap<>(); for (final MeshFacet facet: facets) { - expectedWeightedDistancesMapFP2.put(facet, 0d); - expectedWeightedDistancesMapFP3.put(facet, 0d); - expectedWeightedDistancesMapFP4.put(facet, 0d); + expectedWeightedDistancesMapFP2.put(facet, Double.NaN); + expectedWeightedDistancesMapFP3.put(facet, Double.NaN); + expectedWeightedDistancesMapFP4.put(facet, Double.NaN); } - final double weightedDistance = 0 + 0.09 + 0.16 + 0.21 + 0.24 + 0.25 + 0.24 + 0.21 + 0.16 + 0.09 + 0 + 0.09; + final double weightedDistance = (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11; expectedWeightedDistancesMapFP2.put(facet1, weightedDistance); expectedWeightedDistancesMapFP3.put(facet3, weightedDistance); - expectedWeightedDistancesMapFP4.put(facet5, weightedDistance); + expectedWeightedDistancesMapFP4.put(facet5, -weightedDistance); final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1, fpType2, expectedWeightedDistancesMapFP2, fpType3, expectedWeightedDistancesMapFP3, @@ -333,7 +352,11 @@ public class HausdorffDistancePrioritizedTest { expectedMergedPrioritiesMap.put(facet3, mergedPriorities); expectedMergedPrioritiesMap.put(facet5, mergedPriorities); - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, false, false); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + true, + false); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } @@ -370,10 +393,10 @@ public class HausdorffDistancePrioritizedTest { final Map<MeshFacet, Double> expectedWeightedDistancesMapFP2 = new HashMap<>(); final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>(); for (final MeshFacet facet: facets) { - expectedWeightedDistancesMapFP2.put(facet, 0d); - expectedWeightedDistancesMapFP3.put(facet, 0d); + expectedWeightedDistancesMapFP2.put(facet, Double.NaN); + expectedWeightedDistancesMapFP3.put(facet, Double.NaN); } - final double weightedDistance = 0d + 0d + 0d + 0d + 0d + 0d + 0d + 0d + 0d + 0d + vertexDistance * vertexPriority + 0d; + final double weightedDistance = 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 * vertexPriority + 0; expectedWeightedDistancesMapFP2.put(facet1, weightedDistance); expectedWeightedDistancesMapFP2.put(facet3, weightedDistance); expectedWeightedDistancesMapFP3.put(facet1, weightedDistance); @@ -391,7 +414,11 @@ public class HausdorffDistancePrioritizedTest { expectedMergedPrioritiesMap.put(facet3, mergedPriorities); expectedMergedPrioritiesMap.put(facet4, mergedPriorities); - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, true, false); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + true, + false); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } @@ -428,14 +455,14 @@ public class HausdorffDistancePrioritizedTest { final Map<MeshFacet, Double> expectedWeightedDistancesMapFP3 = new HashMap<>(); final Map<MeshFacet, Double> expectedWeightedDistancesMapFP4 = new HashMap<>(); for (final MeshFacet facet: facets) { - expectedWeightedDistancesMapFP2.put(facet, 0d); - expectedWeightedDistancesMapFP3.put(facet, 0d); - expectedWeightedDistancesMapFP4.put(facet, 0d); + expectedWeightedDistancesMapFP2.put(facet, Double.NaN); + expectedWeightedDistancesMapFP3.put(facet, Double.NaN); + expectedWeightedDistancesMapFP4.put(facet, Double.NaN); } - final double weightedDistance = 0 + 0.09 + 0.16 + 0.21 + 0.24 + 0.25 + 0.24 + 0.21 + 0.16 + 0.09 + 0 + 0.09; + final double weightedDistance = (0 + 0.01 + 0.04 + 0.09 + 0.16 + 0.25 + 0.36 + 0.49 + 0.64 + 0.81 + 1 + 0.99) / 11; expectedWeightedDistancesMapFP2.put(facet1, weightedDistance); expectedWeightedDistancesMapFP3.put(facet3, weightedDistance); - expectedWeightedDistancesMapFP4.put(facet5, weightedDistance); + expectedWeightedDistancesMapFP4.put(facet5, -weightedDistance); final Map<FeaturePointType, Map<MeshFacet, Double>> expectedFeaturePointsWeights = Map.of(fpType1, expectedWeightedDistancesMapFP1, fpType2, expectedWeightedDistancesMapFP2, fpType3, expectedWeightedDistancesMapFP3, @@ -450,7 +477,11 @@ public class HausdorffDistancePrioritizedTest { expectedMergedPrioritiesMap.put(facet3, mergedPriorities); expectedMergedPrioritiesMap.put(facet5, mergedPriorities); - final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(face, new HashSet<>(featurePointTypes), POINT_TO_POINT, false, true); + final HausdorffDistancePrioritized visitor = new HausdorffDistancePrioritized(getHumanFace(facets2, List.of(), List.of()), + new HashSet<>(featurePointTypes), + POINT_TO_POINT, + true, + true); performTest(face, expectedPriorities, expectedFeaturePointsWeights, expectedMergedPrioritiesMap, visitor); } -- GitLab