Skip to content
Snippets Groups Projects
Commit 5b791b26 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Resolve "Adaptive downsampling for ICP"

parent eacd7eef
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@ import cz.fidentis.analyst.mesh.core.MeshPoint;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
......@@ -81,6 +82,29 @@ public class IcpTransformer extends MeshVisitor {
private final PointSampling samplingStrategy;
/**
* Constructor for random sampling, which is the best performing downsampling strategy.
*
* @param mainFacet Primary mesh facet. Must not be {@code null}.
* Inspected facets are transformed toward this primary mesh.
* @param maxIteration Maximal number of ICP iterations (it includes computing
* new transformation and applying it). A number bigger than zero.
* Reasonable number seems to be 10.
* @param scale If {@code true}, then the scale factor is also computed.
* @param error Acceptable error - a number bigger than or equal to zero.
* Mean distance of vertices is computed for each ICP iteration.
* If the difference between the previous and current mean distances is less than the error,
* then the ICP computation stops. Reasonable number seems to be 0.05.
* @param numSamples Number of samples for downsampling. Use 1000 for best performance. Zero = no downsampling
* @throws IllegalArgumentException if some parameter is wrong
*/
public IcpTransformer(MeshFacet mainFacet, int maxIteration, boolean scale, double error, int numSamples) {
this(new HashSet<>(Collections.singleton(mainFacet)), maxIteration, scale, error, (numSamples == 0) ? new NoSampling() : new RandomSampling(numSamples));
if (mainFacet == null) {
throw new IllegalArgumentException("mainFacet");
}
}
/**
* Constructor.
*
......@@ -90,8 +114,10 @@ public class IcpTransformer extends MeshVisitor {
* new transformation and applying it). A number bigger than zero.
* Reasonable number seems to be 10.
* @param scale If {@code true}, then the scale factor is also computed.
* @param error Acceptable error. A number bigger than or equal to zero.
* When reached, then the ICP stops. Reasonable number seems to be 0.05.
* @param error Acceptable error - a number bigger than or equal to zero.
* Mean distance of vertices is computed for each ICP iteration.
* If the difference between the previous and current mean distances is less than the error,
* then the ICP computation stops. Reasonable number seems to be 0.05.
* @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
* @throws IllegalArgumentException if some parameter is wrong
*/
......@@ -111,8 +137,10 @@ public class IcpTransformer extends MeshVisitor {
* new transformation and applying it). A number bigger than zero.
* Reasonable number seems to be 10.
* @param scale If {@code true}, then the scale factor is also computed.
* @param error Acceptable error. A number bugger than or equal to zero.
* When reached, then the ICP stops. Reasonable number seems to be 0.05.
* @param error Acceptable error - a number bigger than or equal to zero.
* Mean distance of vertices is computed for each ICP iteration.
* If the difference between the previous and current mean distances is less than the error,
* then the ICP computation stops. Reasonable number seems to be 0.05.
* @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
* @throws IllegalArgumentException if some parameter is wrong
*/
......@@ -142,8 +170,10 @@ public class IcpTransformer extends MeshVisitor {
* new transformation and applying it). A number bigger than zero.
* Reasonable number seems to be 10.
* @param scale If {@code true}, then the scale factor is also computed.
* @param error Acceptable error. A number bugger than or equal to zero.
* When reached, then the ICP stops. Reasonable number seems to be 0.05.
* @param error Acceptable error - a number bigger than or equal to zero.
* Mean distance of vertices is computed for each ICP iteration.
* If the difference between the previous and current mean distances is less than the error,
* then the ICP computation stops. Reasonable number seems to be 0.05.
* @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
* @throws IllegalArgumentException if some parameter is wrong
*/
......@@ -163,7 +193,10 @@ public class IcpTransformer extends MeshVisitor {
* new transformation and applying it). A number bigger than zero.
* Reasonable number seems to be 10.
* @param scale If {@code true}, then the scale factor is also computed.
* @param error Acceptable error. A number bugger than or equal to zero. When reached, then the ICP stops.
* @param error Acceptable error - a number bigger than or equal to zero.
* Mean distance of vertices is computed for each ICP iteration.
* If the difference between the previous and current mean distances is less than the error,
* then the ICP computation stops. Reasonable number seems to be 0.05.
* @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used.
* @throws IllegalArgumentException if some parameter is wrong
*/
......@@ -259,6 +292,8 @@ public class IcpTransformer extends MeshVisitor {
false // auto crop
);
//int numSamples = samplingStrategy.getNumDownsampledPoints(transformedFacet.getNumberOfVertices());
//samplingStrategy.setRequiredSamples(200);
MeshFacet reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy);
int currentIteration = 0;
......@@ -289,7 +324,12 @@ public class IcpTransformer extends MeshVisitor {
applyTransformation(reducedFacet, transformation);
}
currentIteration ++;
currentIteration++;
//if (currentIteration >= 3) {
// samplingStrategy.setRequiredSamples(numSamples);
// reducedFacet = new UndersampledMeshFacet(transformedFacet, samplingStrategy);
//}
}
}
......
......@@ -134,7 +134,7 @@ public abstract class PointSampling extends MeshVisitor {
* @param origPoints Original number of vertices
* @return number of points to be returned after downsampling.
*/
protected int getNumDownsampledPoints(int origPoints) {
public int getNumDownsampledPoints(int origPoints) {
switch (this.samplingType) {
case PERCENTAGE:
return (int) (origPoints * this.samplingLimit);
......
......@@ -66,7 +66,7 @@ public class BatchPanel extends ControlPanel {
jButton1.addActionListener(createListener(action, ACTION_COMMAND_COMPUTE_ICP));
spinSlider1.initInteger(2000, 0, 5000, 1);
spinSlider1.initInteger(1000, 0, 5000, 1); // downsampling strength
jComboBox2.addItem(SIMILARITY_APPROX_HD);
jComboBox2.addItem(SIMILARITY_COMPLETE_HD);
......
......@@ -27,6 +27,9 @@ import javax.swing.SwingWorker;
* @author Radek Oslejsek
*/
public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
private static final double ICP_ERROR = 0.3; //0.05;
private static final int ICP_ITERS = 100;
private HumanFace avgFace;
private final ProgressDialog progressDialog;
......@@ -121,14 +124,14 @@ public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
HumanFaceUtils.alignMeshes(
initFace,
face, // is transformed
100, // max iterations
ICP_ITERS, // max iterations
controlPanel.scaleIcp(),
0.3, // error
ICP_ERROR, // error
sampling,
false // drop k-d tree, if exists
);
icpComputationTime.stop();
System.out.println(sampling);
//System.out.println(sampling);
}
if (computeAvgFace) { // AVG template face
......
......@@ -3,10 +3,9 @@ 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.symmetry.Plane;
import cz.fidentis.analyst.symmetry.SymmetryEstimator;
import cz.fidentis.analyst.symmetry.SymmetryEstimatorRobust;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
import cz.fidentis.analyst.visitors.mesh.sampling.CurvatureSampling;
import cz.fidentis.analyst.visitors.mesh.sampling.NoSampling;
......@@ -19,6 +18,7 @@ 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;
......@@ -48,13 +48,13 @@ public class IcpDownsampling {
.limit(MAX_SAMPLES)
.collect(Collectors.toList());
SortedMap<Integer, Stopwatch> efficiency = new TreeMap<>();
SortedMap<Integer, List<Double>> precision = new TreeMap<>();
SortedMap<Integer, Stopwatch> efficiency = new TreeMap<>(Collections.reverseOrder());
SortedMap<Integer, List<Double>> precision = new TreeMap<>(Collections.reverseOrder());
//String alg = "random";
String alg = "random";
//String alg = "gaussian";
//String alg = "uniform space";
String alg = "uniform mesh";
//String alg = "uniform mesh";
int counter = 1;
for (int i = 0; i < faces.size(); i += 5) {
......@@ -78,7 +78,7 @@ public class IcpDownsampling {
});
System.out.println();
System.out.println("Avg. Precision - " + sampling + " sampling:");
System.out.println("# samples;average similarity;variance");
System.out.println("# samples;dissimilarity;variance");
precision.entrySet().forEach(e -> {
double avg = e.getValue().stream()
.mapToDouble(val -> val)
......@@ -100,64 +100,86 @@ public class IcpDownsampling {
//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[]{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);
SymmetryEstimator seVisitor = new SymmetryEstimatorRobust(new UniformSpaceSampling(), 100, 1000);
priFace.getMeshModel().compute(seVisitor);
priFace.setSymmetryPlane(seVisitor.getSymmetryPlane());
HumanFace secFaceFromFile = new HumanFace(secFacePath.toFile());
seVisitor = new SymmetryEstimatorRobust(new UniformSpaceSampling(), 100, 1000);
secFaceFromFile.getMeshModel().compute(seVisitor);
secFaceFromFile.setSymmetryPlane(seVisitor.getSymmetryPlane());
System.out.println(secFaceFromFile.getShortName());
for (int i: samples) {
HumanFace secFace = new HumanFace(new MeshModel(secFaceFromFile.getMeshModel()), secFaceFromFile.getId());
secFace.setSymmetryPlane(new Plane(secFaceFromFile.getSymmetryPlane()));
PointSampling sampling;
PointSampling secSampling;
PointSampling priSampling;
switch (samp) {
case "random":
sampling = new RandomSampling();
secSampling = new RandomSampling();
priSampling = new RandomSampling();
break;
case "gaussian":
sampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
secSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
priSampling = new CurvatureSampling(CurvatureSampling.CurvatureAlg.GAUSSIAN);
break;
case "uniform space":
sampling = new UniformSpaceSampling();
secSampling = new UniformSpaceSampling();
priSampling = new UniformSpaceSampling();
break;
case "uniform mesh":
sampling = new UniformSurfaceSampling();
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) {
sampling = new NoSampling();
priSampling = new NoSampling();
} else {
//sampling.setRequiredSamples(i/100.0);
sampling.setRequiredSamples(i);
priSampling.setRequiredSamples(i);
}
secSampling.setRequiredSamples(5000);
efficiency.computeIfAbsent(i, k-> new Stopwatch("")).start();
HumanFaceUtils.alignSymmetryPlanes(priFace, secFace, false, true);
HumanFaceUtils.alignMeshes(
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.3, // error
sampling,
false // drop k-d tree, if exists
0.05, // error
secSampling,
false // drop k-d tree of the secFace, if exists
);
*/
efficiency.get(i).stop();
System.out.println("" + sampling);
System.out.println(" Primary face: " + priSampling);
System.out.println("Secondary face: " + secSampling);
HausdorffDistance hd = new HausdorffDistance(
priFace.getKdTree(),
......@@ -171,4 +193,12 @@ public class IcpDownsampling {
}
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;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment