Difference between revisions of "ExampleComputeTrifocalTensor"
From BoofCV
Jump to navigationJump to search (Created page with "Shows how to compute a trifocal tensor robustly from a set of image features between three views. Example Code: * [https://github.com/lessthanoptimal/BoofCV/blob/v0.38/exampl...") |
m |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Shows how to compute a trifocal tensor robustly from a set of image features between three views. | Shows how to compute a trifocal tensor robustly from a set of image features between three views. | ||
Example Code: | '''Example Code:''' | ||
* [https://github.com/lessthanoptimal/BoofCV/blob/v0. | * [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/sfm/ExampleComputeTrifocalTensor.java ExampleComputeTrifocalTensor.java] | ||
Concepts: | '''Concepts:''' | ||
* | * 3D Point Cloud | ||
Related Examples: | '''Related Examples:''' | ||
* [[ | * [[Example_View_Point_Cloud| Viewing a Point Cloud]] | ||
= Example Code = | = Example Code = | ||
Line 95: | Line 94: | ||
var triplePanel = new AssociatedTriplePanel(); | var triplePanel = new AssociatedTriplePanel(); | ||
triplePanel.setImages( | triplePanel.setImages( | ||
UtilImageIO. | UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "01.jpg")), | ||
UtilImageIO. | UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "02.jpg")), | ||
UtilImageIO. | UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "03.jpg"))); | ||
triplePanel.setAssociation(inliers); | triplePanel.setAssociation(inliers); | ||
ShowImages.showWindow(triplePanel, "Inliers", true); | ShowImages.showWindow(triplePanel, "Inliers", true); |
Latest revision as of 16:31, 17 January 2022
Shows how to compute a trifocal tensor robustly from a set of image features between three views.
Example Code:
Concepts:
- 3D Point Cloud
Related Examples:
Example Code
/**
* This example shows how to robustly compute a trifocal tensor to features across three views. The trifocal tensor
* is used extensively in reconstruction scenarios and is more robust than applying two-view tensors (e.g. Fundamental
* and Essential matrices) which have issues along the epipolar lines.
*/
public class ExampleComputeTrifocalTensor {
/**
* Computes the trifocal tensor given three images. Returns the set of inlier features found when computing
* the tensor
*/
public static List<AssociatedTriple> imagesToTrifocal(
GrayU8 gray01, GrayU8 gray02, GrayU8 gray03, TrifocalTensor model ) {
// Using SURF features. Robust and fairly fast to compute
var configDetector = new ConfigFastHessian();
configDetector.maxFeaturesAll = 2500; // limit the feature count
configDetector.extract.radius = 4;
DetectDescribePoint<GrayU8, TupleDesc_F64> detDesc = FactoryDetectDescribe.surfStable(configDetector, null, null, GrayU8.class);
// Associate features across all three views using previous example code
var associateThree = new ExampleAssociateThreeView();
associateThree.initialize(detDesc);
associateThree.detectFeatures(gray01, 0);
associateThree.detectFeatures(gray02, 1);
associateThree.detectFeatures(gray03, 2);
DogArray<AssociatedTripleIndex> associatedIdx = associateThree.threeViewPairwiseAssociate();
System.out.println("features01.size = " + associateThree.features01.size);
System.out.println("features02.size = " + associateThree.features02.size);
System.out.println("features03.size = " + associateThree.features03.size);
// Convert the matched indexes into AssociatedTriple which contain the actual pixel coordinates
var associated = new DogArray<>(AssociatedTriple::new);
associatedIdx.forEach(p -> associated.grow().setTo(
associateThree.locations01.get(p.a),
associateThree.locations02.get(p.b),
associateThree.locations03.get(p.c)));
System.out.println("Total Matched Triples = " + associated.size);
// Storage for the found model. In this example we don't actually use the tensor.
List<AssociatedTriple> inliers = computeTrifocal(associated, model);
System.out.println("Remaining after RANSAC " + inliers.size());
return inliers;
}
/**
* Computes the Trifocal Tensor using RANSAC given associated features across 3-views. The found tensor
* is copied into model and the inliers are returned.
*/
public static List<AssociatedTriple> computeTrifocal( DogArray<AssociatedTriple> associated, TrifocalTensor model ) {
var configRansac = new ConfigRansac();
configRansac.iterations = 500;
configRansac.inlierThreshold = 1;
var configTri = new ConfigTrifocal();
ConfigTrifocalError configError = new ConfigTrifocalError();
configError.model = ConfigTrifocalError.Model.REPROJECTION_REFINE;
Ransac<TrifocalTensor, AssociatedTriple> ransac =
FactoryMultiViewRobust.trifocalRansac(configTri, configError, configRansac);
ransac.process(associated.toList());
model.setTo(ransac.getModelParameters());
return ransac.getMatchSet();
}
public static void main( String[] args ) {
String name = "rock_leaves_";
GrayU8 gray01 = UtilImageIO.loadImage(UtilIO.pathExample("triple/" + name + "01.jpg"), GrayU8.class);
GrayU8 gray02 = UtilImageIO.loadImage(UtilIO.pathExample("triple/" + name + "02.jpg"), GrayU8.class);
GrayU8 gray03 = UtilImageIO.loadImage(UtilIO.pathExample("triple/" + name + "03.jpg"), GrayU8.class);
// Compute the trifocal tensor which matches features inside these images
var model = new TrifocalTensor();
List<AssociatedTriple> inliers = imagesToTrifocal(gray01, gray02, gray03, model);
// Show inlier associations from RANSAC
var triplePanel = new AssociatedTriplePanel();
triplePanel.setImages(
UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "01.jpg")),
UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "02.jpg")),
UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "03.jpg")));
triplePanel.setAssociation(inliers);
ShowImages.showWindow(triplePanel, "Inliers", true);
}
}