AlphaBit OpenML
Documentation
Control Intake Using The OpenML
For Low Quality Camera Machine Learning Model (low.tflite) (Will be added support for high.tflite today)
package org.firstinspires.ftc.teamcode.drive.opmodes;

                        import android.content.res.AssetFileDescriptor;
                        import android.content.res.AssetManager;
                        import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
                        import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
                        import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
                        import org.firstinspires.ftc.robotcore.internal.camera.calibration.CameraCalibration;
                        import org.firstinspires.ftc.vision.VisionPortal;
                        import org.firstinspires.ftc.vision.VisionProcessor;
                        import org.opencv.core.Core;
                        import org.opencv.core.CvType;
                        import org.opencv.core.Mat;
                        import org.opencv.imgproc.Imgproc;
                        import org.tensorflow.lite.Interpreter;

                        import android.graphics.Canvas;
                        import android.util.Size;
                        import java.io.FileInputStream;
                        import java.io.IOException;
                        import java.nio.ByteBuffer;
                        import java.nio.ByteOrder;
                        import java.nio.channels.FileChannel;
                        import java.util.ArrayList;
                        import java.util.List;

                        @TeleOp(name = "AI Vision", group = "AITesting")
                        public class AIVision extends LinearOpMode {

                            // Configuration
                            private static final String MODEL_FILE = "best_float32.tflite";
                            private static final int MODEL_SIZE = 320;
                            private static final float CONF_THRESHOLD = 0.6f;
                            private static final float IOU_THRESHOLD = 0.5f;

                            IntakeControl intake_control; // Intake Control Object
                            private VisionPortal visionPortal;

                            @Override
                            public void runOpMode() {
                                YoloProcessor frameProcessor = new YoloProcessor(hardwareMap.appContext.getAssets());
                            intake_control = new IntakeControl(hardwareMap, Gamepad1);
    
                                visionPortal = new VisionPortal.Builder()
                                        .setCamera(hardwareMap.get(WebcamName.class, "AICam"))
                                        .setStreamFormat(VisionPortal.StreamFormat.YUY2)
                                        .setCameraResolution(new Size(320, 240))
                                        .addProcessor(frameProcessor)
                                        .build();

                                waitForStart();

                                try {
                                    while (opModeIsActive()) {
                                        List detections = frameProcessor.getLatestDetections();
                                        telemetry.addData("Detections", detections.size());
                                        int bestConfidence = -1;
                                        double confCounter=0;
                                        for(int i=0; i 0){
                                            Detection d = detections.get(bestConfidence);
                                            double angle = Math.toDegrees(Math.atan(d.height/d.width));
                                            double x = 6.4131;
                                            double y = 0.7223;
                                            double final_angle = (angle - x)/y;
                                            //example control of intake
                                            intake_control.setIntakePosition(final_angle); // final_ angle is in degrees and will be managed in the IntakeControl class to give the proper position | Example of that is in PYTHON testing code|
                                            telemetry.addData(String.format("Obj %d", bestConfidence),
                                                    "%s %.1f%% | W: %.1f H: %.1f Angle: %.1f",
                                                    d.className(),
                                                    d.confidence * 100,
                                                    d.width,
                                                    d.height,
                                                    final_angle);
                                        }

                                        //!!! This one is to show all the detections. The one from above is to get only the detection with the highest confidence out of all.
                                        /*for (int i = 0; i < detections.size(); i++) {
                                            Detection d = detections.get(i);
                                            telemetry.addData(String.format("Obj %d", i),
                                                    "%s %.1f%% | W: %.1f H: %.1f",
                                                    d.className(),
                                                    d.confidence * 100,
                                                    d.width,
                                                    d.height);
                                        }*/
                                        telemetry.update();
                                    }
                                } finally {
                                    visionPortal.close();
                                    frameProcessor.close();
                                }
                            }

                            static class YoloProcessor implements VisionProcessor {
                                private final Interpreter tflite;
                                private final Object syncLock = new Object();
                                private List detections = new ArrayList<>();

        
                                private final float[][][] outputBuffer = new float[1][7][2100];  
                                private final ByteBuffer inputBuffer;
                                private final Mat resizedMat = new Mat();
                                private final Mat rgbMat = new Mat();

                                public YoloProcessor(AssetManager assets) {
                                    try {
                                        Interpreter.Options options = new Interpreter.Options();
                                        options.setNumThreads(4);
                                        options.setUseXNNPACK(true);
                                        tflite = new Interpreter(loadModelFile(assets), options);

                                        inputBuffer = ByteBuffer.allocateDirect(MODEL_SIZE * MODEL_SIZE * 3 * 4);
                                        inputBuffer.order(ByteOrder.nativeOrder());
                                    } catch (IOException e) {
                                        throw new RuntimeException("Model loading failed", e);
                                    }
                                }

                                private ByteBuffer loadModelFile(AssetManager assets) throws IOException {
                                    try (AssetFileDescriptor afd = assets.openFd(MODEL_FILE)) {
                                        try (FileInputStream fis = new FileInputStream(afd.getFileDescriptor())) {
                                            FileChannel channel = fis.getChannel();
                                            return channel.map(FileChannel.MapMode.READ_ONLY, afd.getStartOffset(), afd.getDeclaredLength());
                                        }
                                    }
                                }

                                @Override
                                public void init(int width, int height, CameraCalibration calibration) {}

                                @Override
                                public Object processFrame(Mat frame, long captureTimeNanos) {
            
                                    Mat rotated = new Mat();
                                    Core.rotate(frame, rotated, Core.ROTATE_90_CLOCKWISE);

                                    Imgproc.resize(rotated  , resizedMat, new org.opencv.core.Size(MODEL_SIZE, MODEL_SIZE));
                                    Imgproc.cvtColor(resizedMat, rgbMat, Imgproc.COLOR_BGR2RGB);
                                    rgbMat.convertTo(rgbMat, CvType.CV_32FC3, 1.0 / 255.0);

                                    float[] floatBuffer = new float[MODEL_SIZE * MODEL_SIZE * 3];
                                    rgbMat.get(0, 0, floatBuffer);
                                    inputBuffer.rewind();
                                    inputBuffer.asFloatBuffer().put(floatBuffer);

            
                                    tflite.run(inputBuffer, outputBuffer);

                                    List newDetections = processOutput(frame.width(), frame.height());
                                    synchronized (syncLock) {
                                        detections = newDetections;
                                    }
                                    return null;
                                }

                                private List processOutput(int frameWidth, int frameHeight) {
                                    List rawDetections = new ArrayList<>();
                                    final float[] xCenterArray = outputBuffer[0][0];
                                    final float[] yCenterArray = outputBuffer[0][1];
                                    final float[] widthArray = outputBuffer[0][2];
                                    final float[] heightArray = outputBuffer[0][3];
                                    final float[] class0Array = outputBuffer[0][4];
                                    final float[] class1Array = outputBuffer[0][5];
                                    final float[] class2Array = outputBuffer[0][6];

            
                                    for (int j = 0; j < 2100; j++) {  
                                        float maxScore = Math.max(class0Array[j], Math.max(class1Array[j], class2Array[j]));
                                        if (maxScore < CONF_THRESHOLD) continue;

                                        int classId = 0;
                                        if (maxScore == class1Array[j]) classId = 1;
                                        else if (maxScore == class2Array[j]) classId = 2;

                                        rawDetections.add(new Detection(
                                                xCenterArray[j] * frameWidth,
                                                yCenterArray[j] * frameHeight,
                                                widthArray[j] * frameWidth,
                                                heightArray[j] * frameHeight,
                                                maxScore,
                                                classId
                                        ));
                                    }
                                    return nms(rawDetections);
                                }

        
                                private List nms(List detections) {
                                    List results = new ArrayList<>(10);
                                    detections.sort((d1, d2) -> Float.compare(d2.confidence, d1.confidence));

                                    while (!detections.isEmpty()) {
                                        Detection best = detections.remove(0);
                                        results.add(best);
                                        detections.removeIf(d -> iou(best, d) > IOU_THRESHOLD);
                                    }
                                    return results;
                                }

                                private float iou(Detection a, Detection b) {
                                    float intersectionLeft = Math.max(a.x1, b.x1);
                                    float intersectionTop = Math.max(a.y1, b.y1);
                                    float intersectionRight = Math.min(a.x2, b.x2);
                                    float intersectionBottom = Math.min(a.y2, b.y2);

                                    if (intersectionRight < intersectionLeft || intersectionBottom < intersectionTop)
                                        return 0.0f;

                                    float intersectionArea = (intersectionRight - intersectionLeft) * (intersectionBottom - intersectionTop);
                                    float areaA = a.width * a.height;
                                    float areaB = b.width * b.height;

                                    return intersectionArea / (areaA + areaB - intersectionArea);
                                }

                                @Override
                                public void onDrawFrame(Canvas canvas, int width, int height, float scale, float density, Object tag) {}

                                public List getLatestDetections() {
                                    synchronized (syncLock) {
                                        return new ArrayList<>(detections);
                                    }
                                }

                                public void close() {
                                    tflite.close();
                                    resizedMat.release();
                                    rgbMat.release();
                                }
                            }

                            static class Detection {
                                final float x1, y1, x2, y2;
                                final float confidence;
                                final int classId;
                                public final float width;
                                public final float height;

                                public Detection(float cx, float cy, float w, float h, float conf, int cls) {
                                    width = w;
                                    height = h;
                                    x1 = cx - width/2;
                                    y1 = cy - height/2;
                                    x2 = cx + width/2;
                                    y2 = cy + height/2;
                                    confidence = conf;
                                    classId = cls;
                                }

                                String className() {
                                    switch (classId) {
                                        case 0: return "Yellow";
                                        case 1: return "Blue";
                                        case 2: return "Red";
                                        default: return "Unknown";
                                    }
                                }
                            }
                        }
                                            
This code implements an AI processing system for object detection using a YOLOv8 model in an FTC competition.
  • AI Vision is a TeleOp that uses the robot's camera to detect objects using a TensorFlow Lite model (best_float32.tflite). Frame processing is handled by the YoloProcessor class, which preprocesses images and runs the inference model.
  • AI Processing: The model receives a frame from the camera, resizes and normalizes it, then returns object detections. These are filtered by confidence and IOU thresholds to remove irrelevant results.
  • Intake Control: We added an object to the IntakeControl class, allowing the AI system to control the object collection mechanism based on the detections made.
  • Visualization and Telemetry: The code displays information about detected objects in telemetry, such as dimensions, class, and angle.
  • Setup
    2D Sample Detection
    3D Sample Detection
    Training ML
    Examples