Skip to content

Fix rounding error on RGB to L conversion#4320

Merged
radarhere merged 3 commits into
python-pillow:masterfrom
uploadcare:rgb2l-rounding-error
Jan 1, 2020
Merged

Fix rounding error on RGB to L conversion#4320
radarhere merged 3 commits into
python-pillow:masterfrom
uploadcare:rgb2l-rounding-error

Conversation

@homm

@homm homm commented Dec 31, 2019

Copy link
Copy Markdown
Member

Fixes #3800

@homm

homm commented Dec 31, 2019

Copy link
Copy Markdown
Member Author

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
Copy Markdown
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

homm commented Dec 31, 2019

Copy link
Copy Markdown
Member Author

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.

Comment thread src/libImaging/Convert.c
@@ -44,7 +44,8 @@
#define L(rgb)\
((INT32) (rgb)[0]*299 + (INT32) (rgb)[1]*587 + (INT32) (rgb)[2]*114)

@radarhere radarhere Dec 31, 2019

Copy link
Copy Markdown
Member

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

@homm homm Dec 31, 2019

Copy link
Copy Markdown
Member Author

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
Copy Markdown
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