mirror of
https://github.com/opencv/opencv.git
synced 2026-10-06 04:03:36 +03:00
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.