Skip to content
imaged

Object detection

Run detection on camera frames and read boxes in image coordinates.

Use your own .slab model and a runtime license. Model files carry their input sizes, preprocessing, labels, and backend preferences.

CameraDetector.kt

Kotlin setup →

Run inference off the main thread.

// Live object detection on camera frames.
//
// With CameraX, ask ImageAnalysis for RGBA frames and pass the plane:
//
//     val analysis = ImageAnalysis.Builder()
//         .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
//         .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
//         .build()
//     analysis.setAnalyzer(executor) { image ->
//         val plane = image.planes[0]
//         val boxes = detector.detect(plane.buffer, image.width, image.height, plane.rowStride)
//         image.close()
//         // draw boxes: they are in the camera frame's pixels
//     }

import dev.slab.Slab
import dev.slab.SlabConfig
import dev.slab.SlabFrame
import dev.slab.SlabInput
import dev.slab.SlabOutput
import dev.slab.SlabSession
import java.nio.ByteBuffer

class CameraDetector(config: SlabConfig, modelPath: String) : AutoCloseable {
    private val session = SlabSession(config).setWarmup(true).also { it.open(modelPath) }
    private val input = SlabInput()
    private val output = SlabOutput()

    /** Detects objects in one RGBA frame; called on the analysis thread. */
    fun detect(rgba: ByteBuffer, width: Int, height: Int, rowStride: Int): List<SlabOutput.Box> {
        // Slab copies the frame and prepares it the way the model expects.
        SlabFrame.fromBuffer(rgba, width, height, Slab.PIXEL_RGBA8, rowStride, 1).use { frame ->
            input.clear().setFrame(frame)
            session.run(input, output)
        }
        return output.boxes(0.4f, 0.45f, 100)
    }

    val lastLatencyMs: Double get() = output.latencyMs()

    override fun close() {
        input.close()
        output.close()
        session.close()
    }
}