Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
Loading 16-bit tiff images (cvat-ai#5005)
Browse files Browse the repository at this point in the history
Pull Request regarding Issue cvat-ai#2987 

PIL.Image conversion from I;16 to L or RGB are unsuccessful as for now.
See the corresponding Issue in the Pillow GitHub (Opened 2018, so no
changes to be expected)
python-pillow/Pillow#3011

The proposed changes at least fix this issue for the mode 'I;16' and
delivers a possible solution for other modes (eg. I;16B/L/N).

This results in a correct calculation of the preview thumbnail and the
actual image, the annotation will be performed on.

We have used this solution on our own dataset and created annotations
accordingly.
  • Loading branch information
MyNameIsFu authored and mikhail-treskin committed Jul 1, 2023
1 parent 51111ec commit d56d3f2
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ from online detectors & interactors) (<https://github.com/opencv/cvat/pull/4543>
non-ascii paths while adding files from "Connected file share" (issue #4428)
- Removed unnecessary volumes defined in docker-compose.serverless.yml
(<https://github.com/openvinotoolkit/cvat/pull/4659>)
- Added support for Image files that use the PIL.Image.mode 'I;16'
- Project import/export with skeletons (<https://github.com/opencv/cvat/pull/4867>,
<https://github.com/opencv/cvat/pull/5004>)
- Shape color is not changed on canvas after changing a label (<https://github.com/opencv/cvat/pull/5045>)
Expand Down
37 changes: 35 additions & 2 deletions cvat/apps/engine/media_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import numpy as np
from natsort import os_sorted
from pyunpack import Archive
from PIL import Image, ImageFile
from PIL import Image, ImageFile, ImageOps
from random import shuffle
from cvat.apps.engine.utils import rotate_image
from cvat.apps.engine.models import DimensionType, SortingMethod
Expand Down Expand Up @@ -127,9 +127,25 @@ def _get_preview(obj):
else:
preview = obj
preview = rotate_within_exif(preview)
# TODO - Check if the other formats work. I'm only interested in I;16 for now. Sorry @:-|
# Summary:
# Images in the Format I;16 definitely don't work. Most likely I;16B/L/N won't work as well.
# Simple Conversion from I;16 to I/RGB/L doesn't work as well.
# Including any Intermediate Conversions doesn't work either. (eg. I;16 to I to L)
# Seems like an internal Bug of PIL
# See Issue for further details: https://github.com/python-pillow/Pillow/issues/3011
# Issue was opened 2018, so don't expect any changes soon and work with manual conversions.
mode: str = preview.mode
if mode == "I;16":
preview = np.array(preview, dtype=np.uint16) # 'I;16' := Unsigned Integer 16, Grayscale
image = image - image.min() # In case the used range lies in [a, 2^16] with a > 0
preview = preview / preview.max() * 255 # Downscale into real numbers of range [0, 255]
preview = preview.astype(np.uint8) # Floor to integers of range [0, 255]
preview = Image.fromarray(preview, mode="L") # 'L' := Unsigned Integer 8, Grayscale
preview = ImageOps.equalize(preview) # The Images need equalization. High resolution with 16-bit but only small range that actually contains information
preview.thumbnail(PREVIEW_SIZE)

return preview.convert('RGB')
return preview

@abstractmethod
def get_image_size(self, i):
Expand Down Expand Up @@ -589,6 +605,23 @@ def _compress_image(image_path, quality):
im_data = np.array(image)
im_data = im_data * (2**8 / im_data.max())
image = Image.fromarray(im_data.astype(np.int32))

# TODO - Check if the other formats work. I'm only interested in I;16 for now. Sorry @:-|
# Summary:
# Images in the Format I;16 definitely don't work. Most likely I;16B/L/N won't work as well.
# Simple Conversion from I;16 to I/RGB/L doesn't work as well.
# Including any Intermediate Conversions doesn't work either. (eg. I;16 to I to L)
# Seems like an internal Bug of PIL
# See Issue for further details: https://github.com/python-pillow/Pillow/issues/3011
# Issue was opened 2018, so don't expect any changes soon and work with manual conversions.
if image.mode == "I;16":
image = np.array(image, dtype=np.uint16) # 'I;16' := Unsigned Integer 16, Grayscale
image = image - image.min() # In case the used range lies in [a, 2^16] with a > 0
image = image / image.max() * 255 # Downscale into real numbers of range [0, 255]
image = image.astype(np.uint8) # Floor to integers of range [0, 255]
image = Image.fromarray(image, mode="L") # 'L' := Unsigned Integer 8, Grayscale
image = ImageOps.equalize(image) # The Images need equalization. High resolution with 16-bit but only small range that actually contains information

converted_image = image.convert('RGB')
image.close()
buf = io.BytesIO()
Expand Down

0 comments on commit d56d3f2

Please sign in to comment.