Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix rounding error on RGB to L conversion #4320

Merged
merged 3 commits into from Jan 1, 2020

Conversation

homm
Copy link
Member

@homm homm commented Dec 31, 2019

Fixes #3800

@homm
Copy link
Member Author

homm commented Dec 31, 2019

This code was altered by me but I believe the error was there from the beginning. I think this PR is relatively safe for merge in 7.0.0.

A bit more work needs for fixing other L macro calls but I'm not ready for such feats before the release.

@homm homm requested a review from radarhere December 31, 2019 01:23
@radarhere
Copy link
Member

Looks like you're solving the second problem in the thread, but the original poster would like our results to exactly match OpenCV. This PR brings Pillow closer, but doesn't exactly match it.

@homm
Copy link
Member Author

homm commented Dec 31, 2019

We don't have an aim "to do everything like OpenCV". The real aim is to do everything correctly and OpenCV is wrong very often.

from PIL import Image
import cv2, numpy

im = Image.open('../imgs/56811035-ce7e0000-6805-11e9-9123-b297635e739e.png')
num_im = numpy.array(im)

ref = (num_im[:, :, 0] * 0.299 + num_im[:, :, 1] * 0.587 + num_im[:, :, 2] * 0.114 + 0.5).astype('uint8')
res_pillow = numpy.array(im.convert('L'))
res_cv2 = cv2.cvtColor(num_im, cv2.COLOR_RGB2GRAY)

print(numpy.count_nonzero(ref - res_pillow))
print(numpy.count_nonzero(ref - res_cv2))
61
224

So Pillow's result much closer to reference. I think this is because OpenCV uses fewer significant bits.

Anyway, now this is a question of precision, not rounding error which was truly an error.

@@ -44,7 +44,8 @@
#define L(rgb)\
((INT32) (rgb)[0]*299 + (INT32) (rgb)[1]*587 + (INT32) (rgb)[2]*114)
Copy link
Member

@radarhere radarhere Dec 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you've changed ImageColor, shouldn't this be changed as well for consistency?

color = (r * 299 + g * 587 + b * 114 + 500) // 1000

Copy link
Member Author

@homm homm Dec 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the "L" macro itself should be fixed. This macro is used for F mode for example, where no rounding needed. Instead, every place where "L" is used should be analyzed. This is a bit more work that needs more attention and I haven't much time today to do this before the release.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I've fixed ImageColor.getcolor implementation.

@radarhere radarhere merged commit 4203845 into python-pillow:master Jan 1, 2020
@homm homm deleted the rgb2l-rounding-error branch January 1, 2020 11:13
sgsunder added a commit to sgsunder/szurubooru that referenced this pull request Jun 4, 2020
Furthermore, an update to Pillow has improved the floating-point
precision of the image hash algorithm, requiring minor updates to
the respective unit tests.

See python-pillow/Pillow#4320
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrect Grayscale Conversion
2 participants