
Bindings for OpenCV 5.x exposing a thin C ABI, exception-safe native calls, embedded native libs with automatic loader; Mat operators, image I/O, DNN and image-processing helpers.
Kotlin Multiplatform bindings for OpenCV (5.x, Android SDK API surface: core / imgproc / imgcodecs / video / videoio / objdetect / dnn / photo / calib / features2d / stereo / ptcloud).
libopencv_jni) is built from the OpenCV submodule and shipped as a classpath resource per OS/arch; NativeLoader extracts and loads the matching one at runtime.Both platforms call the same thin C ABI (native/, cvk_ prefix) that wraps the C++ API, so behavior is identical everywhere. All native calls are exception-safe: failures surface as OpenCVException (with cv::Exception::what() text) or nullable returns.
| Target | Native lib | JVM lib |
|---|---|---|
| macOS arm64 / x64 | klib-embedded static |
darwin-aarch64 / darwin-x86_64
|
| iOS (sim) arm64 / x64, device arm64 | klib-embedded static | — |
| tvOS (sim) arm64, device arm64 | klib-embedded static | — |
| watchOS (sim) arm64, device arm64 | klib-embedded static | — |
| Linux x64 / arm64 | klib-embedded static |
linux-x86_64 / linux-aarch64
|
| Windows x64 | klib-embedded static (mingw) | windows-x86_64 |
| Android (native) arm32 / arm64 / x86 / x86_64 | klib-embedded static | — |
| Android (JVM) armv7 / armv8 / x86 / x86_64 | — | android-* |
import cn.enaium.opencv.*
fun main() {
println(opencvVersion)
mat(rows = 2, cols = 2, type = MatType.CV_32FC1, fill = Scalar.all(1.5)).use { a ->
eye(2, 2, MatType.CV_32FC1).use { identity ->
(a + identity).use { sum -> println(sum[0, 0]) } // 2.5
}
(a * 3.0).use { println(it[0, 0]) } // 4.5
}
imread("input.png")?.use { image ->
val gray = image.cvtColor(ColorConversionCodes.BGR2GRAY)
val edges = gray.canny(threshold1 = 50.0, threshold2 = 150.0)
imwrite("edges.png", edges)
gray.close()
edges.close()
}
}Gradle:
dependencies {
implementation("cn.enaium.opencv:opencv-kmp:<version>")
}The JVM artifact bundles all nine JNI libraries (~9 × a few MB); Android apps get the right one automatically.
Mat: + - * / with another Mat or a Scalar, indexed get/set, times(scale), broadcast + - / Double, abs()/squared(), infix bitwiseAnd/Or/Xor, diff, rsub.Scalar + - * / Scalar, * / + - Double, unaryMinus, infix dist.toGray(), toFloat32(), normalize01(), mirror(), rotate90/180/270(), pixels: ByteArray, shape, fill { }.mat(), zeros(), ones(), eye(), imread(), imwrite(), imencode(), imdecode().Requirements: JDK 21+, CMake ≥3.16, a C++17 compiler; the OpenCV sources are a git submodule (git submodule update --init --recursive). Cross builds additionally need:
aarch64-linux-gnu-gcc
x86_64-w64-mingw32-gcc
sdk.dir in local.properties, $ANDROID_HOME, or ~/Android/Sdk)macOS klibs and the darwin JNI artifacts are built on macOS hosts; the windows-x86_64 JNI DLL is built on Windows hosts (MinGW via choco works).
# build + test everything buildable on this host
./gradlew :opencv-kmp:jvmTest :opencv-kmp:linuxX64Test # platform tests
./gradlew :examples:basic:jvmRun # JVM demo
./gradlew :examples:basic:runDebugExecutableLinuxX64 # native demo
# publish local-platform artifacts to mavenLocal
./gradlew :opencv-kmp:publishToMavenLocal :jni-jvm-linux-x86_64:publishToMavenLocalApple mobile targets (iOS/tvOS/watchOS, simulator + device) compile but are not runnable from the CLI; the simulator suites run under iosSimulatorArm64Test / tvosSimulatorArm64Test / watchosSimulatorArm64Test (they need a booted simulator). The linuxArm64 klib is cross-compiled from x64 hosts, but Kotlin/Native has no linux-aarch64 host distribution in this Kotlin version, so there is no host that can run the linuxArm64 tests; the arm64 Linux JNI artifact is covered by the CI publish job instead.
Each Kotlin/Native target drives its own CMake configuration (configureNative_<target> / buildNative_<target>) that compiles OpenCV statically (BUILD_LIST=core,imgproc,imgcodecs,video,videoio,objdetect,dnn,photo,calib plus cvv, ptcloud-related modules, bundled zlib/libpng/libjpeg-turbo, no network downloads) plus the cvk shim, merges all archives into one libopencv_kmp.a, and embeds it into the klib.
OpenCV submodule patches. The vendored OpenCV tree ships with two patches applied automatically by
native/CMakeLists.txton every configure (idempotent,git apply --reverse --checkfirst):native/cmake/mlas-subproject.patch(3rdparty/mlas resolve paths underadd_subdirectoryand Apple architecture detection fromCMAKE_OSX_ARCHITECTURES) andnative/cmake/imgcodecs-appletv.patch(exclude macOS-only imgcodecs sources on tvOS/watchOS). Keep the submodule checkout pristine; the build applies what it needs.
Two manually-dispatched workflows (Actions tab):
build.gradle.kts; nothing to input.Required secrets for Publish: MAVEN_CENTRAL_USERNAME, MAVEN_CENTRAL_PASSWORD, SIGNING_KEY (base64 .gpg), SIGNING_KEY_ID, SIGNING_PASSWORD.
MIT — see LICENSE. OpenCV itself stays under its Apache 2.0 license.
Kotlin Multiplatform bindings for OpenCV (5.x, Android SDK API surface: core / imgproc / imgcodecs / video / videoio / objdetect / dnn / photo / calib / features2d / stereo / ptcloud).
libopencv_jni) is built from the OpenCV submodule and shipped as a classpath resource per OS/arch; NativeLoader extracts and loads the matching one at runtime.Both platforms call the same thin C ABI (native/, cvk_ prefix) that wraps the C++ API, so behavior is identical everywhere. All native calls are exception-safe: failures surface as OpenCVException (with cv::Exception::what() text) or nullable returns.
| Target | Native lib | JVM lib |
|---|---|---|
| macOS arm64 / x64 | klib-embedded static |
darwin-aarch64 / darwin-x86_64
|
| iOS (sim) arm64 / x64, device arm64 | klib-embedded static | — |
| tvOS (sim) arm64, device arm64 | klib-embedded static | — |
| watchOS (sim) arm64, device arm64 | klib-embedded static | — |
| Linux x64 / arm64 | klib-embedded static |
linux-x86_64 / linux-aarch64
|
| Windows x64 | klib-embedded static (mingw) | windows-x86_64 |
| Android (native) arm32 / arm64 / x86 / x86_64 | klib-embedded static | — |
| Android (JVM) armv7 / armv8 / x86 / x86_64 | — | android-* |
import cn.enaium.opencv.*
fun main() {
println(opencvVersion)
mat(rows = 2, cols = 2, type = MatType.CV_32FC1, fill = Scalar.all(1.5)).use { a ->
eye(2, 2, MatType.CV_32FC1).use { identity ->
(a + identity).use { sum -> println(sum[0, 0]) } // 2.5
}
(a * 3.0).use { println(it[0, 0]) } // 4.5
}
imread("input.png")?.use { image ->
val gray = image.cvtColor(ColorConversionCodes.BGR2GRAY)
val edges = gray.canny(threshold1 = 50.0, threshold2 = 150.0)
imwrite("edges.png", edges)
gray.close()
edges.close()
}
}Gradle:
dependencies {
implementation("cn.enaium.opencv:opencv-kmp:<version>")
}The JVM artifact bundles all nine JNI libraries (~9 × a few MB); Android apps get the right one automatically.
Mat: + - * / with another Mat or a Scalar, indexed get/set, times(scale), broadcast + - / Double, abs()/squared(), infix bitwiseAnd/Or/Xor, diff, rsub.Scalar + - * / Scalar, * / + - Double, unaryMinus, infix dist.toGray(), toFloat32(), normalize01(), mirror(), rotate90/180/270(), pixels: ByteArray, shape, fill { }.mat(), zeros(), ones(), eye(), imread(), imwrite(), imencode(), imdecode().Requirements: JDK 21+, CMake ≥3.16, a C++17 compiler; the OpenCV sources are a git submodule (git submodule update --init --recursive). Cross builds additionally need:
aarch64-linux-gnu-gcc
x86_64-w64-mingw32-gcc
sdk.dir in local.properties, $ANDROID_HOME, or ~/Android/Sdk)macOS klibs and the darwin JNI artifacts are built on macOS hosts; the windows-x86_64 JNI DLL is built on Windows hosts (MinGW via choco works).
# build + test everything buildable on this host
./gradlew :opencv-kmp:jvmTest :opencv-kmp:linuxX64Test # platform tests
./gradlew :examples:basic:jvmRun # JVM demo
./gradlew :examples:basic:runDebugExecutableLinuxX64 # native demo
# publish local-platform artifacts to mavenLocal
./gradlew :opencv-kmp:publishToMavenLocal :jni-jvm-linux-x86_64:publishToMavenLocalApple mobile targets (iOS/tvOS/watchOS, simulator + device) compile but are not runnable from the CLI; the simulator suites run under iosSimulatorArm64Test / tvosSimulatorArm64Test / watchosSimulatorArm64Test (they need a booted simulator). The linuxArm64 klib is cross-compiled from x64 hosts, but Kotlin/Native has no linux-aarch64 host distribution in this Kotlin version, so there is no host that can run the linuxArm64 tests; the arm64 Linux JNI artifact is covered by the CI publish job instead.
Each Kotlin/Native target drives its own CMake configuration (configureNative_<target> / buildNative_<target>) that compiles OpenCV statically (BUILD_LIST=core,imgproc,imgcodecs,video,videoio,objdetect,dnn,photo,calib plus cvv, ptcloud-related modules, bundled zlib/libpng/libjpeg-turbo, no network downloads) plus the cvk shim, merges all archives into one libopencv_kmp.a, and embeds it into the klib.
OpenCV submodule patches. The vendored OpenCV tree ships with two patches applied automatically by
native/CMakeLists.txton every configure (idempotent,git apply --reverse --checkfirst):native/cmake/mlas-subproject.patch(3rdparty/mlas resolve paths underadd_subdirectoryand Apple architecture detection fromCMAKE_OSX_ARCHITECTURES) andnative/cmake/imgcodecs-appletv.patch(exclude macOS-only imgcodecs sources on tvOS/watchOS). Keep the submodule checkout pristine; the build applies what it needs.
Two manually-dispatched workflows (Actions tab):
build.gradle.kts; nothing to input.Required secrets for Publish: MAVEN_CENTRAL_USERNAME, MAVEN_CENTRAL_PASSWORD, SIGNING_KEY (base64 .gpg), SIGNING_KEY_ID, SIGNING_PASSWORD.
MIT — see LICENSE. OpenCV itself stays under its Apache 2.0 license.