0

Im not expert in python. I want to seee the effect of quantization (bit depth reduction) by converting the image (array) with type of uint8 to uint4 (4 bit arrray).

Is it possible an array with type of uint4 in python?

I scaled my data to 0-15 and use this line im4 = np.bitwise_and(im_scaled, 0x0f) But still the type is uint8 as you see in below: In[173]: im4.dtype Out[173]: dtype('uint8')

I expected dtype('uint4')

1 Answers1

1

Here is the list of numpy's data types, so no uint4.

For uints, you have the following:

(note: .itemsize returns the "length of one array element in bytes")

In [1]: numpy_dtypes = (
   ...:     (np.uint8, np.ubyte),
   ...:     (np.uint16, np.ushort),
   ...:     (np.uint32, np.uintc),
   ...:     (np.uint64, np.uintp, np.ulonglong),
   ...: )
   ...: for dtypes in numpy_dtypes:
   ...:     print([dt().itemsize for dt in dtypes])
[1, 1]
[2, 2]
[4, 4]
[8, 8, 8]

You can simulate any bit depth by just scaling into the correct dynamic range and rounding to integers:

various num bits plots

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable


def main():

    imh, imw = 512, 512

    data = np.arange(imh * imw).reshape(imh, imw)
    num_bits = [2, 4, 8, 16]

    images = {
        nbits: np.round(minmax_scale(data, vmin=0, vmax=2**nbits - 1))
        for nbits in num_bits
    }

    fig, axes = plt.subplots(ncols=len(images), figsize=(12, 4))

    for ax, (nbits, image) in zip(axes, images.items()):
        ax.set_title(f"{nbits = }")
        im = ax.imshow(image, vmin=0, vmax=2**nbits - 1, interpolation="none")
        add_colorbar(ax, im)

    plt.subplots_adjust(wspace=0.8)
    plt.show()


def add_colorbar(ax, im):
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)
    cax.get_figure().colorbar(im, cax=cax, orientation="vertical")


def minmax_scale(arr, *, vmin, vmax):
    amin, amax = arr.min(), arr.max()
    arr_std = (arr - amin) / (amax - amin)
    return arr_std * (vmax - vmin) + vmin


if __name__ == "__main__":
    main()
paime
  • 2,901
  • 1
  • 6
  • 17
  • Thank you for your answer. Are the printed numbers related to bytes? And do you know how can I make an array in 4 bits in python? I have an image dataset in 8 bits. I want to create another dataset by converting the images to 4 bits. – Omid Ghozat Jan 08 '23 at 12:13
  • Added an edit for that – paime Jan 09 '23 at 09:21
  • I see the differences in the images for different numbers of bits. But my concern is all 4 created images in images {dict} are Array of float64. Do you think is it ok created an image in 2 bits that is stored it in float 64? – Omid Ghozat Jan 09 '23 at 10:59
  • It is enough to "see the effect of quantization". Sure it is not best suited for storage, but as you can only use `np.uint8`, `np.uint16`, `np.uint32` and `np.uint64` you have no other choice but to use at best the "smallest" data type that is "big" enough. For example in remote sensing optical imagery it is common for sensors to have a dynamic range of 12 bits, and images are stored in `uint16` with metadata describing that the dynamic range is only 12 bits, so the maximum value expected is only `2 ** 12 - 1` and not `2 ** 16 - 1` as the data type used for storage would have suggested. – paime Jan 10 '23 at 07:47
  • Btw a byte is the minimum entity for computers, so `8` bits. Even if you try a custom data type in numpy using `dtype = np.dtype((np.void, 1))` then you'll found `dtype.itemsize` to be `1` (byte). – paime Jan 10 '23 at 08:06