use of boofcv.alg.geo.WorldToCameraToPixel in project BoofCV by lessthanoptimal.
the class VisualizeFiducial method drawLabelCenter.
/**
* Draws a flat cube to show where the square fiducial is on the image
*/
public static void drawLabelCenter(Se3_F64 targetToCamera, CameraPinholeRadial intrinsic, String label, Graphics2D g2) {
// Computer the center of the fiducial in pixel coordinates
Point2D_F64 p = new Point2D_F64();
Point3D_F64 c = new Point3D_F64();
WorldToCameraToPixel worldToPixel = PerspectiveOps.createWorldToPixel(intrinsic, targetToCamera);
worldToPixel.transform(c, p);
drawLabel(p, label, g2);
}
use of boofcv.alg.geo.WorldToCameraToPixel in project BoofCV by lessthanoptimal.
the class CommonStructure method simulate.
public void simulate(int numViews, int numFeatures, boolean planar) {
worldToViews = new ArrayList<>();
projections = new ArrayList<>();
observations = new ArrayList<>();
// Randomly generate structure in front of the cameras
if (planar) {
PlaneNormal3D_F64 plane = new PlaneNormal3D_F64(0, 0, 2, 0.1, -0.05, 1);
plane.n.normalize();
features3D = UtilPoint3D_F64.random(plane, 0.5, numFeatures, rand);
} else {
features3D = UtilPoint3D_F64.random(new Point3D_F64(0, 0, 2), -0.5, 0.5, numFeatures, rand);
}
DMatrixRMaj K = PerspectiveOps.pinholeToMatrix(pinhole, (DMatrixRMaj) null);
// Generate views the adjust all 6-DOF but and distinctive while pointing at the points
for (int i = 0; i < numViews; i++) {
Se3_F64 worldToView = new Se3_F64();
worldToView.T.x = -1 + 0.1 * i;
worldToView.T.y = rand.nextGaussian() * 0.05;
worldToView.T.z = -0.5 + 0.05 * i + rand.nextGaussian() * 0.01;
double rotX = rand.nextGaussian() * 0.05;
double rotY = rand.nextGaussian() * 0.05;
ConvertRotation3D_F64.eulerToMatrix(EulerType.XYZ, rotX, rotY, 0, worldToView.R);
DMatrixRMaj P = new DMatrixRMaj(3, 4);
PerspectiveOps.createCameraMatrix(worldToView.R, worldToView.T, K, P);
worldToViews.add(worldToView);
projections.add(P);
}
// generate observations
WorldToCameraToPixel w2p = new WorldToCameraToPixel();
for (int i = 0; i < numViews; i++) {
List<Point2D_F64> viewObs = new ArrayList<>();
w2p.configure(pinhole, worldToViews.get(i));
for (int j = 0; j < numFeatures; j++) {
viewObs.add(w2p.transform(features3D.get(j)));
}
observations.add(viewObs);
}
}
use of boofcv.alg.geo.WorldToCameraToPixel in project BoofCV by lessthanoptimal.
the class GenericBundleAdjustmentMetricChecks method createHorizontalMotion.
public Tuple2<SceneStructureMetric, SceneObservations> createHorizontalMotion(long seed, boolean cameraFixed) {
Random rand = new Random(seed);
int width = 600;
CameraPinhole intrinsic = new CameraPinhole(400, 400, 0, 300, 300, width, width);
int numViews = 5;
int numFeatures = 250;
SceneStructureMetric structure = new SceneStructureMetric(false);
structure.initialize(1, numViews, numFeatures);
SceneObservations observations = new SceneObservations();
observations.initialize(numViews);
structure.setCamera(0, cameraFixed, intrinsic);
double minX = 0, maxX = 5;
for (int i = 0; i < numViews; i++) {
Se3_F64 worldToView = new Se3_F64();
worldToView.T.x = -((maxX - minX) * i / (numViews - 1) + minX);
structure.setView(i, 0, i == 0, worldToView);
}
WorldToCameraToPixel wcp = new WorldToCameraToPixel();
Point2D_F64 pixel = new Point2D_F64();
for (int featureIndex = 0; featureIndex < numFeatures; featureIndex++) {
// Run until it finds a location where it's visible in at least two views
while (true) {
Point3D_F64 P = new Point3D_F64();
P.x = (maxX - minX) * rand.nextDouble() + minX;
P.y = rand.nextGaussian() / 3;
P.z = rand.nextGaussian() / 10 + maxX / 3;
structure.setPoint(featureIndex, P.x, P.y, P.z);
// see which views it's visible in
int count = 0;
for (int viewIndex = 0; viewIndex < numViews; viewIndex++) {
Se3_F64 parent_to_view = structure.getParentToView(viewIndex);
wcp.configure(intrinsic, parent_to_view);
wcp.transform(P, pixel);
if (pixel.x >= 0 && pixel.x < width && pixel.y >= 0 && pixel.y < width) {
count++;
}
}
if (count >= 2) {
for (int viewIndex = 0; viewIndex < numViews; viewIndex++) {
Se3_F64 parent_to_view = structure.getParentToView(viewIndex);
wcp.configure(intrinsic, parent_to_view);
wcp.transform(P, pixel);
if (pixel.x >= 0 && pixel.x < width && pixel.y >= 0 && pixel.y < width) {
observations.getView(viewIndex).add(featureIndex, (float) pixel.x, (float) pixel.y);
structure.connectPointToView(featureIndex, viewIndex);
}
}
break;
}
}
}
return new Tuple2<>(structure, observations);
}
use of boofcv.alg.geo.WorldToCameraToPixel in project BoofCV by lessthanoptimal.
the class TestMultiViewStereoOps method renderCloudToDisparity.
/**
* Renders the cloud into the disparity image and removes points which land on the same pixel
*/
void renderCloudToDisparity(List<Point3D_F64> cloud, Se3_F64 cloud_to_stereo, LensDistortionNarrowFOV distortion, DisparityParameters param, ImageGray<?> disparity) {
// mark all pixels as invalid initially
GImageMiscOps.fill(disparity, param.disparityRange);
var w2p = new WorldToCameraToPixel();
w2p.configure(distortion, cloud_to_stereo);
Point2D_F64 pixel = new Point2D_F64();
for (int i = cloud.size() - 1; i >= 0; i--) {
assertTrue(w2p.transform(cloud.get(i), pixel));
assertTrue(BoofMiscOps.isInside(disparity, pixel.x, pixel.y));
double d = param.baseline * param.pinhole.fx / w2p.getCameraPt().z - param.disparityMin;
assertTrue(d >= 0.0 && d < param.disparityRange);
int xx = (int) (pixel.x + 0.5);
int yy = (int) (pixel.y + 0.5);
double value = GeneralizedImageOps.get(disparity, xx, yy);
if (Math.abs(value - param.disparityRange) > 5e-4) {
cloud.remove(i);
} else {
GeneralizedImageOps.set(disparity, xx, yy, d);
}
}
}
use of boofcv.alg.geo.WorldToCameraToPixel in project BoofCV by lessthanoptimal.
the class MockLookupSimilarImagesRealistic method generate.
/**
* Renders the scene using only ready generated points and image coordinates
*/
public MockLookupSimilarImagesRealistic generate(List<Se3_F64> list_camera_to_world, int numViewConnect) {
DMatrixRMaj K = PerspectiveOps.pinholeToMatrix(intrinsic, (DMatrixRMaj) null);
int numViews = list_camera_to_world.size();
// render pixel coordinates of all points
for (int viewCnt = 0; viewCnt < numViews; viewCnt++) {
View v = new View();
v.id = "" + viewCnt;
Se3_F64 camera_to_world = list_camera_to_world.get(viewCnt);
camera_to_world.invert(v.world_to_view);
v.camera = PerspectiveOps.createCameraMatrix(v.world_to_view.R, v.world_to_view.T, K, null);
// Project the features into the camera and see what's visible
WorldToCameraToPixel w2p = new WorldToCameraToPixel();
w2p.configure(intrinsic, v.world_to_view);
Point2D_F64 pixel = new Point2D_F64();
for (Feature f : points) {
if (!w2p.transform(f.world, pixel))
continue;
// Adjust pixel coordinates if intrinsics has principle point at (0,0) instead of inside the image
double xx = pixel.x + (intrinsic.cx == 0.0 ? intrinsic.width / 2 : 0.0);
double yy = pixel.y + (intrinsic.cy == 0.0 ? intrinsic.height / 2 : 0.0);
if (xx < 0 || yy < 0 || xx >= intrinsic.width || yy >= intrinsic.height)
continue;
Observation o = new Observation();
o.feature = f;
o.pixel.setTo(pixel);
v.observations.add(o);
}
BoofMiscOps.checkTrue(v.observations.size() > 0);
// System.out.println("view="+viewCnt+" obs.size="+v.observations.size());
// Randomize the order of the observations
Collections.shuffle(v.observations, rand);
// for (int i = 0; i < v.observations.size(); i++) {
// for (int j = i+1; j < v.observations.size(); j++) {
// if (v.observations.get(i).feature == v.observations.get(j).feature ) {
// throw new RuntimeException("Observing the same feature more than once!");
// }
// }
// }
views.add(v);
}
// connected
for (int idx0 = 0; idx0 < views.size(); idx0++) {
View a = views.get(idx0);
for (int offset = 1; offset <= numViewConnect; offset++) {
int idx1 = idx0 + offset;
// when wrapping be careful to not connect to the same node twice
if (idx1 >= views.size()) {
if (!loop)
continue;
idx1 %= views.size();
if (idx1 + numViewConnect >= idx0)
continue;
}
View b = views.get(idx1);
if (a.fractionOverlap(b) < 0.5) {
// System.out.println("REJECT "+idx0+" <-> "+idx1+" Fraction Overlap: "+a.fractionOverlap(b));
continue;
}
// System.out.println(idx0+" <-> "+idx1+" Fraction Overlap: "+a.fractionOverlap(b));
a.connected.add(b);
b.connected.add(a);
}
}
return this;
}
Aggregations