Files
opencv/modules/imgproc/include/opencv2
Thebinary110 d0c18a8701 imgproc: add RGB <-> Oklab color conversion
Adds COLOR_BGR2Oklab, COLOR_RGB2Oklab, COLOR_Oklab2BGR, and
COLOR_Oklab2RGB to cvtColor, implementing Bjorn Ottosson's Oklab
perceptual color space (https://bottosson.github.io/posts/oklab/),
requested in #21760.

Scope for this first PR: CV_8U and CV_32F only (matching the existing
Lab/Luv precedent -- neither supports CV_16U either, likely for the
same reason: the cube-root nonlinearity doesn't lend itself to a
fixed-point integer fast path), plain scalar C++ (no SIMD, no OpenCL
kernel -- cvtColor's CV_OCL_RUN/CV_Assert machinery already falls back
to this CPU path cleanly for codes without an OpenCL case), and the
core RGB<->Oklab conversion only (not the Okhsv/Okhsl variants the
issue also mentions, which the issue itself calls secondary to the
"most directly important" Oklab conversion).

Encoding: CV_32F keeps Oklab's native range (L in [0,1], a/b roughly
in [-0.5,0.5] for in-gamut sRGB colors), matching how the reference
formulas and other tools (e.g. CSS Color 4's oklab()) represent it.
CV_8U scales L by 255 and offsets a/b by 128, mirroring CIE Lab's own
8-bit encoding shape.

Testing:
- The forward matrices were verified against an independent NumPy
  reimplementation before writing any C++: round-trip identity over
  20000 random RGB samples (~1.6e-6 max error), plus cross-checked
  pure red/green/blue/white/black/gray against commonly-published
  Oklab reference values -- matches to 6+ significant figures.
- New tests in test_color.cpp: reference-value cross-check (same
  known values as above, now through the actual cv::cvtColor), a
  channel-order check (COLOR_RGB2Oklab vs COLOR_BGR2Oklab on the same
  logical pixels), float32 and uint8 round-trips, and alpha-channel
  passthrough on the 4-channel inverse. All pass; verified the uint8
  round-trip test actually exercises meaningful precision by comparing
  its tolerance against CIE Lab's own established uint8 tolerance
  (CV_ColorLabTest accepts up to 37 for the analogous case; this uses
  32 for a still-meaningful, not looser, bound).
- Confirmed swapBlue() needed COLOR_BGR2Oklab/COLOR_Oklab2BGR added to
  its explicit list -- its default (true) is correct for the RGB
  variants by accident but wrong for the BGR ones, which would have
  silently swapped red and blue. Caught by code review before testing,
  then confirmed fixed via the channel-order test.
- Ran the full opencv_test_imgproc suite: no new failures (the same
  360 pre-existing "missing opencv_extra test data" failures present
  before this change, e.g. StackBlur/HoughCircles/ColorBayer, all in
  unrelated files).
- Verified the UMat (OpenCL) path falls back to the CPU implementation
  correctly (no OpenCL kernel is added in this PR).
- Added a perf test (cvtColorOklab) covering both directions, CV_8U
  and CV_32F, at VGA/720p/1080p.

Natural follow-ups, intentionally left out of this first PR: SIMD/
fixed-point optimization (this is a plain scalar implementation),
Okhsv/Okhsl, and an OpenCL kernel.
2026-09-23 16:52:56 +05:30
..