diff --git a/MANIFEST.in b/MANIFEST.in
index dc8f75ecc362021410f6686954b25c1d98966bc8..cf1d827b4de456cfd9faa016ac18001948a7caf3 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,3 @@
 include README.rst buildout.cfg COPYING version.txt requirements.txt
 recursive-include doc *.rst *.png *.ico *.txt
-recursive-include bob *.json
+recursive-include bob *.json *.png
diff --git a/bob/ip/binseg/data/transforms.py b/bob/ip/binseg/data/transforms.py
index a347fcbb3af00052ea79dc7394a2945a006986e1..bea81bcd9dbf7ba998795f96c35ccae3b7c1b417 100644
--- a/bob/ip/binseg/data/transforms.py
+++ b/bob/ip/binseg/data/transforms.py
@@ -18,8 +18,6 @@ import PIL.Image
 import torchvision.transforms
 import torchvision.transforms.functional
 
-import bob.core
-
 
 class TupleMixin:
     """Adds support to work with tuples of objects to torchvision transforms"""
@@ -104,12 +102,17 @@ class SingleAutoLevel16to8:
     To auto-level, we calculate the maximum and the minimum of the image, and
     consider such a range should be mapped to the [0,255] range of the
     destination image.
+
     """
 
     def __call__(self, img):
+        imin, imax = img.getextrema()
+        irange = imax - imin
         return PIL.Image.fromarray(
-            bob.core.convert(img, "uint8", (0, 255), img.getextrema())
-        )
+            numpy.round(
+                255.0 * (numpy.array(img).astype(float) - imin) / irange
+            ).astype("uint8"),
+        ).convert("L")
 
 
 class AutoLevel16to8(TupleMixin, SingleAutoLevel16to8):
@@ -121,6 +124,7 @@ class AutoLevel16to8(TupleMixin, SingleAutoLevel16to8):
     consider such a range should be mapped to the [0,255] range of the
     destination image.
     """
+
     pass
 
 
@@ -132,6 +136,7 @@ class SingleToRGB:
     defaults.  This may be aggressive if applied to 16-bit images without
     further considerations.
     """
+
     def __call__(self, img):
         return img.convert(mode="RGB")
 
@@ -195,8 +200,8 @@ class RandomRotation(torchvision.transforms.RandomRotation):
     """
 
     def __init__(self, p=0.5, **kwargs):
-        kwargs.setdefault('degrees', 15)
-        kwargs.setdefault('resample', PIL.Image.BILINEAR)
+        kwargs.setdefault("degrees", 15)
+        kwargs.setdefault("resample", PIL.Image.BILINEAR)
         super(RandomRotation, self).__init__(**kwargs)
         self.p = p
 
@@ -205,16 +210,17 @@ class RandomRotation(torchvision.transforms.RandomRotation):
         if random.random() < self.p:
             angle = self.get_params(self.degrees)
             return [
-                torchvision.transforms.functional.rotate(img, angle,
-                    self.resample, self.expand, self.center)
+                torchvision.transforms.functional.rotate(
+                    img, angle, self.resample, self.expand, self.center
+                )
                 for img in args
-                ]
+            ]
         else:
             return args
 
     def __repr__(self):
         retval = super(RandomRotation, self).__repr__()
-        return retval.replace('(', f'(p={self.p},', 1)
+        return retval.replace("(", f"(p={self.p},", 1)
 
 
 class ColorJitter(torchvision.transforms.ColorJitter):
@@ -243,10 +249,10 @@ class ColorJitter(torchvision.transforms.ColorJitter):
     """
 
     def __init__(self, p=0.5, **kwargs):
-        kwargs.setdefault('brightness', 0.3)
-        kwargs.setdefault('contrast', 0.3)
-        kwargs.setdefault('saturation', 0.02)
-        kwargs.setdefault('hue', 0.02)
+        kwargs.setdefault("brightness", 0.3)
+        kwargs.setdefault("contrast", 0.3)
+        kwargs.setdefault("saturation", 0.02)
+        kwargs.setdefault("hue", 0.02)
         super(ColorJitter, self).__init__(**kwargs)
         self.p = p
 
@@ -259,4 +265,4 @@ class ColorJitter(torchvision.transforms.ColorJitter):
 
     def __repr__(self):
         retval = super(ColorJitter, self).__repr__()
-        return retval.replace('(', f'(p={self.p},', 1)
+        return retval.replace("(", f"(p={self.p},", 1)
diff --git a/bob/ip/binseg/test/test_transforms.py b/bob/ip/binseg/test/test_transforms.py
index 826343f632d9c4e7b62fbecea68df45bcf71728b..a1967fe54894eccd1fe818c8564c08d92c98ad88 100644
--- a/bob/ip/binseg/test/test_transforms.py
+++ b/bob/ip/binseg/test/test_transforms.py
@@ -4,7 +4,10 @@
 import random
 
 import nose.tools
+import pkg_resources
+
 import numpy
+import PIL.Image
 import torch
 import torchvision.transforms.functional
 
@@ -93,7 +96,7 @@ def test_pad_default():
     # checks that the border introduced with padding is all about "fill"
     img_t = numpy.array(img_t)
     img_t[idx] = 0
-    border_size_plane = (img_t[:,:,0].size - numpy.array(img)[:,:,0].size)
+    border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size
     nose.tools.eq_(img_t.sum(), 0)
 
     gt_t = numpy.array(gt_t)
@@ -131,8 +134,8 @@ def test_pad_2tuple():
     # checks that the border introduced with padding is all about "fill"
     img_t = numpy.array(img_t)
     img_t[idx] = 0
-    border_size_plane = (img_t[:,:,0].size - numpy.array(img)[:,:,0].size)
-    expected_sum = sum((fill[k]*border_size_plane) for k in range(3))
+    border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size
+    expected_sum = sum((fill[k] * border_size_plane) for k in range(3))
     nose.tools.eq_(img_t.sum(), expected_sum)
 
     gt_t = numpy.array(gt_t)
@@ -170,8 +173,8 @@ def test_pad_4tuple():
     # checks that the border introduced with padding is all about "fill"
     img_t = numpy.array(img_t)
     img_t[idx] = 0
-    border_size_plane = (img_t[:,:,0].size - numpy.array(img)[:,:,0].size)
-    expected_sum = sum((fill[k]*border_size_plane) for k in range(3))
+    border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size
+    expected_sum = sum((fill[k] * border_size_plane) for k in range(3))
     nose.tools.eq_(img_t.sum(), expected_sum)
 
     gt_t = numpy.array(gt_t)
@@ -194,7 +197,7 @@ def test_resize_downscale_w():
     img, gt, mask = [_create_img(im_size) for i in range(3)]
     nose.tools.eq_(img.size, (im_size[2], im_size[1]))  # confirms the above
     img_t, gt_t, mask_t = transforms(img, gt, mask)
-    new_size = (new_size, (new_size*im_size[1])/im_size[2])
+    new_size = (new_size, (new_size * im_size[1]) / im_size[2])
     nose.tools.eq_(img_t.size, new_size)
     nose.tools.eq_(gt_t.size, new_size)
     nose.tools.eq_(mask_t.size, new_size)
@@ -224,8 +227,8 @@ def test_crop():
 
     # test
     idx = (
-        slice(crop_size[0], crop_size[0]+crop_size[2]),
-        slice(crop_size[1], crop_size[1]+crop_size[3]),
+        slice(crop_size[0], crop_size[0] + crop_size[2]),
+        slice(crop_size[1], crop_size[1] + crop_size[3]),
         slice(0, im_size[0]),
     )
     transforms = Crop(*crop_size)
@@ -297,7 +300,7 @@ def test_rotation():
     assert numpy.any(numpy.array(img1_t) != numpy.array(img))
 
     # asserts two random transforms are not the same
-    img_t2, = transforms(img)
+    (img_t2,) = transforms(img)
     assert numpy.any(numpy.array(img_t2) != numpy.array(img1_t))
 
 
@@ -327,15 +330,40 @@ def test_color_jitter():
 
 def test_compose():
 
-    transforms = Compose([
-                RandomVerticalFlip(p=1),
-                RandomHorizontalFlip(p=1),
-                RandomVerticalFlip(p=1),
-                RandomHorizontalFlip(p=1),
-                ])
+    transforms = Compose(
+        [
+            RandomVerticalFlip(p=1),
+            RandomHorizontalFlip(p=1),
+            RandomVerticalFlip(p=1),
+            RandomHorizontalFlip(p=1),
+        ]
+    )
 
     img, gt, mask = [_create_img((3, 24, 42)) for i in range(3)]
     img_t, gt_t, mask_t = transforms(img, gt, mask)
     assert numpy.all(numpy.array(img_t) == numpy.array(img))
     assert numpy.all(numpy.array(gt_t) == numpy.array(gt))
     assert numpy.all(numpy.array(mask_t) == numpy.array(mask))
+
+
+def test_16bit_autolevel():
+
+    test_image_path = pkg_resources.resource_filename(
+        __name__, "testimg-16bit.png"
+    )
+    # the way to load a 16-bit PNG image correctly, according to:
+    # https://stackoverflow.com/questions/32622658/read-16-bit-png-image-file-using-python
+    # https://github.com/python-pillow/Pillow/issues/3011
+    img = PIL.Image.fromarray(
+        numpy.array(
+            PIL.Image.open("bob/ip/binseg/test/testimg-16bit.png")
+        ).astype("uint16")
+    )
+    nose.tools.eq_(img.mode, "I;16")
+    nose.tools.eq_(img.getextrema(), (0, 65281))
+
+    timg = SingleAutoLevel16to8()(img)
+    nose.tools.eq_(timg.mode, "L")
+    nose.tools.eq_(timg.getextrema(), (0, 255))
+    #timg.show()
+    #import ipdb; ipdb.set_trace()
diff --git a/bob/ip/binseg/test/testimg-16bit.png b/bob/ip/binseg/test/testimg-16bit.png
new file mode 100644
index 0000000000000000000000000000000000000000..1bd5c6ad984e9200e0611d492149126b628fd74d
Binary files /dev/null and b/bob/ip/binseg/test/testimg-16bit.png differ
diff --git a/conda/meta.yaml b/conda/meta.yaml
index a6e591aa6c590bb61dc4358b47d830c65b03cc2b..b0b78dc569dc0490873f3a81547e3def158661f3 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -25,21 +25,21 @@ requirements:
   host:
     - python {{ python }}
     - setuptools {{ setuptools }}
-    - torchvision  {{ torchvision }} # [linux]
-    - pytorch {{ pytorch }} # [linux]
     - numpy {{ numpy }}
+    - h5py {{ h5py }}
+    - pytorch {{ pytorch }} # [linux]
+    - torchvision  {{ torchvision }} # [linux]
     - bob.extension
-    - bob.core
-    - bob.io.base
   run:
     - python
     - setuptools
+    - {{ pin_compatible('numpy') }}
+    - {{ pin_compatible('pillow') }}
+    - {{ pin_compatible('pandas') }}
+    - {{ pin_compatible('matplotlib') }}
     - {{ pin_compatible('pytorch') }} # [linux]
     - {{ pin_compatible('torchvision') }} # [linux]
-    - {{ pin_compatible('numpy') }}
-    - pandas
-    - pillow
-    - matplotlib
+    - {{ pin_compatible('h5py') }}
     - tqdm
     - tabulate
 
diff --git a/requirements.txt b/requirements.txt
index 8eff46db1eacdeae2082181c185a43425a537d36..e394a12df53ee4280702ad258089f3704c007bd8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,8 @@
-bob.core
 bob.extension
-bob.io.base
 matplotlib
 numpy
 pandas
+h5py
 pillow
 setuptools
 tabulate