Hygiene for JavaCV + DJL vision pipelines on Kotlin/JVM: camera discovery and probing, frame-skip policy for heavy inference, downscale-before-detection. Replaces the Python jbaruch/vision-pipeline-foundations tile.
94
93%
Does it follow best practices?
Impact
99%
1.86xAverage score across 3 eval scenarios
Passed
No known issues
OpenCVFrameGrabber(0) on macOS frequently opens a virtual camera instead of the physical webcam. The grabber succeeds, frames come through, and detection runs against… nothing. This skill is the probe pattern that avoids that.
import org.bytedeco.javacv.OpenCVFrameGrabber
import org.bytedeco.javacv.OpenCVFrameConverter
import org.bytedeco.opencv.global.opencv_core.mean
import org.bytedeco.opencv.opencv_core.Mat
private const val MIN_BRIGHTNESS = 10.0
private const val WARM_UP_MS = 500L
private const val MAX_PROBE_INDEX = 5
data class CameraInfo(val index: Int, val width: Int, val height: Int, val meanBrightness: Double)
fun probeCameras(): List<CameraInfo> {
val converter = OpenCVFrameConverter.ToMat()
val results = mutableListOf<CameraInfo>()
for (i in 0..MAX_PROBE_INDEX) {
val grabber = OpenCVFrameGrabber(i)
try {
grabber.start()
Thread.sleep(WARM_UP_MS) // crucial on macOS — first frames are black
val frame = grabber.grab() ?: continue
val mat = converter.convert(frame) ?: continue
val brightness = mean(mat).get(0L)
results += CameraInfo(i, mat.cols(), mat.rows(), brightness)
} catch (_: Throwable) {
// index not present
} finally {
runCatching { grabber.stop() }
}
}
return results
}
fun selectRealCamera(): Int {
val cams = probeCameras()
// Prefer the first index whose probe frame is bright enough
val real = cams.firstOrNull { it.meanBrightness >= MIN_BRIGHTNESS }
?: error("No usable camera found. Probed: $cams")
return real.index
}A Mat mean below 10 (on a 0..255 BGR scale) is essentially black:
Real webcams pointed at a room average 70–150. Even a dark room registers > 20. A < 10 threshold is conservative and catches the common bad cases.
AVFoundation error: "not authorized to capture video (status 0)" — TCC denied. The user has to approve via System Settings → Privacy & Security → Camera, then re-run.system_profiler SPCameraDataType from the shell.class Camera(private val width: Int = 1280, private val height: Int = 720) : AutoCloseable {
private val converter = OpenCVFrameConverter.ToMat()
private val grabber: OpenCVFrameGrabber
init {
val idx = System.getenv("CAM")?.toIntOrNull() ?: selectRealCamera()
grabber = OpenCVFrameGrabber(idx).apply {
imageWidth = width
imageHeight = height
start()
}
Thread.sleep(WARM_UP_MS)
}
fun grab(): Mat? = converter.convert(grabber.grab() ?: return null)
override fun close() {
runCatching { grabber.stop() }
}
}OpenCVFrameGrabber(0).start() without probing — Insta360 / Continuity Camera / Snap silently win.start() as "the camera works" — macOS will hand you a working virtual camera that delivers black frames.imageWidth = 1920 and assuming the camera supports it — JavaCV falls back to the closest mode, often silently. Probe what you actually got: grabber.imageWidth.# List physical cameras macOS knows about:
system_profiler SPCameraDataType
# Probe via the Kotlin pipeline:
CAM= ./gradlew run # forces probe (env unset)
CAM=1 ./gradlew run # forces a specific index