Skip to content
CrocoDocs
Starter GuideProgrammingEngineeringDesignPortfolio
Documentation

Introduction

IntroductionBIOBUZZ game overview

Getting started

Getting startedBlocksOnBot JavaAndroid StudioYour first OpModeJava basicsMotors and servosNonblocking codeDebugging robot code

Control systems

Control systemsJoystick mappingField-centric mecanum drivePID controlFeedforwardFlywheel velocity controlSystem identificationMotion profilingKalman filterLow-pass filter

Autonomous

AutonomousTimed and encoder movementOdometryLocalization troubleshootingMotion planningReliable autonomous sequencesPure PursuitSensor fusionAuto to TeleOp handoff

Season topics

Season topicsProjectile mathematicsTurret aimingShooting on the move

Code practices

Code practicesNaming conventionsCode organizationLoop timing and bulk readsFormattingComments and documentationTeam collaboration

Libraries

LibrariesNextFTCFTCLibSolversLibPedro PathingRoad RunnerFTC DashboardMercurial v2Mercurial v1PanelsSloth

Community software

Community softwareBlaze FTCOpenLoopHive Vision

Sensors and vision

Vision overviewVision basicsLimelight 3A
EasyOpenCV basics
OpenCV pipelines
VisionBench
Starter Guide
Engineering
Design
Portfolio
Appearance
EasyOpenCV

EasyOpenCV basics

Open a camera and understand how a custom OpenCV pipeline receives frames

The SDK already includes EasyOpenCV for supported SDK versions (SDK 8.2 and later). For that setup, you do not need to add a separate Maven repository, download a native library, or copy a .so file to the . Those instructions appear in older tutorials and are not the normal setup for a current FTC project.

EasyOpenCV gives your a camera stream and a place to run your own OpenCV code. Choose it when you need a custom pipeline. If the built-in FTC Color Locator or AprilTag processor already answers your question, begin with VisionPortal; it requires less custom processing code.

Camera lifecycle

  1. Your OpMode finds a camera by the name in Configuration.
  2. EasyOpenCV opens that camera asynchronously. “Asynchronously” means the open result arrives later in a callback, so the robot loop does not wait for the camera to open.
  3. You attach an OpenCvPipeline before starting the stream.
  4. EasyOpenCV passes each camera frame to the pipeline's processFrame method.
  5. When the OpMode ends, stop the stream and close the camera.

OpenCV stages on an official BIOBUZZ Pollen photo: source image, yellow HSV mask, cleaned candidate, and measured blob.

The mask is a learning example from a controlled product photo; tune your pipeline against your live camera image.

The vision illustration shows the stages after a frame reaches your pipeline. EasyOpenCV itself manages camera frames and pipeline calls; it does not choose what object to detect. Your OpenCV code does that.

Webcam configuration

In the configuration, add the webcam and give it a simple name such as Webcam 1. That name is part of your program's hardware configuration. If your code asks for Webcam 1 but the configured device is named Front Camera, hardwareMap cannot find it.

Connect the camera to the Control Hub or Robot Controller device, then use a preview sample to confirm that the image is live and correctly rotated before you write detection logic.

Camera setup

This short setup is the part that belongs in your LinearOpMode. PollenTargetPipeline is the small custom class you will build in Writing Pipelines.

int monitorViewId = hardwareMap.appContext.getResources().getIdentifier(
    "cameraMonitorViewId", "id", hardwareMap.appContext.getPackageName());

WebcamName cameraName = hardwareMap.get(WebcamName.class, "Webcam 1");
OpenCvCamera camera = OpenCvCameraFactory.getInstance()
    .createWebcam(cameraName, monitorViewId);
PollenTargetPipeline pipeline = new PollenTargetPipeline();
camera.setPipeline(pipeline);
val monitorViewId = hardwareMap.appContext.resources.getIdentifier(
    "cameraMonitorViewId", "id", hardwareMap.appContext.packageName
)

val cameraName = hardwareMap.get(WebcamName::class.java, "Webcam 1")
val camera = OpenCvCameraFactory.getInstance()
    .createWebcam(cameraName, monitorViewId)
val pipeline = PollenTargetPipeline()
camera.setPipeline(pipeline)

The first lines find a local preview container on the Robot Controller Android screen. The Camera Stream is a separate stream; it does not require that local view. The hardwareMap.get(...) line connects your variable to the named camera. setPipeline(...) tells EasyOpenCV which class should process the images.

Use the OpenCvCameraFactory and callback signatures from the sample bundled with your installed FTC SDK. EasyOpenCV and SDK APIs have changed over time; the SDK sample is the version-matched reference.

Asynchronous opening

Declare private volatile String cameraError = ""; as a Java OpMode field, or @Volatile private var cameraError = "" in Kotlin. In the OpMode loop, display it with telemetry.addData("Camera error", cameraError). The callback writes it from another thread.

Opening a camera can take time or fail. EasyOpenCV reports success in onOpened() and failure in onError(). Start streaming only after success:

camera.openCameraDeviceAsync(new OpenCvCamera.AsyncCameraOpenListener() {
    @Override
    public void onOpened() {
        camera.startStreaming(640, 480, OpenCvCameraRotation.UPRIGHT);
    }

    @Override
    public void onError(int errorCode) {
        // Save the error for telemetry in the OpMode loop.
        cameraError = "Camera open failed: " + errorCode;
    }
});
camera.openCameraDeviceAsync(object : OpenCvCamera.AsyncCameraOpenListener {
    override fun onOpened() {
        camera.startStreaming(640, 480, OpenCvCameraRotation.UPRIGHT)
    }

    override fun onError(errorCode: Int) {
        // Save the error for telemetry in the OpMode loop.
        cameraError = "Camera open failed: $errorCode"
    }
})

The 640 × 480 size and UPRIGHT rotation are examples, not universal settings. Start with a resolution supported by your camera; more pixels can take more processing time. Do not try to start streaming inside the OpMode before onOpened() runs.

Shutdown

After starting the stream, the OpMode must continue running while you read pipeline results. Keep the result visible in telemetry during the first test. Use try/finally around the loop. With EasyOpenCV 1.7.3, call camera.closeCameraDevice() in finally, then pipeline.release(). This synchronous close stops processing before returning. The pipeline in Writing Pipelines releases its own working Mats; it leaves the camera-owned input alone. This differs from the asynchronous VisionPortal.close() wrapper.

Do not run a based on an untested camera result. First confirm the preview, then confirm that the pipeline result changes as you move a target in front of the camera.

Pixel channel order

EasyOpenCV supplies pipeline frames in RGBA order. Some desktop OpenCV examples use BGR instead. When converting a frame to HSV, use the conversion code that matches the frame you actually receive, such as COLOR_RGB2HSV (which accepts RGB or RGBA input and ignores alpha); copying COLOR_BGR2HSV from a desktop tutorial can produce incorrect colors.

You will apply that conversion one step at a time in Writing Pipelines.

Troubleshooting

  • Confirm that the configured camera name exactly matches the name in hardwareMap.get(...).
  • Check the cable, adapter, and USB connection.
  • Confirm that the camera is not already in use by another OpMode or process.
  • Read onError telemetry and the Robot Controller log.
  • Try the version-matched FTC/EasyOpenCV sample before changing resolution or adding image processing.

Sources

  • OpenFTC EasyOpenCV repository and installation notes
  • OpenFTC EasyOpenCV camera initialization guide
  • OpenFTC EasyOpenCV pipeline guide
  • FTC VisionPortal overview
  • AndyMark: BIOBUZZ scoring elements — source photo

Limelight 3A

Read a configured pipeline, reject stale results, and separate target aiming from field localization

OpenCV pipelines

Build a small color mask step by step with EasyOpenCV

On this page

Camera lifecycleWebcam configurationCamera setupAsynchronous openingShutdownPixel channel orderTroubleshootingSources