Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cd90dec
Delete aaBlueDuckdet.java
MechaKnights Sep 19, 2022
3fffa4e
Delete aaBlueWaredet.java
MechaKnights Sep 19, 2022
980cd94
Delete aaRedDuckdet.java
MechaKnights Sep 19, 2022
32ad999
Delete aaRedWaredet.java
MechaKnights Sep 19, 2022
34397cc
Delete bluetest.java
MechaKnights Sep 19, 2022
7f75b8d
Delete redtest.java
MechaKnights Sep 19, 2022
80a31a0
Delete aaabluewere.java
MechaKnights Sep 19, 2022
3d7360a
Update TeamShippingElementPipeline.java
MechaKnights Sep 19, 2022
ebdf44e
Update TeamShippingElementPipeline.java
MechaKnights Sep 19, 2022
95e92ae
Update TeamShippingElementPipeline.java
MechaKnights Sep 19, 2022
7f2e216
Add files via upload
MechaKnights Oct 24, 2022
4e01136
Update SignalPipeline1.java
MechaKnights Nov 4, 2022
c5e94de
Update WebcamTesting.java
MechaKnights Nov 4, 2022
48743af
Add files via upload
MechaKnights Nov 12, 2022
5d5d463
Update TeleopTest.java
MechaKnights Nov 28, 2022
d8a306c
Update TeleopTest.java
MechaKnights Nov 29, 2022
b49a084
Delete SignalPipeline1.java
MechaKnights Nov 30, 2022
0ec7545
Delete WebcamTesting.java
MechaKnights Nov 30, 2022
0bd016d
Update WebcamTest.java
MechaKnights Nov 30, 2022
c3488fa
Create Test
MechaKnights Nov 30, 2022
9606052
Update DriveConstants.java
MechaKnights Nov 30, 2022
4c10c96
Update SignalPipeline.java
MechaKnights Nov 30, 2022
3430233
Update SignalPipeline.java
MechaKnights Feb 3, 2023
654c324
Add files via upload
MechaKnights Feb 3, 2023
5a253cd
Update and rename teamcode/BlueLeftAuto.java to RedLeftTest.java
MechaKnights Feb 13, 2023
2e4e30b
Update and rename BlueRightAuto.java to BlueRightTest.java
MechaKnights Feb 13, 2023
fb0273f
Update and rename RedLeftTest.java to BlueLeftTest.java
MechaKnights Feb 13, 2023
605f2a9
Update and rename RedL.java to RedLeftTest.java
MechaKnights Feb 13, 2023
9737741
Update and rename RedR.java to RedRightTest.java
MechaKnights Feb 13, 2023
4435a4a
Update and rename Teleop.java to TeleopTest.java
MechaKnights Feb 13, 2023
c05fc09
Update TeleopTest.java
MechaKnights Feb 24, 2023
60ed69d
Add files via upload
MechaKnights Feb 28, 2023
72277be
Delete BlueLeftTest.java
MechaKnights Jun 28, 2023
82e7f1e
Add files via upload
MechaKnights Jun 28, 2023
c10e856
Delete teamcode directory
MechaKnights Jun 28, 2023
00a2db1
Add files via upload
MechaKnights Jun 28, 2023
f91651c
Update BlueLeftTest.java
MechaKnights Sep 6, 2023
bdb6fd2
Update BlueRightTest.java
MechaKnights Sep 6, 2023
a732009
Update RedLeftTest.java
MechaKnights Sep 6, 2023
2298178
Update RedRightTest.java
MechaKnights Sep 6, 2023
42dcad3
Update AprilTagDetectionPipeline.java
MechaKnights Sep 6, 2023
7f24aa0
Create TeleopTest
MechaKnights Sep 6, 2023
24bb967
Update TeleopTest
ptaylor-ditto Jan 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
312 changes: 312 additions & 0 deletions AprilTagDetectionPipeline.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
package org.firstinspires.ftc.teamcode.Auton;

/*
* Copyright (c) 2021 OpenFTC Team
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import org.opencv.calib3d.Calib3d;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.MatOfPoint3f;
import org.opencv.core.Point;
import org.opencv.core.Point3;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.openftc.apriltag.AprilTagDetection;
import org.openftc.apriltag.AprilTagDetectorJNI;
import org.openftc.easyopencv.OpenCvPipeline;

import java.util.ArrayList;

class AprilTagDetectionPipeline extends OpenCvPipeline
{
private long nativeApriltagPtr;
private Mat grey = new Mat();
private ArrayList<AprilTagDetection> detections = new ArrayList<>();

private ArrayList<AprilTagDetection> detectionsUpdate = new ArrayList<>();
private final Object detectionsUpdateSync = new Object();

Mat cameraMatrix;

Scalar blue = new Scalar(7,197,235,255);
Scalar red = new Scalar(255,0,0,255);
Scalar green = new Scalar(0,255,0,255);
Scalar white = new Scalar(255,255,255,255);

double fx;
double fy;
double cx;
double cy;

// UNITS ARE METERS
double tagsize;
double tagsizeX;
double tagsizeY;

private float decimation;
private boolean needToSetDecimation;
private final Object decimationSync = new Object();

public AprilTagDetectionPipeline(double tagsize, double fx, double fy, double cx, double cy)
{
this.tagsize = tagsize;
this.tagsizeX = tagsize;
this.tagsizeY = tagsize;
this.fx = fx;
this.fy = fy;
this.cx = cx;
this.cy = cy;

constructMatrix();

// Allocate a native context object. See the corresponding deletion in the finalizer
nativeApriltagPtr = AprilTagDetectorJNI.createApriltagDetector(AprilTagDetectorJNI.TagFamily.TAG_36h11.string, 3, 3);
}

@Override
public void finalize()
{
// Might be null if createApriltagDetector() threw an exception
if(nativeApriltagPtr != 0)
{
// Delete the native context we created in the constructor
AprilTagDetectorJNI.releaseApriltagDetector(nativeApriltagPtr);
nativeApriltagPtr = 0;
}
else
{
System.out.println("AprilTagDetectionPipeline.finalize(): nativeApriltagPtr was NULL");
}
}

@Override
public Mat processFrame(Mat input)
{
// Convert to greyscale
Imgproc.cvtColor(input, grey, Imgproc.COLOR_RGBA2GRAY);

synchronized (decimationSync)
{
if(needToSetDecimation)
{
AprilTagDetectorJNI.setApriltagDetectorDecimation(nativeApriltagPtr, decimation);
needToSetDecimation = false;
}
}

// Run AprilTag
detections = AprilTagDetectorJNI.runAprilTagDetectorSimple(nativeApriltagPtr, grey, tagsize, fx, fy, cx, cy);

synchronized (detectionsUpdateSync)
{
detectionsUpdate = detections;
}

// For fun, use OpenCV to draw 6DOF markers on the image. We actually recompute the pose using
// OpenCV because I haven't yet figured out how to re-use AprilTag's pose in OpenCV.
for(AprilTagDetection detection : detections)
{
Pose pose = poseFromTrapezoid(detection.corners, cameraMatrix, tagsizeX, tagsizeY);
drawAxisMarker(input, tagsizeY/2.0, 6, pose.rvec, pose.tvec, cameraMatrix);
draw3dCubeMarker(input, tagsizeX, tagsizeX, tagsizeY, 5, pose.rvec, pose.tvec, cameraMatrix);
}

return input;
}

public void setDecimation(float decimation)
{
synchronized (decimationSync)
{
this.decimation = decimation;
needToSetDecimation = true;
}
}

public ArrayList<AprilTagDetection> getLatestDetections()
{
return detections;
}

public ArrayList<AprilTagDetection> getDetectionsUpdate()
{
synchronized (detectionsUpdateSync)
{
ArrayList<AprilTagDetection> ret = detectionsUpdate;
detectionsUpdate = null;
return ret;
}
}

void constructMatrix()
{
// Construct the camera matrix.
//
// -- --
// | fx 0 cx |
// | 0 fy cy |
// | 0 0 1 |
// -- --
//

cameraMatrix = new Mat(3,3, CvType.CV_32FC1);

cameraMatrix.put(0,0, fx);
cameraMatrix.put(0,1,0);
cameraMatrix.put(0,2, cx);

cameraMatrix.put(1,0,0);
cameraMatrix.put(1,1,fy);
cameraMatrix.put(1,2,cy);

cameraMatrix.put(2, 0, 0);
cameraMatrix.put(2,1,0);
cameraMatrix.put(2,2,1);
}

/**
* Draw a 3D axis marker on a detection. (Similar to what Vuforia does)
*
* @param buf the RGB buffer on which to draw the marker
* @param length the length of each of the marker 'poles'
* @param rvec the rotation vector of the detection
* @param tvec the translation vector of the detection
* @param cameraMatrix the camera matrix used when finding the detection
*/
void drawAxisMarker(Mat buf, double length, int thickness, Mat rvec, Mat tvec, Mat cameraMatrix)
{
// The points in 3D space we wish to project onto the 2D image plane.
// The origin of the coordinate space is assumed to be in the center of the detection.
MatOfPoint3f axis = new MatOfPoint3f(
new Point3(0,0,0),
new Point3(length,0,0),
new Point3(0,length,0),
new Point3(0,0,-length)
);

// Project those points
MatOfPoint2f matProjectedPoints = new MatOfPoint2f();
Calib3d.projectPoints(axis, rvec, tvec, cameraMatrix, new MatOfDouble(), matProjectedPoints);
Point[] projectedPoints = matProjectedPoints.toArray();

// Draw the marker!
Imgproc.line(buf, projectedPoints[0], projectedPoints[1], red, thickness);
Imgproc.line(buf, projectedPoints[0], projectedPoints[2], green, thickness);
Imgproc.line(buf, projectedPoints[0], projectedPoints[3], blue, thickness);

Imgproc.circle(buf, projectedPoints[0], thickness, white, -1);
}

void draw3dCubeMarker(Mat buf, double length, double tagWidth, double tagHeight, int thickness, Mat rvec, Mat tvec, Mat cameraMatrix)
{
//axis = np.float32([[0,0,0], [0,3,0], [3,3,0], [3,0,0],
// [0,0,-3],[0,3,-3],[3,3,-3],[3,0,-3] ])

// The points in 3D space we wish to project onto the 2D image plane.
// The origin of the coordinate space is assumed to be in the center of the detection.
MatOfPoint3f axis = new MatOfPoint3f(
new Point3(-tagWidth/2, tagHeight/2,0),
new Point3( tagWidth/2, tagHeight/2,0),
new Point3( tagWidth/2,-tagHeight/2,0),
new Point3(-tagWidth/2,-tagHeight/2,0),
new Point3(-tagWidth/2, tagHeight/2,-length),
new Point3( tagWidth/2, tagHeight/2,-length),
new Point3( tagWidth/2,-tagHeight/2,-length),
new Point3(-tagWidth/2,-tagHeight/2,-length));

// Project those points
MatOfPoint2f matProjectedPoints = new MatOfPoint2f();
Calib3d.projectPoints(axis, rvec, tvec, cameraMatrix, new MatOfDouble(), matProjectedPoints);
Point[] projectedPoints = matProjectedPoints.toArray();

// Pillars
for(int i = 0; i < 4; i++)
{
Imgproc.line(buf, projectedPoints[i], projectedPoints[i+4], blue, thickness);
}

// Base lines
//Imgproc.line(buf, projectedPoints[0], projectedPoints[1], blue, thickness);
//Imgproc.line(buf, projectedPoints[1], projectedPoints[2], blue, thickness);
//Imgproc.line(buf, projectedPoints[2], projectedPoints[3], blue, thickness);
//Imgproc.line(buf, projectedPoints[3], projectedPoints[0], blue, thickness);

// Top lines
Imgproc.line(buf, projectedPoints[4], projectedPoints[5], green, thickness);
Imgproc.line(buf, projectedPoints[5], projectedPoints[6], green, thickness);
Imgproc.line(buf, projectedPoints[6], projectedPoints[7], green, thickness);
Imgproc.line(buf, projectedPoints[4], projectedPoints[7], green, thickness);
}

/**
* Extracts 6DOF pose from a trapezoid, using a camera intrinsics matrix and the
* original size of the tag.
*
* @param points the points which form the trapezoid
* @param cameraMatrix the camera intrinsics matrix
* @param tagsizeX the original width of the tag
* @param tagsizeY the original height of the tag
* @return the 6DOF pose of the camera relative to the tag
*/
Pose poseFromTrapezoid(Point[] points, Mat cameraMatrix, double tagsizeX , double tagsizeY)
{
// The actual 2d points of the tag detected in the image
MatOfPoint2f points2d = new MatOfPoint2f(points);

// The 3d points of the tag in an 'ideal projection'
Point3[] arrayPoints3d = new Point3[4];
arrayPoints3d[0] = new Point3(-tagsizeX/2, tagsizeY/2, 0);
arrayPoints3d[1] = new Point3(tagsizeX/2, tagsizeY/2, 0);
arrayPoints3d[2] = new Point3(tagsizeX/2, -tagsizeY/2, 0);
arrayPoints3d[3] = new Point3(-tagsizeX/2, -tagsizeY/2, 0);
MatOfPoint3f points3d = new MatOfPoint3f(arrayPoints3d);

// Using this information, actually solve for pose
Pose pose = new Pose();
Calib3d.solvePnP(points3d, points2d, cameraMatrix, new MatOfDouble(), pose.rvec, pose.tvec, false);

return pose;
}

/*
* A simple container to hold both rotation and translation
* vectors, which together form a 6DOF pose.
*/
class Pose
{
Mat rvec;
Mat tvec;

public Pose()
{
rvec = new Mat();
tvec = new Mat();
}

public Pose(Mat rvec, Mat tvec)
{
this.rvec = rvec;
this.tvec = tvec;
}
}
}
Loading