Repository navigation
[io] Place transparent images on a white background in read_img_as_numpy - #2183
MohammadHijjawi97 wants to merge 3 commits into
Conversation
Decoding with cv2.IMREAD_COLOR drops the alpha channel and keeps the color stored under the transparent pixels, which is usually black. A PNG with dark text on a transparent background was therefore read as an all-black page. Images with transparency are now composited over white (with the EXIF orientation still applied).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2183 +/- ##
=======================================
Coverage 97.74% 97.74%
=======================================
Files 170 170
Lines 10932 10958 +26
=======================================
+ Hits 10685 10711 +26
Misses 247 247
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
felixdittrich92
left a comment
There was a problem hiding this comment.
Thanks @MohammadHijjawi97 👍
Two small things:
-
Skip compositing for fully opaque images.
has_transparency_datais true for any RGBA image, so opaque RGBA files (screenshots, many exports) now take the slower Pillow path. On a 2500×3000 opaque RGBA PNG this went from ~50 ms to ~130–150 ms. Please return early whenalpha.min() == 255. Doing the compositing in numpy instead ofalpha_compositewould also cut the extra image copies. With an early exit I measured ~68 ms. -
Keep the tensor readers consistent.
read_img_as_tensoranddecode_img_as_tensorindoctr/io/image/pytorch.pystill use.convert("RGB"), so transparent pixels come out black there and white inread_img_as_numpy. Please share the helper between both readers.
Minor:
- Avoid the RGB→BGR→RGB round trip when
rgb_output=True. - In the EXIF test with a transparent image, also assert that a corner pixel is white, not just the shape.
…readers - Return early when the alpha channel is fully opaque, and composite in place on the decoded array instead of building Pillow images. - read_img_as_tensor and decode_img_as_tensor now use the same helper, so transparent pixels are white there too (they were black). - Keep Pillow's RGB output as is when rgb_output=True.
|
Thanks for the review, all four points are addressed in 113390c (and main is merged in).
|
read_img_as_numpy(used byDocumentFile.from_images) decodes images withcv2.IMREAD_COLOR, which drops the alpha channel and keeps the color stored under the transparent pixels, usually black. A PNG with dark text on a transparent background (logo, screenshot, exported scan) is read as an all-black page and nothing gets recognized.Reproduction:
Before:
[0](the whole page is black)After: the text pixels plus a white (255) background
Fix: images with transparency (checked from the PIL header,
has_transparency_data) are composited over a white background, with the EXIF orientation applied ascv2.imdecodedoes. Every other image keeps the existing OpenCV path, and files PIL cannot open still fall back to OpenCV (sameValueErrorfor invalid files).Tests: extended
test_read_img_as_numpy(transparent PNG -> white background, colors and BGR order kept) andtest_read_img_as_numpy_exif_orientation(EXIF orientation is still applied to a transparent PNG). The first fails on main and passes with this change.ruff check,ruff format --checkandmypy doctr/pass.Any feedback is welcome 🤗