kwimage.im_io

Module Contents

Functions

imread(fpath, space=’auto’, backend=’auto’) Reads image data in a specified format using some backend implementation.
_imread_turbojpeg(fpath) See: https://www.learnopencv.com/efficient-image-loading/
_imread_skimage(fpath)
_imread_cv2(fpath)
_imread_gdal(fpath) gdal imread backend
imwrite(fpath, image, space=’auto’, backend=’auto’, **kwargs) Writes image data to disk.
load_image_shape(fpath) Determine the height/width/channels of an image without reading the entire
__inspect_optional_overhead() Benchmark:
_have_turbojpg() pip install PyTurboJPEG
_have_gdal()
_imwrite_cloud_optimized_geotiff(fpath, data, compress=’auto’, blocksize=256, overviews=None, overview_resample=’NEAREST’, options=[]) Writes data as a cloud-optimized geotiff using gdal
_numpy_to_gdal_dtype(numpy_dtype) maps numpy dtypes to gdal dtypes
_gdal_to_numpy_dtype(gdal_dtype) maps gdal dtypes to numpy dtypes
_gdal_auto_compress(src_fpath=None, data=None, data_set=None) Heuristic for automatically choosing gdal compression type
_dtype_equality(dtype1, dtype2) Check for numpy dtype equality
kwimage.im_io.imread(fpath, space='auto', backend='auto')

Reads image data in a specified format using some backend implementation.

Parameters:
  • fpath (str) – path to the file to be read
  • space (str, default=’auto’) – the desired colorspace of the image. Can by any colorspace accepted by convert_colorspace, or it can be ‘auto’, in which case the colorspace of the image is unmodified (except in the case where a color image is read by opencv, in which case we convert BGR to RGB by default). If None, then no modification is made to whatever backend is used to read the image.
  • backend (str, default=’auto’) – which backend reader to use. By default the file extension is used to determine this, but it can be manually overridden. Valid backends are gdal, skimage, and cv2.
Returns:

the image data in the specified color space.

Return type:

ndarray

Note

if space is something non-standard like HSV or LAB, then the file must be a normal 8-bit color image, otherwise an error will occur.

Raises:
  • IOError - If the image cannot be read
  • ImportError - If trying to read a nitf without gdal
  • NotImplementedError - if trying to read a corner-case image

Example

>>> # xdoctest: +REQUIRES(--network)
>>> from kwimage.im_io import *  # NOQA
>>> import tempfile
>>> from os.path import splitext  # NOQA
>>> # Test a non-standard image, which encodes a depth map
>>> fpath = ub.grabdata('http://www.topcoder.com/contest/problem/UrbanMapper3D/JAX_Tile_043_DTM.tif')
>>> img1 = imread(fpath)
>>> # Check that write + read preserves data
>>> tmp = tempfile.NamedTemporaryFile(suffix=splitext(fpath)[1])
>>> imwrite(tmp.name, img1)
>>> img2 = imread(tmp.name)
>>> assert np.all(img2 == img1)
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.imshow(img1, pnum=(1, 2, 1), fnum=1, norm=True)
>>> kwplot.imshow(img2, pnum=(1, 2, 2), fnum=1, norm=True)

Example

>>> # xdoctest: +REQUIRES(--network)
>>> import tempfile
>>> img1 = imread(ub.grabdata('http://i.imgur.com/iXNf4Me.png', fname='ada.png'))
>>> tmp_tif = tempfile.NamedTemporaryFile(suffix='.tif')
>>> tmp_png = tempfile.NamedTemporaryFile(suffix='.png')
>>> imwrite(tmp_tif.name, img1)
>>> imwrite(tmp_png.name, img1)
>>> tif_im = imread(tmp_tif.name)
>>> png_im = imread(tmp_png.name)
>>> assert np.all(tif_im == png_im)
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.imshow(png_im, pnum=(1, 2, 1), fnum=1)
>>> kwplot.imshow(tif_im, pnum=(1, 2, 2), fnum=1)

Example

>>> # xdoctest: +REQUIRES(--network)
>>> import tempfile
>>> tif_fpath = ub.grabdata('https://ghostscript.com/doc/tiff/test/images/rgb-3c-16b.tiff', fname='pepper.tif')
>>> img1 = imread(tif_fpath)
>>> tmp_tif = tempfile.NamedTemporaryFile(suffix='.tif')
>>> tmp_png = tempfile.NamedTemporaryFile(suffix='.png')
>>> imwrite(tmp_tif.name, img1)
>>> imwrite(tmp_png.name, img1)
>>> tif_im = imread(tmp_tif.name)
>>> png_im = imread(tmp_png.name)
>>> assert np.all(tif_im == png_im)
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> kwplot.autompl()
>>> kwplot.imshow(png_im / 2 ** 16, pnum=(1, 2, 1), fnum=1)
>>> kwplot.imshow(tif_im / 2 ** 16, pnum=(1, 2, 2), fnum=1)
Benchmark:
>>> from kwimage.im_io import *  # NOQA
>>> import timerit
>>> import kwimage
>>> import tempfile
>>> #
>>> dsize = (1920, 1080)
>>> img1 = kwimage.grab_test_image('amazon', dsize=dsize)
>>> ti = timerit.Timerit(10, bestof=3, verbose=1, unit='us')
>>> formats = {}
>>> dpath = ub.ensure_app_cache_dir('cache')
>>> space = 'auto'
>>> formats['png'] = kwimage.imwrite(join(dpath, '.png'), img1, space=space, backend='cv2')
>>> formats['jpg'] = kwimage.imwrite(join(dpath, '.jpg'), img1, space=space, backend='cv2')
>>> formats['tif_raw'] = kwimage.imwrite(join(dpath, '.raw.tif'), img1, space=space, backend='gdal', compress='RAW')
>>> formats['tif_deflate'] = kwimage.imwrite(join(dpath, '.deflate.tif'), img1, space=space, backend='gdal', compress='DEFLATE')
>>> formats['tif_lzw'] = kwimage.imwrite(join(dpath, '.lzw.tif'), img1, space=space, backend='gdal', compress='LZW')
>>> grid = [
>>>     ('cv2', 'png'),
>>>     ('cv2', 'jpg'),
>>>     ('gdal', 'jpg'),
>>>     ('turbojpeg', 'jpg'),
>>>     ('gdal', 'tif_raw'),
>>>     ('gdal', 'tif_lzw'),
>>>     ('gdal', 'tif_deflate'),
>>>     ('skimage', 'tif_raw'),
>>> ]
>>> backend, filefmt = 'cv2', 'png'
>>> for backend, filefmt in grid:
>>>     for timer in ti.reset(f'imread-{filefmt}-{backend}'):
>>>         with timer:
>>>             kwimage.imread(formats[filefmt], space=space, backend=backend)
>>> # Test all formats in auto mode
>>> for filefmt in formats.keys():
>>>     for timer in ti.reset(f'kwimage.imread-{filefmt}-auto'):
>>>         with timer:
>>>             kwimage.imread(formats[filefmt], space=space, backend='auto')
>>> ti.measures = ub.map_vals(ub.sorted_vals, ti.measures)
>>> import netharn as nh
>>> print('ti.measures = {}'.format(nh.util.align(ub.repr2(ti.measures['min'], nl=2), ':')))
Timed best=42891.504 µs, mean=44008.439 ± 1409.2 µs for imread-png-cv2
Timed best=33146.808 µs, mean=34185.172 ± 656.3 µs for imread-jpg-cv2
Timed best=40120.306 µs, mean=41220.927 ± 1010.9 µs for imread-jpg-gdal
Timed best=30798.162 µs, mean=31573.070 ± 737.0 µs for imread-jpg-turbojpeg
Timed best=6223.170 µs, mean=6370.462 ± 150.7 µs for imread-tif_raw-gdal
Timed best=42459.404 µs, mean=46519.940 ± 5664.9 µs for imread-tif_lzw-gdal
Timed best=36271.175 µs, mean=37301.108 ± 861.1 µs for imread-tif_deflate-gdal
Timed best=5239.503 µs, mean=6566.574 ± 1086.2 µs for imread-tif_raw-skimage
ti.measures = {
    'imread-tif_raw-skimage' : 0.0052395030070329085,
    'imread-tif_raw-gdal'    : 0.006223169999429956,
    'imread-jpg-turbojpeg'   : 0.030798161998973228,
    'imread-jpg-cv2'         : 0.03314680799667258,
    'imread-tif_deflate-gdal': 0.03627117499127053,
    'imread-jpg-gdal'        : 0.040120305988239124,
    'imread-tif_lzw-gdal'    : 0.042459404008695856,
    'imread-png-cv2'         : 0.042891503995633684,
}
>>> print('ti.measures = {}'.format(nh.util.align(ub.repr2(ti.measures['mean'], nl=2), ':')))
kwimage.im_io._imread_turbojpeg(fpath)

See: https://www.learnopencv.com/efficient-image-loading/

References

https://pypi.org/project/PyTurboJPEG/

Bash:
pip install PyTurboJPEG sudo apt install libturbojpeg -y
Ignore:
>>> # xdoctest: +REQUIRES(--network)
>>> # xdoctest: +REQUIRES(turbojpeg)
>>> import kwimage
>>> rgb_fpath = kwimage.grab_test_image_fpath('amazon')
>>> assert rgb_fpath.endswith('.jpg')
>>> #
>>> rgb = kwimage.imread(rgb_fpath)
>>> gray = kwimage.convert_colorspace(rgb, 'rgb', 'gray')
>>> gray_fpath = rgb_fpath + '.gray.jpg'
>>> kwimage.imwrite(gray_fpath, gray)
>>> #
>>> fpath = gray_fpath
>>> #
>>> from kwimage.im_io import _imread_turbojpeg, _imread_skimage, _imread_cv2
>>> import timerit
>>> ti = timerit.Timerit(50, bestof=10, verbose=2)
>>> #
>>> for timer in ti.reset('turbojpeg'):
>>>     with timer:
>>>         im_turbo = _imread_turbojpeg(fpath)
>>> #
>>> for timer in ti.reset('cv2'):
>>>     with timer:
>>>         im_cv2 = _imread_cv2(fpath)
kwimage.im_io._imread_skimage(fpath)
kwimage.im_io._imread_cv2(fpath)
kwimage.im_io._imread_gdal(fpath)

gdal imread backend

kwimage.im_io.imwrite(fpath, image, space='auto', backend='auto', **kwargs)

Writes image data to disk.

Parameters:
  • fpath (PathLike) – location to save the image
  • image (ndarray) – image data
  • space (str) – the colorspace of the image to save. Can by any colorspace accepted by convert_colorspace, or it can be ‘auto’, in which case we assume the input image is either RGB, RGBA or grayscale. If None, then absolutely no color modification is made and whatever backend is used writes the image as-is.
  • backend (str, default=’auto’) – which backend writer to use. By default the file extension is used to determine this. Valid backends are gdal, skimage, and cv2.
  • **kwargs – args passed to the backend writer
Returns:

path to the written file

Return type:

str

Notes

The image may be modified to preserve its colorspace depending on which backend is used to write the image.

When saving as a jpeg or png, the image must be encoded with the uint8 data type. When saving as a tiff, any data type is allowed.

Raises:Exception – if the image cannot be written
Doctest:
>>> # xdoctest: +REQUIRES(--network)
>>> # This should be moved to a unit test
>>> import tempfile
>>> test_image_paths = [
>>>    ub.grabdata('https://ghostscript.com/doc/tiff/test/images/rgb-3c-16b.tiff', fname='pepper.tif'),
>>>    ub.grabdata('http://i.imgur.com/iXNf4Me.png', fname='ada.png'),
>>>    #ub.grabdata('http://www.topcoder.com/contest/problem/UrbanMapper3D/JAX_Tile_043_DTM.tif'),
>>>    ub.grabdata('https://upload.wikimedia.org/wikipedia/commons/f/fa/Grayscale_8bits_palette_sample_image.png', fname='parrot.png')
>>> ]
>>> for fpath in test_image_paths:
>>>     for space in ['auto', 'rgb', 'bgr', 'gray', 'rgba']:
>>>         img1 = imread(fpath, space=space)
>>>         print('Test im-io consistency of fpath = {!r} in {} space, shape={}'.format(fpath, space, img1.shape))
>>>         # Write the image in TIF and PNG format
>>>         tmp_tif = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         tmp_png = tempfile.NamedTemporaryFile(suffix='.png')
>>>         imwrite(tmp_tif.name, img1, space=space, backend='skimage')
>>>         imwrite(tmp_png.name, img1, space=space)
>>>         tif_im = imread(tmp_tif.name, space=space)
>>>         png_im = imread(tmp_png.name, space=space)
>>>         assert np.all(tif_im == png_im), 'im-read/write inconsistency'
>>>         if _have_gdal:
>>>             tmp_tif2 = tempfile.NamedTemporaryFile(suffix='.tif')
>>>             imwrite(tmp_tif2.name, img1, space=space, backend='gdal')
>>>             tif_im2 = imread(tmp_tif2.name, space=space)
>>>             assert np.all(tif_im == tif_im2), 'im-read/write inconsistency'
>>>         if space == 'gray':
>>>             assert tif_im.ndim == 2
>>>             assert png_im.ndim == 2
>>>         elif space in ['rgb', 'bgr']:
>>>             assert tif_im.shape[2] == 3
>>>             assert png_im.shape[2] == 3
>>>         elif space in ['rgba', 'bgra']:
>>>             assert tif_im.shape[2] == 4
>>>             assert png_im.shape[2] == 4
Benchmark:
>>> import timerit
>>> import kwimage
>>> import tempfile
>>> #
>>> img1 = kwimage.grab_test_image('astro', dsize=(1920, 1080))
>>> space = 'auto'
>>> #
>>> file_sizes = {}
>>> #
>>> ti = timerit.Timerit(10, bestof=3, verbose=2)
>>> #
>>> for timer in ti.reset('imwrite-skimage-tif'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='skimage')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-cv2-png'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.png')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='cv2')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-cv2-jpg'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.jpg')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='cv2')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-gdal-raw'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='gdal', compress='RAW')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-gdal-lzw'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='gdal', compress='LZW')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-gdal-deflate'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='gdal', compress='DEFLATE')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> for timer in ti.reset('imwrite-gdal-jpeg'):
>>>     with timer:
>>>         tmp = tempfile.NamedTemporaryFile(suffix='.tif')
>>>         kwimage.imwrite(tmp.name, img1, space=space, backend='gdal', compress='JPEG')
>>>     file_sizes[ti.label] = os.stat(tmp.name).st_size
>>> #
>>> file_sizes = ub.sorted_vals(file_sizes)
>>> file_sizes_human = ub.map_vals(lambda x: xdev.byte_str(x, 'MB'), file_sizes)
>>> print('ti.rankings = {}'.format(ub.repr2(ti.rankings, nl=2)))
>>> print('file_sizes = {}'.format(ub.repr2(file_sizes_human, nl=1)))
kwimage.im_io.load_image_shape(fpath)

Determine the height/width/channels of an image without reading the entire file.

Parameters:fpath (str) – path to an image
Returns:
Tuple - shape of the dataset.
Recall this library uses the convention that “shape” is refers to height,width,channels and “size” is width,height ordering.
Benchmark:
>>> # For large files, PIL is much faster
>>> import gdal
>>> from PIL import Image
>>> #
>>> import kwimage
>>> fpath = kwimage.grab_test_image_fpath()
>>> #
>>> ti = ub.Timerit(100, bestof=10, verbose=2)
>>> for timer in ti.reset('gdal'):
>>>     with timer:
>>>         gdal_dset = gdal.Open(fpath, gdal.GA_ReadOnly)
>>>         width = gdal_dset.RasterXSize
>>>         height = gdal_dset.RasterYSize
>>>         gdal_dset = None
>>> #
>>> for timer in ti.reset('PIL'):
>>>     with timer:
>>>         pil_img = Image.open(fpath)
>>>         width, height = pil_img.size
>>>         pil_img.close()
Timed gdal for: 100 loops, best of 10
    time per loop: best=62.967 µs, mean=63.991 ± 0.8 µs
Timed PIL for: 100 loops, best of 10
    time per loop: best=46.640 µs, mean=47.314 ± 0.4 µs
kwimage.im_io.__inspect_optional_overhead()
Benchmark:
>>> from kwimage.im_io import _have_gdal, _have_turbojpg  # NOQA
>>> def dis_instructions(func):
>>>     import dis
>>>     import io
>>>     buf = io.StringIO()
>>>     dis.disassemble(func.__code__, file=buf)
>>>     _, text = buf.seek(0), buf.read()
>>>     return text
>>> func = _have_turbojpg
>>> func = _have_gdal
>>> memo = ub.memoize(func)
>>> print(func_dis := dis_instructions(func))
>>> print(memo_dis := dis_instructions(memo))
>>> n = max(func_dis.count('

‘), memo_dis.count(‘ ‘))

>>> sep = ' |
‘ * n
>>> prefix = '|
‘ * n
>>> print('
‘)
>>> print(ub.hzcat([prefix, x, sep, y]))
Benchmark:
>>> from kwimage.im_io import _have_gdal, _have_turbojpg  # NOQA
>>> funcs = []
>>> funcs += [_have_turbojpg]
>>> funcs += [_have_gdal]
>>> for func in funcs:
>>>     memo = ub.memoize(func)
>>>     print('func = {!r}'.format(func))
>>>     print('memo = {!r}'.format(memo))
>>>     import timerit
>>>     ti = timerit.Timerit(100, bestof=10, verbose=1, unit='us')
>>>     ti.reset('call func').call(func).report()
>>>     ti.reset('call memo').call(memo).report()
kwimage.im_io._have_turbojpg()

pip install PyTurboJPEG

kwimage.im_io._have_gdal()
kwimage.im_io._imwrite_cloud_optimized_geotiff(fpath, data, compress='auto', blocksize=256, overviews=None, overview_resample='NEAREST', options=[])

Writes data as a cloud-optimized geotiff using gdal

Parameters:
  • fpath (PathLike) – file path to save the COG to.
  • data (ndarray[ndim=3]) – Raw HWC image data to save. Dimensions should be height, width, channels.
  • compress (bool, default=’auto’) – Can be JPEG (lossy) or LZW (lossless), or DEFLATE (lossless). Can also be ‘auto’, which will try to heuristically choose a sensible choice.
  • blocksize (int, default=256) – size of tiled blocks
  • overviews (None | int | list, default=None) – if specified as a list, then uses exactly those overviews. If specified as an integer a list is created using powers of two.
  • overview_resample (str, default=’NEAREST’) – resampling method for overview pyramid. Valid choices are: ‘NEAREST’, ‘AVERAGE’, ‘BILINEAR’, ‘CUBIC’, ‘CUBICSPLINE’, ‘LANCZOS’.
  • options (List[str]) – other gdal options

References

https://geoexamples.com/other/2019/02/08/cog-tutorial.html#create-a-cog-using-gdal-python http://osgeo-org.1560.x6.nabble.com/gdal-dev-Creating-Cloud-Optimized-GeoTIFFs-td5320101.html https://gdal.org/drivers/raster/cog.html https://github.com/harshurampur/Geotiff-conversion https://github.com/sshuair/cogeotiff https://github.com/cogeotiff/rio-cogeo https://gis.stackexchange.com/questions/1104/should-gdal-be-set-to-produce-geotiff-files-with-compression-which-algorithm-sh

Example

>>> # xdoctest: +REQUIRES(module:gdal)
>>> import tempfile
>>> data = np.random.randint(0, 255, (800, 800, 3), dtype=np.uint8)
>>> tmp_tif = tempfile.NamedTemporaryFile(suffix='.cog.tif')
>>> fpath = tmp_tif.name
>>> compress = 'JPEG'
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='JPEG')
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='LZW')
>>> data = (np.random.rand(100, 100, 4) * 255).astype(np.uint8)
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='JPEG')
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='LZW')
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='DEFLATE')
>>> data = (np.random.rand(100, 100, 5) * 255).astype(np.uint8)
>>> _imwrite_cloud_optimized_geotiff(fpath, data, compress='LZW')
>>> _imwrite_cloud_optimized_geotiff(fpath, data, overviews=3)
>>> import gdal
>>> ds = gdal.Open(fpath, gdal.GA_ReadOnly)
>>> filename = ds.GetDescription()
>>> main_band = ds.GetRasterBand(1)
>>> assert main_band.GetOverviewCount() == 3
>>> _imwrite_cloud_optimized_geotiff(fpath, data, overviews=[2, 4])
kwimage.im_io._numpy_to_gdal_dtype(numpy_dtype)

maps numpy dtypes to gdal dtypes

kwimage.im_io._gdal_to_numpy_dtype(gdal_dtype)

maps gdal dtypes to numpy dtypes

Example

>>> # xdoctest: +REQUIRES(module:gdal)
>>> numpy_types = [np.uint8, np.uint16, np.int16, np.uint32, np.int32,
>>>                np.float32, np.float64, np.complex64,
>>>                np.complex128]
>>> for np_type in numpy_types:
>>>     numpy_dtype1 = np_type().dtype
>>>     gdal_dtype1 = _numpy_to_gdal_dtype(numpy_dtype1)
>>>     numpy_dtype2 = _gdal_to_numpy_dtype(gdal_dtype1)
>>>     gdal_dtype2 = _numpy_to_gdal_dtype(numpy_dtype2)
>>>     assert gdal_dtype2 == gdal_dtype1
>>>     assert _dtype_equality(numpy_dtype1, numpy_dtype2)
kwimage.im_io._gdal_auto_compress(src_fpath=None, data=None, data_set=None)

Heuristic for automatically choosing gdal compression type

Parameters:
  • src_fpath (str) – path to source image if known
  • data (ndarray) – data pixels if known
  • data_set (gdal.Dataset) – gdal dataset if known
Returns:

gdal compression code

Return type:

str

Example

>>> # xdoctest: +REQUIRES(module:gdal)
>>> assert _gdal_auto_compress(src_fpath='foo.jpg') == 'JPEG'
>>> assert _gdal_auto_compress(src_fpath='foo.png') == 'LZW'
>>> assert _gdal_auto_compress(data=np.random.rand(3, 2)) == 'RAW'
>>> assert _gdal_auto_compress(data=np.random.rand(3, 2, 3).astype(np.uint8)) == 'RAW'
>>> assert _gdal_auto_compress(data=np.random.rand(3, 2, 4).astype(np.uint8)) == 'RAW'
>>> assert _gdal_auto_compress(data=np.random.rand(3, 2, 1).astype(np.uint8)) == 'RAW'
kwimage.im_io._dtype_equality(dtype1, dtype2)

Check for numpy dtype equality

References

https://stackoverflow.com/questions/26921836/correct-way-to-test-for-numpy-dtype

Example

dtype1 = np.empty(0, dtype=np.uint8).dtype dtype2 = np.uint8 _dtype_equality(dtype1, dtype2)