package cz.fidentis.analyst.tests; import cz.fidentis.analyst.batch.Stopwatch; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.face.HumanFaceUtils; import cz.fidentis.analyst.icp.UndersampledMeshFacet; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.sampling.CurvatureSampling; 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 cz.fidentis.analyst.visitors.mesh.sampling.UniformSpaceSampling; import cz.fidentis.analyst.visitors.mesh.sampling.UniformSurfaceSampling; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.Collectors; /** * This class evaluates efficiency (acceleration) and precision of ICP with different * point sampling algorithms and different downsampling strength. * * @author Radek Oslejsek */ public class IcpDownsampling { private static final String DATA_DIR = "../../analyst-data-antropologie/_ECA"; private static final int MAX_SAMPLES = 500; /** * Main method * @param args Input arguments * @throws IOException on IO error */ public static void main(String[] args) throws IOException, ClassNotFoundException, Exception { List<Path> faces = Files.list(new File(DATA_DIR).toPath()) .filter(f -> f.toString().endsWith(".obj")) .sorted() .limit(MAX_SAMPLES) .collect(Collectors.toList()); SortedMap<Integer, Stopwatch> efficiency = new TreeMap<>(Collections.reverseOrder()); SortedMap<Integer, List<Double>> precision = new TreeMap<>(Collections.reverseOrder()); String alg = "random"; //String alg = "gaussian"; //String alg = "uniform space"; //String alg = "uniform mesh"; int counter = 1; for (int i = 0; i < faces.size(); i += 5) { for (int j = i; j < faces.size(); j += 5) { // starts with "i"! if (i != j) { // register only different faces System.out.println(); System.out.println("Iteration: " + counter); compareFaces(faces.get(i), faces.get(j), efficiency, precision, alg); printResults(efficiency, precision, counter, alg); counter++; } } } } protected static void printResults(SortedMap<Integer, Stopwatch> efficiency, SortedMap<Integer, List<Double>> precision, double counter, String sampling) { System.out.println(); System.out.println("Avg. Time (ms) - " + sampling + " sampling:"); efficiency.entrySet().forEach(e -> { System.out.println(e.getKey() + ";" + (e.getValue().getTotalTime() / counter)); }); System.out.println(); System.out.println("Avg. Precision - " + sampling + " sampling:"); System.out.println("# samples;dissimilarity;variance"); precision.entrySet().forEach(e -> { double avg = e.getValue().stream() .mapToDouble(val -> val) .summaryStatistics() .getAverage(); double variance = e.getValue().stream() .mapToDouble(val -> Math.pow(Math.abs(val - avg), 2)) .average() .orElse(-1); System.out.println(e.getKey() + ";" + avg + ";" + variance); }); } protected static void compareFaces( Path priFacePath, Path secFacePath, Map<Integer, Stopwatch> efficiency, Map<Integer, List<Double>> precision, String samp) throws IOException { //double[] percs = new double[]{0.5,1,2,4,6,8,10,15,20,30,40,50,60,70,80,85,90,92,94,96,98,100}; //double[] percs = new double[]{100,90,80,70,60,50,40,30,20,15,10,8,6,4,2,1,0.5}; //int[] samples = new int[]{0,200,500,1000,2000,3000,5000,10000,20000,30000,40000}; //int[] samples = new int[]{0,200,500,1000,2000,3000,5000}; //int[] samples = new int[]{50,100,150,300,400}; //int[] samples = new int[]{0,50,100,150,200,300,400,500,1000,2000,3000,5000,10000,20000,30000}; //int[] samples = new int[]{5,10,20,30,40,50}; int[] samples = new int[]{0,40,50,100,150,200,300,400,500,1000,2000,3000,5000,10000,20000,30000}; HumanFace priFace = new HumanFace(priFacePath.toFile()); priFace.computeKdTree(false); HumanFace secFaceFromFile = new HumanFace(secFacePath.toFile()); System.out.println(secFaceFromFile.getShortName()); for (int i: samples) { HumanFace secFace = new HumanFace(new MeshModel(secFaceFromFile.getMeshModel()), secFaceFromFile.getId()); PointSampling secSampling; PointSampling priSampling; switch (samp) { case "random": secSampling = new RandomSampling(); priSampling = new RandomSampling(); break; case "gaussian": secSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN); priSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN); break; case "uniform space": secSampling = new UniformSpaceSampling(); priSampling = new UniformSpaceSampling(); break; case "uniform mesh": secSampling = new UniformSurfaceSampling(); priSampling = new UniformSurfaceSampling(); break; default: return; } /* if (samples[i] == 0) { secSampling = new NoSampling(); priSampling = new NoSampling(); } else { secSampling.setRequiredSamples(i); priSampling.setRequiredSamples(i); } */ if (i == 0) { priSampling = new NoSampling(); } else { priSampling.setRequiredSamples(i); } secSampling.setRequiredSamples(5000); efficiency.computeIfAbsent(i, k-> new Stopwatch("")).start(); HumanFaceUtils.alignMeshes( downsamplePriFace(priFace, priSampling), secFace, // is transformed 100, // max iterations false,// scale 0.05, // error secSampling, false // drop k-d tree of the secFace, if exists ); /* HumanFaceUtils.alignMeshes( /// ORIG SETTING priFace, secFace, // is transformed 100, // max iterations false,// scale 0.05, // error secSampling, false // drop k-d tree of the secFace, if exists ); */ efficiency.get(i).stop(); System.out.println(" Primary face: " + priSampling); System.out.println("Secondary face: " + secSampling); HausdorffDistance hd = new HausdorffDistance( priFace.getKdTree(), HausdorffDistance.Strategy.POINT_TO_POINT, false, // relative distance true, // parallel true // crop ); secFace.getMeshModel().compute(hd); precision.computeIfAbsent(i, k -> new ArrayList<>()).add(hd.getStats().getAverage()); } System.out.println(); } private static HumanFace downsamplePriFace(HumanFace priFace, PointSampling sampling) { MeshFacet reducedFacet = new UndersampledMeshFacet(priFace.getMeshModel().getFacets().get(0), sampling); MeshModel model = new MeshModel(); model.setFacets(List.of(reducedFacet)); HumanFace ret = new HumanFace(model, priFace.getId()); return ret; } }