Skip to content
Snippets Groups Projects
IcpDownsampling.java 8.59 KiB
Newer Older
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";
        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();
                case "uniform mesh":
                    secSampling = new UniformSurfaceSampling();
                    priSampling = new UniformSurfaceSampling();
            /*
            if (samples[i] == 0) {
                secSampling = new NoSampling();
                priSampling = new NoSampling();
            } else {
                secSampling.setRequiredSamples(i);
                priSampling.setRequiredSamples(i);
            }
            */
            
                priSampling = new NoSampling();
                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());
    
    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;
    }