Fix 2D grayscale NumPy array prediction on color models - #24751
Conversation
A 2D grayscale NumPy array (H, W) passed to a 3-channel model crashed deep
in conv2d ("expected input to have 3 channels, but got 1"), while the same
image as a PIL object or file path worked (both auto-expand to 3 channels).
LoadPilAndNumpy._single_check now expands a 2D grayscale array to match the
model channels (3 for color, 1 for grayscale), mirroring the PIL branch. The
ndim==3 NumPy path (N-channel multispectral) is untouched. Adds a regression
test feeding a 2D grayscale array to the default color model.
|
All Contributors have signed the CLA. ✅ |
|
👋 Hello @maxime2476, thank you for submitting a -✅ Define a Purpose: Clearly explain the purpose of your fix or feature in your PR description, and link to any relevant issues. Ensure your commit messages are clear, concise, and adhere to the project's conventions. For more guidance, please refer to our Contributing Guide. Don't hesitate to leave a comment if you have any questions. Thank you for contributing to Ultralytics! 🚀 |
UltralyticsAssistant
left a comment
There was a problem hiding this comment.
🔍 PR Review
Made with ❤️ by Ultralytics Actions
Good targeted fix and test coverage for the reported uint8 grayscale ndarray case. One issue to address before merging: the new cv2.cvtColor expansion introduces a dtype regression for non-OpenCV-compatible NumPy grayscale arrays, so a NumPy-based channel repeat would be safer here.
💬 Posted 1 inline comment
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Address review: cv2.cvtColor(GRAY2BGR) rejects non-OpenCV dtypes (float64, int64, bool), which would make some 2D arrays fail at the expansion step. np.repeat produces 3 channels while keeping the input dtype. Extends the regression test with a float64 case.
|
I have read the CLA Document and I sign the CLA |
|
Thanks @maxime2476! 🎉 Really clean fix — a 2D grayscale NumPy array now predicts correctly on color models (auto-expanded to 3 channels like PIL/file inputs), resolving the |
⚡ Actions TriggerMade with ❤️ by Ultralytics Actions GitHub Actions below triggered via workflow dispatch for this PR at 2026-07-05 18:14:07 UTC with
|
Fix grayscale NumPy array prediction on color models
Closes #24750
What this does
Makes
LoadPilAndNumpy._single_checkexpand a 2D grayscale numpy array(H, W)to the model's channel count (3 for a color model, 1 for a grayscale model), the same way the PIL branch just above it already does. Adds a regression test.Why
Passing a 2D grayscale numpy array to a normal 3-channel model crashed inside PyTorch:
The same image works when passed as a PIL image or a file path, because both get normalized to the model's channel count. Only the raw numpy array failed: the grayscale branch added a single channel (
im[..., None]) and ignoredflag, unlike the PIL branch that calls.convert(flag). This change just makes the numpy path behave like the PIL and file paths.Before / after
Before:
RuntimeError(3 vs 1 channels).After: runs normally and returns 1 result, same as the PIL image / file path.
Scope
im.ndim == 2(grayscale) branch changes.im.ndim == 3numpy path is left as-is, so multispectral/multichannel models aren't affected (test_multichannelfeedsnp.zeros((32, 32, 10))).Tests
test_predict_grayscale_ndarrayfails before the change (RuntimeError) and passes after.test_predict_img(all models including grayscale),test_predict_gray_and_4ch,test_grayscale,test_multichanneland the new test all pass (16 passed).ruff checkandruff format --checkare clean.Not included
A 4-channel
(H, W, 4)RGBA numpy array fails the same way, but the loader can't tell it apart from a real 4-channel multispectral input (both arendim == 3), so I left it out to avoid breaking multichannel models. Can be a separate discussion.🛠️ PR Summary
Made with ❤️ by Ultralytics Actions
🌟 Summary
Fixes grayscale NumPy array inference for color YOLO models by aligning 2D ndarray handling with existing PIL and file input behavior. 🖼️
📊 Key Changes
_single_check()inultralytics/data/loaders.pyto convert 2D grayscale NumPy arrays to 3-channel BGR when used with color models.flag == "L"inputs as single-channel arrays.test_predict_grayscale_ndarray()intests/test_python.pyto verify that genuine 2D grayscale NumPy arrays run successfully through a default color model.🎯 Purpose & Impact