OpenCV 5 for Unity through a project-owned C ABI, distributed as a reproducible native UPM package.
Status: v0.4.0 is the newest published release (2026-09-12). Everything below describes the repository, which matches that release apart from documentation edited after the tag was cut. v0.4.0 is the first release to carry the September 2026 API expansion and all of M7. The one number that is generated at both ends:
docs/api-map.mdcounted 27 public C ABI functions at v0.3.0 and 57 at v0.4.0. On the C# sideCvAruco,CvCoreOps,CvStereo,CvDnnandRenderTextureConverterdid not exist at v0.3.0 at all and are in the package you download now; if you are still on v0.3.0, settingOCVU_PROFILE_DNNthere defines a symbol with nothing behind it. What has actually shipped is recorded in the "配布" sections of the roadmap — that, not this paragraph, is the source of truth for it. It carries six platforms — Windows x64, macOS arm64, Linux x64, Android arm64-v8a, iOS arm64 and Web/WebGL — and is the first release with opt-in ONNX inference (dnn), ArUco markers, pose estimation, stereo disparity and theRenderTextureintegration; six platforms, the generated binding layer and camera calibration first shipped in v0.3.0. Every platform is built, tested and packaged by CI; Unity itself exercises the plugin on Mono (EditMode), a real IL2CPP player, and a headless browser. Some honest limits. Android and iOS have never been run on a device — CI cross-compiles them and inspects the artifacts, but no phone has loaded these binaries. Web has no PNG:imgcodecsthere decodes and encodes JPEG only (see below), and the browser it was driven in is one headless Chromium on Linux. Unity has never been run on macOS at all, though its plugin settings are verified by asking Unity itself on other systems.dnnhas never been run on a device either, and its inference speed has not been measured. Two things changed for the worse in v0.4.0 and are worth knowing before you upgrade: PNG lost its ARM acceleration on Android, iOS and macOS arm64 (see Platforms), and the Android.sonow ships stripped of its symbol table, so a native crash on Android cannot be symbolicated — no debug package is published anywhere. The public C ABI is deliberately narrow, because the point was getting ownership, stride, error handling, IL2CPP and platform gating right rather than covering surface area. If you are on Linux, take v0.1.1 or later: the Linux plugin in v0.1.0 required glibc 2.38 and would not load on Ubuntu 22.04.
A Unity-first integration of OpenCV 5, built around a narrow C ABI that this project owns and versions itself — rather than a repackaging of an existing .NET wrapper.
- OpenCV 5 first. Designed against the 5.x module layout, not ported from a 4.x wrapper.
- Unity first. IL2CPP, AOT, iOS static linking, Android and Web are design constraints, not afterthoughts.
- A project-owned C ABI. No C++ or STL types cross the boundary. Opaque handles, fixed-size types, explicit ownership, exceptions converted to status codes.
- Reproducible binaries. Pinned OpenCV tag, build options, toolchain and hashes, regenerated from CI.
- Apache-2.0.
Reimplementing OpenCV algorithms. Hand-wrapping the entire OpenCV API up front. Duplicating OpenCvSharp's managed API for compatibility. Shipping one large binary with every codec and GPU backend enabled — imgcodecs is linked, but only with PNG and JPEG; TIFF, WebP, OpenEXR, JPEG 2000 and the rest are off in the build, as are video I/O (FFmpeg, GStreamer) and every GPU backend. dnn is the exception, and it is deliberate: it is always in the native binary, and what you opt into is the C# side (see Optional profiles: dnn below).
Shipping today (all six, since v0.3.0 on 2026-09-04): Windows x64, macOS arm64, Linux x64, Android arm64-v8a, iOS arm64 and Web (WebGL). Each is built, tested and packaged by CI, and the Linux and Windows plugins are exercised by Unity itself (EditMode on Mono and a real IL2CPP player).
"Shipped" is not "verified on a device." What each platform has actually been through differs, and the paragraphs below say so one by one.
The macOS plugin is packaged, and Unity itself now reads its Plugin Import Settings —
an EditMode test asks Unity's own PluginImporter how it interpreted every .meta
file, with every binary present. But the macOS library has never been
loaded, and Unity has never been run on macOS at all. Treat that platform as built and
gated rather than exercised.
Shipped but never run on a device: Android arm64-v8a and iOS arm64. CI cross-compiles
both, checks the Android .so for 16 KB page alignment against the real ELF program
headers, and confirms the iOS .a actually bundles the OpenCV symbols this plugin
references. None of that is the same as running on a phone. No Android or iOS device
has ever loaded these binaries. They have shipped since v0.3.0 and are in v0.4.0, so they reach users today;
treat them as unverified until someone runs
the device checklist.
Web/Wasm is in the tree and actually runs in a browser — a headless Chromium loads a
real WebGL player and drives the same checks EditMode and the IL2CPP player run — the same
functions, not a copy. One of them takes a different path on Web: the encode/decode check
uses JPEG instead of PNG and therefore cannot assert pixel-for-pixel equality. It has
one limitation the other platforms do not have: imgcodecs decodes and encodes JPEG
only, not PNG. Unity's WebGL support ships its own libpng; bundling OpenCV's copy makes
the player fail to link on duplicate symbols, and leaving it out makes OpenCV's PNG code
fail to link on undefined ones. Neither extreme works, so the Web build has PNG turned
off. Every other platform has both.
PNG decoding lost its ARM acceleration on Android, iOS and macOS (not just Web).
This shipped in v0.4.0; v0.3.0 and earlier are unaffected.
Working around an upstream OpenCV 5.0.0 defect required turning off PNG_ARM_NEON on
those three arm64 platforms, which drops both the hand-written assembly kernel and the
NEON intrinsics path — they share the same build switch. This affects every CvCodecs
user on those platforms, whether or not they touch dnn. See the
roadmap for why.
Unity 6000.3 or newer throughout.
Releases live at
github.com/ayutaz/OpenCVUnityNative/releases.
The published release (v0.4.0) carries all six platforms: Mat lifecycle, cvtColor / resize / GaussianBlur plus the wider imgproc set (thresholding, Canny, morphology, perspective transform and warp, template matching, contours, probabilistic Hough lines, sub-pixel corners), the core array operations, encoding/decoding images to and from byte arrays in memory, QR encode/decode, ArUco markers, ORB keypoints and descriptor matching, homography and pose estimation, the three stages of monocular camera calibration, stereo disparity, and — only when you set OCVU_PROFILE_DNN — ONNX inference. The ABI takes no file paths at all —
only byte buffers. That is on purpose: a StreamingAssets file inside an Android APK
has no path that can be opened, and a path crossing this boundary would drag Windows
text encoding along with it.
The full surface, with what is deliberately absent, is in the API reference; the count itself lives at the top of the API map.
On Linux, use v0.1.1 or later. The Linux plugin in v0.1.0 was built against
glibc 2.38 and fails to load on anything older — Ubuntu 22.04 included — with
DllNotFoundException. Since v0.1.1 the Linux artifacts are built in an Ubuntu
22.04 container and require only glibc 2.34.
Each release carries one tarball holding every platform — that is the one to take — plus one tarball per platform for anyone who wants a single platform's binary and nothing else:
com.ayutaz.opencv-unity-native.tgz # every platform — take this one
com.ayutaz.opencv-unity-native-<version>-windows-x64.tgz # one platform only, if that is what you want
com.ayutaz.opencv-unity-native-<version>-macos-arm64.tgz
com.ayutaz.opencv-unity-native-<version>-linux-x64.tgz
com.ayutaz.opencv-unity-native-<version>-android-arm64.tgz
com.ayutaz.opencv-unity-native-<version>-ios-arm64.tgz
com.ayutaz.opencv-unity-native-<version>-web-wasm.tgz
The per-platform list grows with the platform set; the release you download is the authority on which ones exist.
The all-platform tarball carries no version number in its filename on purpose:
OpenUPM selects a release asset by a stable name prefix, so a version in the name
would mean rewriting that pattern every release. The per-platform tarballs keep
theirs. The package is registered on OpenUPM (accepted 2026-08-30) and
https://package.openupm.com/com.ayutaz.opencv-unity-native serves it.
Releases land first. OpenUPM builds on its own queue, so a new version takes
hours to appear there — v0.3.0 took about four. Until it does, openupm add
installs the previous version, not the one this page describes. If a version
was just published, take the release tarball instead.
(docs/openupm-registration.md).
Download com.ayutaz.opencv-unity-native.tgz, put it somewhere inside or beside your
project, and point the package manifest at it:
A relative path is resolved from the Packages folder; an absolute path also works.
Unity 6000.3 or newer is required — 2022 LTS is not supported, and 6000.0 LTS is no
longer what the lanes verify, because its regular support ends in October 2026. The
Unity lanes pin 6000.3.16f1, both locally and in CI, which reads that version out of
the test project rather than carrying its own copy of the number.
Every release also carries SHA256SUMS.txt, listing the SHA-256 of every other
asset in that release — it cannot list itself. Download it alongside the files you
took and check them in one go:
sha256sum -c SHA256SUMS.txt # Linux
shasum -a 256 -c SHA256SUMS.txt # macOSFiles you did not download are reported as missing; that is expected. The line for
each file you did take must say OK.
A release also carries checksum files that are not about the downloads at all:
checksums.txt for the all-platform package (one line per binary) and
<platform>-checksums.txt for each single-platform package. Those cover the files
inside those packages, so they are only useful after extracting.
SHA256SUMS.txt is the one that covers the downloadable assets themselves.
A Git URL will not work, and this is deliberate. The native plugin binaries
(.dll / .dylib / .so / .a) are not tracked in git — keeping every platform's
binaries in history would grow it without bound. A Git URL reference therefore
delivers the C# code and the Plugin Import Settings but no actual libraries, and
every DllImport fails at runtime. Use the release tarball —
com.ayutaz.opencv-unity-native.tgz.
The package you install carries every platform's binary together (all six since v0.3.0; Windows, macOS and Linux were the three in v0.2.0). Unity allows one package per package ID, so a project whose editor and build target are different platforms needs them in one package. Earlier releases shipped one tarball per platform and could not express that; the per-platform tarballs still ship, but only as a convenience for a project that wants a single platform's binary.
Each binary's Plugin Import Settings enable it on its own platform only, and that is
now measured rather than asserted: an EditMode test asks Unity's own PluginImporter
how it read the .meta files, with every binary present. Two things that
measurement established are worth knowing if you go inspecting the settings yourself.
First, GetCompatibleWithEditor() returns true for every plugin — the editor
is gated by the OS sub-setting underneath that flag, not by the flag, so a check
reading only the flag passes always and proves nothing. Second, the check has teeth:
deliberately breaking a .meta so the macOS library claims Windows leaves the older
ten-test suite at 10 of 10 — DllImport resolution already branches on the differing
file names, so nothing there ever noticed — and fails 3 of the gating tests.
Installing the all-platform tarball into a throwaway project and running EditMode there passes, measured on one Windows machine. CI runs the same EditMode suite with every platform's binary present, so the multi-platform case those checks exist for is exactly what CI exercises — an EditMode test refuses to go green unless it sees them all. Current counts and sizes are in the roadmap; they move with every release, so they are not repeated here.
New in v0.4.0. Against v0.3.0 or earlier, setting OCVU_PROFILE_DNN defines a symbol with nothing behind it.
The native binary always contains OpenCV's dnn module (ONNX loading, blob
conversion, and forward inference) — it is not split into a separate binary,
because two of the six platforms (iOS, WebGL) resolve DllImport("__Internal")
by symbol name, not by library name, so there is no name to switch on. What is
optional is the C# side: the dnn API (CvDnn, in the CvUnity.Dnn
assembly) only compiles into your project if you add the Scripting Define
Symbol OCVU_PROFILE_DNN under Project Settings → Player → Other Settings →
Scripting Define Symbols for the platforms you target. Leave it unset and
that code — and the P/Invoke declarations it depends on — is not part of your
build.
This could not be automated with package.json's versionDefines: that
mechanism fires a define when a given package is present, but dnn lives
inside this same package rather than a separate one, so there is nothing
whose presence to key off. The define is therefore something you set
yourself, not something the package sets for you.
dnn has not been run on a real device (the same gap the mobile platforms
have generally — see the roadmap), and inference speed has
not been measured.
Tagging v* builds every platform, verifies the linkage of what was built,
checks that the Linux library does not require a newer glibc or libstdc++ than the
oldest environment we support, overlays every platform's plugin tree into one
package, packages everything, and creates a draft release. The glibc check reads
the version records inside the built .so; it does not load the library, so it is a
statement about what the binary asks of its host, not proof that it runs there.
That portability check now runs on the release path as well, which it did not before. It was written in response to the v0.1.0 defect, yet it only ran in the Unity and nightly lanes, neither of which a tag triggers — so it had never been applied to a binary anyone actually downloaded. Building Linux inside a pinned container prevents the problem structurally, but "the structure prevents it, so the check is redundant" is precisely the reasoning v0.1.0 disproved.
The workflow then counts what it staged — and looks for the all-platform tarball
among them by name — before uploading, because a name collision would otherwise
overwrite a file silently and still look successful. (SHA256SUMS.txt is written
afterwards, so a published release holds one more file than was staged.) A human looks at what was produced
and publishes it. A tag alone does not make a release visible — that is deliberate, so
a release that is wrong can be discarded before anyone has it.
- Visual Studio 2022 with the C++ desktop workload
- CMake 3.25+
- .NET 8 SDK or newer
- PowerShell 7+
- GitHub CLI (
gh), authenticated —tools/opencv.ps1 restoreuses it to download the prebuilt OpenCV artifact - Only for the Web (Wasm) build: Ninja and Unity's WebGL Build Support module. Emscripten cannot be driven by the Visual Studio generator, so this is the one platform that needs Ninja on Windows. Set
OCVU_NINJAif you keep it outsidePATH. Every other platform builds without it.
OpenCV is not built locally. Fetch the pinned artifact first:
./tools/opencv.ps1 restoreThis downloads the prebuilt OpenCV 5.0.0 artifact CI publishes for the current configuration hash (tools/opencv-config.psd1); tools/opencv.ps1 build reproduces that build locally, so use it only to verify what CI produced. Measured cost: CI's own build step (clone + configure + build + install + verify) took 4m09s on a windows-2022 GitHub Actions runner (run 32849957498); local timing hasn't been measured and may differ with local hardware and network conditions.
All local development after that goes through tools/dev.ps1:
# The fast tools tests, the generated-bindings check, and both native lanes
# (L1 GoogleTest + L3 managed P/Invoke). Run this one lane at a time: the lanes
# share artifacts/test-results/ and each one clears it on start.
./tools/dev.ps1 test
# Individual lanes
./tools/dev.ps1 build
./tools/dev.ps1 test-native
./tools/dev.ps1 test-managed
# Regenerate the C header, the C# P/Invoke declarations, the reachability test
# and docs/api-map.md from bindings/spec/*.json, and check they are up to date.
# The declarations are never written by hand; verify-generated is part of `test`.
./tools/dev.ps1 generate
./tools/dev.ps1 verify-generated
# AddressSanitizer lane (L2)
./tools/dev.ps1 test-asan
# Unity EditMode (L4) and a Windows IL2CPP Player build + run (L5);
# need Unity 6000.3.16f1 installed locally, with the IL2CPP module for the player lane
./tools/dev.ps1 test-unity-editmode
./tools/dev.ps1 test-unity-player
# Build the WebGL player and drive it in a headless browser (Playwright + Chromium).
# Also asserts that Unity's bundled Emscripten matches tools/emscripten-versions.psd1.
./tools/dev.ps1 test-unity-web
# The GPU-dependent RenderTexture paths (EditMode, graphics enabled) and the
# benchmark lane that collects OCVU_BENCH: lines from the player and graphics
# lanes. CI has run equivalents of both since 2026-09-11, but neither of those
# checks is required — see "What CI covers" below.
./tools/dev.ps1 test-unity-graphics
./tools/dev.ps1 benchmark
# Install the UPM tarball into a throwaway Unity project and run its tests there.
# Without -PluginSource this packs only this machine's own platform, and says so
# rather than pretending to be the all-platform package. Pass the other platforms'
# plugin trees (';'-separated, e.g. extracted from a published release) to build
# and install the all-platform package instead.
./tools/dev.ps1 test-unity-tarball
./tools/dev.ps1 test-unity-tarball -PluginSource "<mac>/package;<linux>/package"
# Remove build output
./tools/dev.ps1 cleanCI calls the same tools/dev.ps1 script for everything except the Unity lanes, where
it uses GameCI to provide the editor and activate the licence.
That divergence is deliberate and bounded: the pass/fail decision is shared, in
tools/assert-unity-results.ps1, which both the local lanes and CI run. In particular
"zero tests executed is not a pass" lives there, so it cannot hold locally while
silently lapsing in CI.
A local green run is an approximation kept for speed; CI decides mergeability.
| Windows x64 | macOS arm64 | Linux x64 | Android arm64 | iOS arm64 | Web wasm32 | |
|---|---|---|---|---|---|---|
| L1 contract tests + L3 P/Invoke | yes | yes | yes | cross-build only | cross-build only | cross-build only |
| L2 sanitizers | ASan | — | ASan + LeakSanitizer | — | — | — |
| Artifact linkage and enabled languages | yes | yes | yes | 16 KB page size | bundled symbols | bundled symbols + SIMD |
| Unity EditMode (L4) | local only | local only | yes | — | — | — |
| Unity IL2CPP player (L5) | local only | — | yes | — | — | — |
| Browser end-to-end | — | — | — | — | — | yes |
The mobile columns say "cross-build only" because that is all CI can do: it compiles and inspects the artifacts, and no device has ever loaded them. The Web column is different: CI builds a real WebGL player and runs it in a headless Chromium, so the same checks EditMode and the IL2CPP player run also run in a browser. There is no sanitizer lane for Web (a cross-compiled sanitizer cannot run on the host).
Four lanes are absent from that table because CI does not invoke those dev.ps1
commands directly. All four now have a CI equivalent — that changed on
2026-09-11, and before it two of them had none at all. test-unity-tarball is the
closest coupling: CI calls ./tools/dev.ps1 test-unity-tarball -PrepareOnly to build
the throwaway project and then hands the launch to GameCI, so the tarball CI installs
is built by the same code that builds the one you install locally. test-unity-web
is the loosest: CI's Web browser E2E job builds the player itself and calls the same
two scripts directly rather than going through dev.ps1. test-unity-graphics and
benchmark sit in between — CI runs a Graphics lane and a benchmarks job that
exercise and collect the same things.
Three of those four CI checks are not required, so a red one does not stop a
merge: the Graphics lane, the tarball install job and the benchmark job. The
fourth, Web browser E2E, is required — it was promoted on 2026-09-10. That
split is why the paragraph above distinguishes "CI runs it" from "CI blocks on
it"; the two are not the same thing.
The GPU half of the RenderTexture API is now exercised, in the Editor only.
RenderTextureConverter.ToMat and RequestMat are public API in the package
(since v0.4.0 — see Status). Until 2026-09-11 the code path that
actually moves pixels had never run in CI, on the assumption that it could not:
every CI Unity lane was believed to run with -nographics, where RenderTexture
creation succeeds but the pixels read back are not the ones you drew. That
assumption was never measured. GameCI's Linux editor container runs Unity under
xvfb without -nographics, so a Graphics lane exercises the real path — it
passes, including the AsyncGPUReadback route. The IL2CPP player is a different
story and is still not covered: GameCI launches the standalone player with
-nographics from inside the action, and that is not ours to change. Argument
validation is covered in every lane (ToMat(null) is rejected); the player-side
GPU path is not.
tests/UnityProject/Assets/Tests/EditMode/CiVisibilityTests.cs pins the list of
tests that live only in the non-required Graphics lane, so the list has to be
edited deliberately rather than growing by accident.
The Unity lanes run on Linux, and the Windows IL2CPP player is covered only by the
local lane. That is now a measured conclusion rather than an assumption. An earlier
note here blamed upstream issues that turned out to describe a different action and a
different image lineage; the workflow was actually tried on windows-2022 in
2026-08-31. EditMode ran there and passed 33 tests. The Standalone player did not:
IL2CPP emits C++ and the GameCI Windows container has no MSVC to compile it, so the
build fails with ToolchainNotFoundException. Windows-specific IL2CPP defects
therefore stay invisible to CI by design, not by oversight. macOS was tried four times
in the same window and fails earlier still — GameCI does not support darwin, and
installing the editor directly gets as far as a licence that reports zero
entitlements. The roadmap records both attempts.
Linux artifacts are built inside an Ubuntu 22.04 container, not on the runner
image. A shared library only loads on a system at least as new as the one that built
it, and runner images keep moving forward. Building in a pinned container keeps the
floor where we intend it (glibc 2.35), and tools/verify-plugin-portability.ps1
fails the build if what came out requires anything newer.
Beyond the table, every pull request also runs actionlint, shellcheck,
PSScriptAnalyzer and a repository-relative link check, and CodeQL analyses the C++
and C#. A nightly workflow re-checks the Linux artifact's glibc floor, runs the fast
lanes on Windows and macOS, and confirms the pinned OpenCV artifacts have not
expired — things that break while nobody is pushing. It has run on its schedule
every day since 2026-08-29 — thirteen scheduled runs as of 2026-09-10, the last
eight of them green. (An earlier version of this paragraph said it had never run on
a schedule. That was wrong for over a week, and nothing goes red when a statement
like that stops being true.)
Almost every lane that runs on a pull request blocks a merge. Twenty-nine checks are
required: the contract, P/Invoke and sanitizer jobs across the three desktop platforms, the
Android, iOS and Web/Wasm cross-builds, the four lint jobs, both CodeQL analyses, both
Unity lanes, the browser end-to-end test, the seven release jobs that build and
assemble the distributable for all six platforms, and — since 2026-09-11 — the
five ci-unity jobs added that day: the Graphics lane, the two dnn-profile
lanes, the tarball-install job and the benchmark-publishing job.
Thirteen are deliberately not required. Six of them are the GameCI results checks
(EditMode results and its five siblings): they report neutral on pull requests,
and GitHub counts neutral as passing, so requiring them would add no stopping
power. (Count these after the run finishes: GameCI creates them late in each job,
so counting mid-run undercounts. These numbers come from gh pr checks on a
completed PR, matched against the protection settings by name.)
Of the other seven, five build the per-platform plugins the Unity lanes
consume: when one fails the Unity lanes run anyway and go red on the missing input, which
is what stops the merge. The other four are the aggregate CodeQL check, whose two
per-language analyses are required individually; the two Unity result-publishing jobs,
which are skipped on pull requests; and Publish the release, described at the end of
this section. (The three Web/Wasm checks — its cross-build, its browser end-to-end test
and its release packaging — were promoted on 2026-09-10, after passing on all eleven
pull requests merged since #63 and, for the two that also run on main, its last six
runs. A red Web lane now stops a merge like any other; they are counted among the
twenty-four above.)
Promotion follows evidence, but somebody has to go and look at it. A skipped required check
counts as passing, so depending on one without that guard would let a broken build
through. A lane is only made required once it has been reliably green — but the failure
mode seen twice here was the opposite of impatience: a lane was added and left
un-required, which is exactly the gap where a red check cannot stop a merge. Until 2026-08-29 the
Unity, lint and CodeQL workflows ran on every pull request without being required,
so they could be red and the change still merged; CI watching something and CI
stopping something are different things, and only the second one is a gate. The
remaining three workflows (build-opencv, nightly, unity-probe) are not
triggered by pull requests at all, so they cannot be required. release was in that list until
2026-08-31; it now runs on pull requests too, because three defects had accumulated in the
distribution path while it only ran on tags — one of which meant that tagging a release
would have produced no release at all. Its Publish the release job stays out of the
required set: it is skipped on pull requests by design, and a skipped check counts as
passing, so requiring it would stop nothing.
- CONTRIBUTING.md — how a change gets in, what a change needs, and what CI does not check.
- SECURITY.md — how to report a vulnerability privately, and what is in scope at this boundary.
Apache License 2.0 for this repository's own source. That does not by itself determine the terms of third-party code linked into the distributed binary — see THIRD_PARTY_NOTICES.md for the licenses of what the pinned OpenCV build bundles. That file lists every licence the artifact ships and says, per component, which of OpenCV's own static libraries it is compiled into — SoftFloat, annoylib, MSCR's chi table and the Rubik font are linked alongside zlib, libpng, libjpeg-turbo and libclapack; a few others ship a licence file without being linked. The Rubik font is under the SIL Open Font License, not a BSD-family licence, so the set is not uniform. Dependencies are constrained by an allowlist (tools/verify-opencv-artifact.ps1) and documented per build profile.
Which of those then reach the plugin you redistribute depends on which OpenCV
modules this plugin links, and that has changed several times. It now links core,
imgproc, imgcodecs, objdetect, features, geometry, calib, stereo and dnn; before
imgcodecs it linked only core and imgproc. Static linking pulls in only what is referenced, so until the functions that
call into a module are written, none of that module's code reaches the shipped library.
Writing them is what pulls it in — on Windows the debug library grew from 8,831,488 to
10,177,536 bytes when the encode/decode functions landed (zlib, libpng and libjpeg-turbo
came with them), and to 20,136,960 bytes when the QR and ORB functions landed
(annoylib and the MSCR chi_table come with features). It stands at 22,283,264 bytes now.
The previous figure recorded here was 21,464,576, measured when calibrateCamera
landed. Rebuilding the same sources after M6 gives 21,465,600 — the Web work
changed the build without anyone re-measuring, so 1,024 bytes of the difference are
not ours. The 26 functions added in September 2026 account for 817,664 bytes.
Adding a module to the build system alone changes nothing: linking calib, and
later stereo, each moved the library by exactly zero bytes until a function
actually called into it.
That distinction is easy to lose, and this repository lost it for a while. The pinned
OpenCV build has always been configured with imgcodecs, and
ocvu_get_build_information() duly lists it under "To be built" — which says OpenCV
was built with the module, not that this plugin links against it. It did not, and the
linker is what settled the question: the first calls to cv::imencode came out as
unresolved externals.
The notices, SBOM and build manifest are published per platform, as separate
release assets. The all-platform tarball carries only its checksum list: both of the
other two are derived from one platform's restored OpenCV artifact, and the job that
bundles every platform has no such source, so a merged version would have to be
invented rather than derived. Take the <platform>-THIRD_PARTY_NOTICES.md asset for
each platform you ship.
On Windows the plugin links the runtime library in its shared form rather than embedding a copy. A developer integrating this package decides what to redistribute with their game, rather than the package deciding for them.
Design and research documents (in Japanese) live under docs/:
- Roadmap
- M0 implementation plan
- M1 implementation plan
- M2 implementation plan
- M3 implementation plan
- M3.5 implementation plan
- M4 implementation plan
- M5 implementation plan
- M6 implementation plan
- M7 design — the shared spec for the three M7 plans
- M7 (a) low-copy paths and benchmarks
- M7 (b) module separation
- M7 (c) dnn profile
The plans that closed M5's remaining criterion, and the six that expanded the API between M6 and M7, live beside them; the documentation index lists all of them.
- Performance — what was measured, and what deliberately was not
- Device verification checklist — what CI cannot close
- API reference
- API map — generated from the binding spec
- OpenUPM registration
- C ABI ownership and versioning
- Unity/OpenCV integration research and plan
- Native backend language TDD evaluation