boofcv.alg.fiducial.microqr.MicroQrPose3DUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boofcv-recognition Show documentation
Show all versions of boofcv-recognition Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
The newest version!
/*
* Copyright (c) 2022, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.alg.fiducial.microqr;
import boofcv.struct.distort.DoNothing2Transform2_F64;
import boofcv.struct.distort.Point2Transform2_F64;
import boofcv.struct.geo.Point2D3D;
import boofcv.struct.geo.PointIndex2D_F64;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point3D_F64;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Utilities when estimating the 3D pose of a Micro QR Code. Each landmark (e.g. corner on a locator pattern) is assigned
* an ID. Functions are provided for accessing coordinates (of each landmark by ID. 3D coordinates in marker frame
* have values from -1 to 1 to make it more numerically favorable for linear estimators. This scale offset is easily
* fixed with a multiplication after the pose has been found.
*
* @author Peter Abeles
*/
public class MicroQrPose3DUtils {
// observed pixel observations with indexes
public List pixelControl = new ArrayList<>();
// storage for corner locations in marker reference frame in 3D and normalized image coordinate observations
public List point23 = new ArrayList<>();
// storage for corner locations in marker reference frame in 3D
public List point3D = new ArrayList<>();
// transform from pixel to normalzied image coordinates
protected Point2Transform2_F64 pixelToNorm = new DoNothing2Transform2_F64();
protected Point2Transform2_F64 undistToDist = new DoNothing2Transform2_F64(); // undistorted pixel to distorted
public MicroQrPose3DUtils() {
for (int i = 0; i < 4; i++) {
pixelControl.add(new PointIndex2D_F64(0, 0, i));
point23.add(new Point2D3D());
point3D.add(new Point3D_F64());
}
}
/**
* Converts the corner observations into {@link PointIndex2D_F64} where observations are in pixels
*/
public List getLandmarkByIndex( MicroQrCode qr ) {
pixelControl.get(0).p.setTo(qr.pp.get(0));
pixelControl.get(1).p.setTo(qr.pp.get(1));
pixelControl.get(2).p.setTo(qr.pp.get(2));
pixelControl.get(3).p.setTo(qr.pp.get(3));
// put it back into distorted pixels. Required by FiducialDetectorPnP
for (int i = 0; i < pixelControl.size(); i++) {
Point2D_F64 p = pixelControl.get(i).p;
undistToDist.compute(p.x, p.y, p);
}
return pixelControl;
}
/**
* Returns a list of {@link Point2D3D}. The 2D observation is the corner in normalized image coordinates.
* The 3D location is the location of the corner in the marker's reference frame
*
* @param qr The qr code
* @return List of corner points in marker frame and normalized image coordinates
*/
public List getLandmark2D3D( MicroQrCode qr ) {
int N = qr.getNumberOfModules();
setPair(0, 0, 0, N, qr.pp.get(0));
setPair(1, 0, 7, N, qr.pp.get(1));
setPair(2, 7, 7, N, qr.pp.get(2));
setPair(3, 7, 0, N, qr.pp.get(3));
return point23;
}
/**
* Location of each corner in the QR Code's reference frame in 3D
*
* @param version QR Code's version
* @return List. Recycled on each call
*/
public List getLandmark3D( int version ) {
int N = MicroQrCode.totalModules(version);
set3D(0, 0, N, point3D.get(0));
set3D(0, 7, N, point3D.get(1));
set3D(7, 7, N, point3D.get(2));
set3D(7, 0, N, point3D.get(3));
return point3D;
}
/**
* Specifies PNP parameters for a single feature
*
* @param which Landmark's index
* @param row row in the QR code's grid coordinate system
* @param col column in the QR code's grid coordinate system
* @param N width of grid
* @param pixel observed pixel coordinate of feature
*/
private void setPair( int which, int row, int col, int N, Point2D_F64 pixel ) {
set3D(row, col, N, point23.get(which).location);
pixelToNorm.compute(pixel.x, pixel.y, point23.get(which).observation);
}
/**
* Specifies 3D location of landmark in marker coordinate system
*
* @param row row in the QR code's grid coordinate system
* @param col column in the QR code's grid coordinate system
* @param N width of grid
* @param location (Output) location of feature in marker reference frame
*/
private void set3D( int row, int col, int N, Point3D_F64 location ) {
double _N = N;
double gridX = 2.0*(col/_N - 0.5);
double gridY = 2.0*(0.5 - row/_N);
location.setTo(gridX, gridY, 0);
}
/**
* Specifies transform from pixel to normalize image coordinates
*/
public void setLensDistortion( @Nullable Point2Transform2_F64 pixelToNorm,
@Nullable Point2Transform2_F64 undistToDist ) {
if (pixelToNorm == null || undistToDist == null) {
this.pixelToNorm = new DoNothing2Transform2_F64();
this.undistToDist = new DoNothing2Transform2_F64();
} else {
this.pixelToNorm = pixelToNorm;
this.undistToDist = undistToDist;
}
}
public Point2Transform2_F64 getPixelToNorm() {
return pixelToNorm;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy