diff --git a/FtcRobotController/build.gradle b/FtcRobotController/build.gradle index e25651f..497581d 100644 --- a/FtcRobotController/build.gradle +++ b/FtcRobotController/build.gradle @@ -6,7 +6,9 @@ import java.text.SimpleDateFormat apply plugin: 'com.android.library' android { - + buildFeatures{ + buildConfig = true; + } defaultConfig { minSdkVersion 24 //noinspection ExpiredTargetSdkVersion diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/opmodes/FreeSight.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/opmodes/FreeSight.java new file mode 100644 index 0000000..f712d51 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/opmodes/FreeSight.java @@ -0,0 +1,46 @@ +package org.firstinspires.ftc.teamcode.freesight.opmodes; + +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; + +import org.firstinspires.ftc.robotcore.external.Telemetry; +import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; +import org.firstinspires.ftc.teamcode.freesight.vision.FreeSightPipeline; +import org.openftc.easyopencv.*; + +public class FreeSight { + private FreeSightPipeline pipe; + private final OpenCvWebcam web; + private final Telemetry telemetry; + + public FreeSight(LinearOpMode op) + { + web = OpenCvCameraFactory.getInstance().createWebcam( + op.hardwareMap.get(WebcamName.class,"webcam") + ); + telemetry = op.telemetry; + } + + public void findStuff() + { + pipe = new FreeSightPipeline(); + + web.openCameraDeviceAsync(new OpenCvCamera.AsyncCameraOpenListener() { + @Override + public void onOpened() { + web.setPipeline(pipe); + web.startStreaming(800, 448, OpenCvCameraRotation.UPRIGHT); + } + + @Override + public void onError(int errorCode) { + telemetry.addData("Error:", "Camera produced error code: " + errorCode); + stop(); + } + }); + } + + public void stop() + { + web.stopStreaming(); + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/FreeSightPipeline.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/FreeSightPipeline.java new file mode 100644 index 0000000..17f1c21 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/FreeSightPipeline.java @@ -0,0 +1,148 @@ +package org.firstinspires.ftc.teamcode.freesight.vision; + +//import com.acmerobotics.dashboard.config.Config; + +import org.firstinspires.ftc.robotcore.external.Telemetry; +import org.firstinspires.ftc.robotcore.internal.opmode.TelemetryImpl; +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.MatOfRect; +import org.opencv.core.Rect; +import org.opencv.core.Scalar; +import org.opencv.imgproc.Imgproc; +import org.openftc.easyopencv.OpenCvPipeline; + +import java.util.ArrayList; + + +//@Config +public class FreeSightPipeline extends OpenCvPipeline { + + public enum Prop + { + BLUE,ORANGE,NONE + } + public enum Side + { + LEFT,RIGHT,MIDDLE + } + ArrayList frameList = new ArrayList<>(); + public Side positionState; + + public Scalar lowHSV = new Scalar(0,0,0); + public Scalar highHSV = new Scalar(0,0,0); + public Scalar outline = new Scalar(0,0,0); + public Prop colorState = Prop.NONE; + + /** + * @param input the frame to be manipulated + * @return The altered matrix + */ + @Override + public Mat processFrame(Mat input) { + int width = input.width(); + int height = input.height(); + + Mat mat = new Mat(); + + Imgproc.cvtColor(input, mat, Imgproc.COLOR_RGB2HSV); + if(mat.empty()) return input; + + /* + * BLUE + * Scalar lowHSV = new Scalar(55.3, 62.3, 53.8); + * Scalar highHSV = new Scalar(213.9, 240.8, 255); + */ + if(colorState == Prop.BLUE) + { + lowHSV = new Scalar(55.3, 62.3, 53.8); + highHSV = new Scalar(213.9, 240.8, 255); + } + else if(colorState == Prop.ORANGE) + { + lowHSV = new Scalar(0,106.3,198.3); + highHSV = new Scalar(14.2, 255, 255); + } + Mat threshold = new Mat(); + + Core.inRange(mat, lowHSV, highHSV, threshold); + + Mat masked = new Mat(); + + + Core.bitwise_and(mat, mat, masked, threshold); + + Scalar avg = Core.mean(masked, threshold); + Mat scaledMask = new Mat(); + + masked.convertTo(scaledMask, -1, 150/avg.val[1],0); + + Mat scaledThresh = new Mat(); + double strictLowS; + //you probably want to tune this + if(colorState == Prop.BLUE) + strictLowS = 62.3; + else + strictLowS = 86.4; // orange + Scalar strictLowHSV = new Scalar(0, strictLowS, 0); //strict lower bound HSV for yellow + Scalar strictHighHSV = new Scalar(255, 255, 255); //strict higher bound HSV for yellow + //apply strict HSV filter onto scaledMask to get rid of any yellow other than pole + Core.inRange(scaledMask, strictLowHSV, strictHighHSV, scaledThresh); + + //contours, apply post processing to information + ArrayList contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + //find contours, input scaledThresh because it has hard edges + Imgproc.findContours(scaledThresh, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE); + + + + int index = 0; + int area = 0; + for (int i = 0; i < contours.size(); i++) + { + MatOfPoint bar = contours.get(i); + int foo = bar.width() * bar.height(); + if(foo > area) + { + index = i; + area = foo; + } + } + + MatOfPoint contour = contours.get(index); + + Rect boundingRect = Imgproc.boundingRect(contour); + int min_x = boundingRect.x; + int max_x = boundingRect.x - boundingRect.width; + int min_y = boundingRect.y; + int max_y = boundingRect.y - boundingRect.height; + + // center is ( x + w ) / 2 + + Imgproc.rectangle( + threshold, + new Rect( + min_x, + min_y, + (max_x + min_x), + (max_y + min_y)), + outline + ); + + //list of frames to reduce inconsistency, not too many so that it is still real-time, change the number from 5 if you want + if (frameList.size() > 5) { + frameList.remove(0); + } + + //releasing for ram related reasons + input.release(); + scaledThresh.release(); + scaledMask.release(); + mat.release(); + masked.release(); + return threshold; + + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/eocvsim_workspace.json b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/eocvsim_workspace.json new file mode 100644 index 0000000..00e3b1a --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/freesight/vision/eocvsim_workspace.json @@ -0,0 +1,7 @@ +{ + "sourcesPath": ".", + "resourcesPath": ".", + "excludedPaths": [], + "excludedFileExtensions": [], + "eocvSimVersion": "3.5.2" +} \ No newline at end of file diff --git a/build.dependencies.gradle b/build.dependencies.gradle index 9775838..3a6498d 100644 --- a/build.dependencies.gradle +++ b/build.dependencies.gradle @@ -1,6 +1,7 @@ repositories { mavenCentral() google() // Needed for androidx + maven { url = 'https://maven.brott.dev/' } } dependencies { @@ -17,5 +18,7 @@ dependencies { implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.3' runtimeOnly 'org.tensorflow:tensorflow-lite:2.12.0' implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.acmerobotics.dashboard:dashboard:0.4.12' + implementation 'org.openftc:easyopencv:1.7.0' } diff --git a/build.gradle b/build.gradle index 8969a41..a11614b 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { } dependencies { // Note for FTC Teams: Do not modify this yourself. - classpath 'com.android.tools.build:gradle:7.2.0' + classpath 'com.android.tools.build:gradle:8.1.1' } }