jasmcaus / jasmcaus/caer

`yuv2gray()` / `luv2gray()` (and other yuv2* / luv2* conversions) seem to ignore the intermediate BGR conversion. Is this intended?

Open
#81 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
817
Forks
110
PR merge metrics
No merged PRs in 30d

Description

I checked the documentation and searched the repository for the relevant color-conversion behavior. I could not find any documentation or existing implementation pattern indicating that these conversions are intentionally performed directly on the original YUV/LUV values.

Please confirm you have the latest versions of caer, numpy, opencv-contrib-python, and h5py prior to reporting a bug (delete one): YES (caer from dev, latest numpy and opencv-contrib-python from PyPI.)

Describe the bug

Hi! While reading caer/color/_yuv.py I noticed something that looks like a bug, but I'd like to confirm it's not intended before opening a PR.

The derived conversions compute a BGR intermediate and then discard it, converting the original YUV array as if it were BGR:

# caer/color/_yuv.py, yuv2gray()
img = yuv2bgr(tens)
img = bgr2gray(tens)   # <- uses `tens` (YUV data), not `img` (BGR)
return to_tensor(img, cspace="gray")

The same pattern appears in yuv2hls, yuv2hsv, yuv2lab, yuv2luv and, in caer/color/_luv.py, in luv2gray, luv2hls, luv2hsv, luv2lab, luv2yuv. Since caer.to_gray(), to_hsv(), to_hls(), to_lab(), to_yuv() and to_luv() call these functions, they are affected too for YUV/LUV inputs.

For comparison, caer/color/_hsv.py does pass the intermediate along (bgr = hsv2bgr(tens), then img = bgr2gray(bgr)), and its results match OpenCV.

To Reproduce

This uses the bundled sunrise image, so no external files are needed:

import cv2 as cv
import numpy as np
import caer

bgr = caer.data.sunrise(rgb=False)

# YUV -> Grayscale
yuv = caer.to_tensor(cv.cvtColor(bgr, cv.COLOR_BGR2YUV), cspace="yuv")
expected = cv.cvtColor(cv.cvtColor(yuv, cv.COLOR_YUV2BGR), cv.COLOR_BGR2GRAY)
print("yuv2gray matches OpenCV:", np.array_equal(caer.yuv2gray(yuv), expected))
print("to_gray(yuv) matches OpenCV:", np.array_equal(caer.to_gray(yuv), expected))
print("yuv2gray equals bgr2gray on the raw YUV data:", np.array_equal(caer.yuv2gray(yuv), caer.bgr2gray(yuv)))

# HSV -> Grayscale, for comparison
hsv = caer.to_tensor(cv.cvtColor(bgr, cv.COLOR_BGR2HSV), cspace="hsv")
expected = cv.cvtColor(cv.cvtColor(hsv, cv.COLOR_HSV2BGR), cv.COLOR_BGR2GRAY)
print("hsv2gray matches OpenCV:", np.array_equal(caer.hsv2gray(hsv), expected))

Output:

yuv2gray matches OpenCV: False
to_gray(yuv) matches OpenCV: False
yuv2gray equals bgr2gray on the raw YUV data: True
hsv2gray matches OpenCV: True

Expected behavior

yuv2gray(yuv) should equal converting YUV -> BGR -> Gray (as hsv2gray does for HSV). Instead it equals bgr2gray applied directly to the YUV values. The same applies to the other nine functions listed above.

Error with full stack trace

No exception is raised; the functions return silently wrong pixel values.

Additional context

  • caer: dev branch at c313af56 (version 2.1.1)
  • Python: 3.12.12
  • numpy: 2.5.3
  • opencv-contrib-python: 5.0.0
  • OS: Linux (Fedora 43, x86_64)

The existing tests in tests/color/test_yuv.py and tests/color/test_luv.py only check the shape and the cspace flag, which is probably why this wasn't caught.

If this is indeed unintended, I'd be happy to open a PR against dev with the fix (passing img instead of tens in those 10 places) and tests that compare the results against OpenCV.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in caer/color/_yuv.py and caer/color/_luv.py, comparing their derived conversions with the intermediate-passing pattern in caer/color/_hsv.py. Run the bundled sunrise reproduction, then inspect tests/color/test_yuv.py and tests/color/test_luv.py. Done means the listed YUV/LUV conversions match the corresponding OpenCV conversions, with tests covering pixel values as well as shape and cspace.

Written by the indexing model from the issue text.

Assessment

Tech stack
opencv, python
Domain
computer-vision
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
85/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.