Python image IO module with binding cxx image code
Project description
CXX Image IO
CXX Image IO is a Python project which provides the image IO interfaces, binding with the C++ library: https://github.com/emmcb/cxx-image, These IO interfaces are designed to read and write images in many file formats in generic way and to interact nicely with numpy array.
Image format | Read | Write | EXIF | Pixel precision | Pixel type | File extension |
---|---|---|---|---|---|---|
BMP | x | x | 8 bits | Grayscale, RGB, RGBA | .bmp | |
CFA | x | x | 16 bits | Bayer | .cfa | |
DNG | x | x | x | 16 bits, float | Bayer, RGB | .dng |
JPEG | x | x | x | 8 bits | Grayscale, RGB | .jpg, .jpeg |
MIPIRAW | x | x | 10 bits, 12 bits | Bayer | .RAWMIPI, .RAWMIPI10, .RAWMIPI12 | |
PLAIN | x | x | * | * | .plain16, .nv12, * | |
PNG | x | x | 8 bits, 16 bits | Grayscale, RGB, RGBA | .png | |
TIFF | x | x | x | 8 bits, 16 bits, float | Bayer, RGB | .tif, .tiff |
Getting Started
Prerequisites
This projet currently supports Python from 3.10 to 3.13 on Windows and Linux.
numpy >= 1.26.4 is necessary.
Installation
The python package cxx_image_io
is to be installed by pip
pip install cxx_image_io
Usage example
Image reading
read_image
is able to read a image file and return a numpy array and ImageMetadata object.
from cxx_image_io import read_image
from cxx_image_io import ImageMetadata
import numpy as np
from pathlib import Path
image, metadata = read_image(Path('/path/to/image.jpg'))
assert isinstance(image, np.ndarray)
print('Type:', image.dtype)
print('Shape:', image.shape)
image is a numpy array which is suitable for the image processing afterwards.
The result could be like this:
Type: uint8
Shape: (551, 603, 3)
ImageMetadata is the information about the image, including the pixel type, pixel precision and image layout, which define fundamentally how the pixels arranged in buffer.
print(metadata.fileInfo)
The result could be like this:
{'pixelPrecision': 8, 'imageLayout': 'interleaved', 'pixelType': 'rgb'}
Some file formats need to know in advance some informations about the image. For example, the PLAIN format is just a simple dump of a buffer into a file, thus it needs to know how to interpret the data.
image, metadata = read_image(Path('/path/to/image.plain16'))
In this case, user need to have an image sidecar JSON located next to the image file as the same name and path '/path/to/image.json'
{
"fileInfo": {
"format": "plain",
"height": 3072,
"width": 4080
"pixelPrecision": 16,
"pixelType": "bayer_gbrg",
}
}
After image reading, the information in JSON sidecar is parsed in ImageMetadata object.
The result of print(metadata.fileInfo)
could be like this:
{'width': 4080, 'height': 3072, 'pixelPrecision': 16, 'imageLayout': 'planar', 'pixelType': 'bayer_gbrg'}
Image sidecar is not mandatory, for the other formats which have already image information in their header, like jpg, png, tif, cfa. we don't need to provide image metadata.
Split and merge image channels
After calling read_image
, cxx-image-io
provides a public API split_image_channels
which helps to split to different colors channels, so that user can do the different processes on them. The function return type is a dictionary which contains the different color channel name as keys, and the value in numpy array of one single channel.
before calling write_image
, cxx-image-io
provides a public API merge_image_channels
which helps to merge different colors channels to a numpy array buffer.
from cxx_image_io import read_image, split_image_channels, merge_image_channels, ImageLayout, ImageMetadata, PixelRepresentation, PixelType
import numpy as np
from pathlib import Path
rgb, metadata = read_image(Path('rgb_8bit.jpg'))
channels = split_image_channels(rgb, metadata)
# print(channels['r']) # Red channel
# print(channels['g']) # Green channel
# print(channels['b']) # Blue channel
rgb_post = merge_image_channels(channels, metadata)
np.array_equal(rgb, rgb_post)
cfa, metadata = read_image(Path('bayer_16bit.plain16'))
channels = split_image_channels(cfa, metadata)
# print(channels['gr']) # Bayer Gr pixels
# print(channels['r']) # Bayer R pixels
# print(channels['b']) # Bayer B pixels
# print(channels['gb']) # Bayer Gb pixels
cfa_post = merge_image_channels(channels, metadata)
np.array_equal(cfa, cfa_post)
yuv, metadata = read_image(Path('raw.nv12'))
channels = split_image_channels(yuv, metadata)
# print(channels['y']) # Y plane
# print(channels['u']) # U plane
# print(channels['v']) # V plane
yuv_post = merge_image_channels(channels, metadata)
np.array_equal(yuv, yuv_post)
Image writing
write_image
is able to write a numpy array to image file.
To write the pure numpy array to different image file extensions. User need to define the following fundamental parameters in ImageMetadata which is part of ImageWriter.Options. In order to call the specific C++ image libraries with them.
from cxx_image_io import ImageMetadata, ImageWriter, FileFormat, PixelType, ImageLayout
from cxx_image_io import write_image
import numpy as np
from pathlib import Path
metadata = ImageMetadata()
metadata.fileInfo.pixelType = PixelType.RGB
metadata.fileInfo.imageLayout = ImageLayout.INTERLEAVED
write_options = ImageWriter.Options(metadata)
assert isinstance(image, np.ndarray)
write_image(Path('/path/to/image.jpg'), image, write_options)
write_image
can determine the image format by file extensions, but some formats don't not rely on a specific extension, for example the PLAIN format that allows to directly dump the image buffer to a file. In this case, the format can be specified through ImageWriter.Options.
write_options = ImageWriter.Options(metadata)
write_options.fileFormat = FileFormat.PLAIN
assert isinstance(image, np.ndarray)
write_image(Path('/path/to/image.plain16'), image, write_options)
EXIF
Some image formats, like JPEG and TIFF, support EXIF reading and writing.
If supported, EXIF can be read by calling read_exif
and be written by calling write_exif
.
from cxx_image_io import read_exif, write_exif
from pathlib import Path
exif = read_exif(Path('/path/to/image.jpg'))
print(exif)
write_exif(Path('path/to/new_image.jpg'), exif)
print(exif)
will give the following output like:
{'make': 'Canon', 'model': 'Canon EOS 40D', 'orientation': 1, 'software': 'GIMP 2.4.5', 'exposureTime': [1, 160], 'fNumber': [71, 10], 'isoSpeedRatings': 100, 'dateTimeOriginal': '2008:05:30 15:56:01', 'exposureBiasValue': [0, 1], 'focalLength': [135, 1]}
user can use help(exif)
to see the definition of Exif metdata.
EXIF metadata can be read and written along with an image by specifying them in the ImageMetadata. In this case, the EXIF wil be read and written when calling read_image
and write_image
.
image, metadata = read_image(Path('/path/to/image.jpg'))
metadata.exifMetadata.make = 'Custom'
write_options = ImageWriter.Options(metadata)
write_image(Path('/path/to/image.jpg'), image, write_options)
License
This project is licensed under the MIT License - see the LICENSE.md file for details
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for cxx_image_io-0.0.19-cp313-cp313-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 473533157fd242db57cca60577be7619282f1dfec6dcd4e7238aa17f97340af3 |
|
MD5 | 03ddf600fd579589a268b3e0c4242cf9 |
|
BLAKE2b-256 | c440b1d8a1acfb7d4a579007661293dfeff401d9f3f6ccb0f78054dcf9959bed |
Hashes for cxx_image_io-0.0.19-cp313-cp313-manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 94a7d451a9bfd4746ed343ff602de6915e3893469836c9bbe1a372a2b89bb537 |
|
MD5 | 752928ca9ce4e139699b11d4eaeadeb8 |
|
BLAKE2b-256 | a5269b4ef163d867b05e8ca491f7f51f91ebce51372d321dc710cd1c5ea52ad1 |
Hashes for cxx_image_io-0.0.19-cp313-cp313-macosx_11_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2168338495dbcee047e614c25577f9357bf7f3476c7b47197c5c428a4d4c8594 |
|
MD5 | 751f9376072ad64d79a0a0b3d48afdd2 |
|
BLAKE2b-256 | 637bd49c558444595645b9f51c84b77e66888153df37f4d62c566a455c1879ec |
Hashes for cxx_image_io-0.0.19-cp313-cp313-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ef4deca06f4a7c5f24de30fcab003923daceed3cf866d39e3794a033f7d190e9 |
|
MD5 | 2fcda191b8b5d4d9c1670e7f22e7571d |
|
BLAKE2b-256 | e0682f64e945f8a1469289444f2e61152b508e56a1b39e4a0da2b203a0e91418 |
Hashes for cxx_image_io-0.0.19-cp312-cp312-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ec68172f153d555e8a5ff6b1ffa089e6bf2746047ca13fde64e6f288f8f8a4b0 |
|
MD5 | eefbce876bca7755d8bc2f8609e2d6ad |
|
BLAKE2b-256 | 5ae676e9a12c4f939aa22f70b741d105de1b975ee5762fa6106fc0a1c6e668fb |
Hashes for cxx_image_io-0.0.19-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | eab2065585e6d0d4a0a27351e9d51e99735e2d594faf5492d2617fc386e94598 |
|
MD5 | f146a6f99f3098305c95ed8d4940f978 |
|
BLAKE2b-256 | 36a46d99a4b52948311ac0991ab99be6c971e438ff399432dd8c0913a4ef16d0 |
Hashes for cxx_image_io-0.0.19-cp312-cp312-macosx_11_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5b6087fdcbf4444e9c94ad253f2c25755e280d2913ac65c0a41fcc0193c2d89d |
|
MD5 | 2e187041d3168fcece02d2da75291f07 |
|
BLAKE2b-256 | e59ae9a1fdbf425f21d29bdecd4d6d94f09777802b74c0e189c09e977fd070fa |
Hashes for cxx_image_io-0.0.19-cp312-cp312-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e67c6c642be52f169c0d3a369e1a5751e428061ffecf65f756da4ef0b33c599c |
|
MD5 | 06683be76b1f58eada746e64b8e2be2d |
|
BLAKE2b-256 | 12ecdd9334e15b91800e9e7e012ee92e8338a15b8eeb6ee47c89d5deae8dd6c8 |
Hashes for cxx_image_io-0.0.19-cp311-cp311-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 90d415c83e6ad53f1b1fecb341454786d20733913927ea2b02248b79bd2118fb |
|
MD5 | 26a00f9ce985507e062d6d6f1ac9774e |
|
BLAKE2b-256 | 012c88d2ae4d831b3842a37fc8d74de715024eaed01e9bafd61791cec62efaa5 |
Hashes for cxx_image_io-0.0.19-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 76d5f238136d1d73c41ed453f56d3a240ce2724b07adc8622b2b051011f14dfd |
|
MD5 | 06f5216758e430768709b2c7d1c1e2a5 |
|
BLAKE2b-256 | 95b920c953659c76a2c8594b6eb79f1f53f860968519e67ed7b56f7b3e4b9ce5 |
Hashes for cxx_image_io-0.0.19-cp311-cp311-macosx_11_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d6c1fd2cf9af1dd91c4050d151287a99cd5c15dc74b210d9475d20cb752b20f8 |
|
MD5 | 8020863bf7bae027877e6190d6ec6a22 |
|
BLAKE2b-256 | 0b2d0567063ee845773147acd4d22fe632f3b59ad2abcf25883467c0da0e3489 |
Hashes for cxx_image_io-0.0.19-cp311-cp311-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9ab8ea25b14fd9f584c7c3a89551452eddfd98389d88a653f7c8caaa20a34976 |
|
MD5 | a2e15627ef6fa4d4ad03139418301bb1 |
|
BLAKE2b-256 | 0d9d7825543523d4ebe1e45e51fb3d5dc4f476399e88fbed6ad5a94f6ca7b297 |
Hashes for cxx_image_io-0.0.19-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 350c465c79aeedaa869d5268be761f48a4e24d2ba6444d53fc3956590d0c9664 |
|
MD5 | 1ee7394449fcd973604c6c3ecda241b5 |
|
BLAKE2b-256 | 1eb215193bc0839b2029dc49c950520a1f6a9d6ea5f8fc10c7dd255762fede88 |
Hashes for cxx_image_io-0.0.19-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9810b65b8bbacf9aeef8bf3ddc01ceb98ecd31bd470bf9f9a878a27022799a1d |
|
MD5 | edb7f2c44fc3e6fab24aca66547862ad |
|
BLAKE2b-256 | ce523969251ec12ea94020954a41dc7d43f02f941eea3f71225a58f95e20670c |
Hashes for cxx_image_io-0.0.19-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 95ad01484abf2bd16c29bbaab9291c32f0db42c2dccbbee47e803102f60d92d3 |
|
MD5 | f964eea48a7203245ad29d172bd24f12 |
|
BLAKE2b-256 | e810fbcd45c5c854c16e1de35ee14e72bb69927aaa57453153c48229048cf105 |
Hashes for cxx_image_io-0.0.19-cp310-cp310-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 01c8cb3028565f29884fef445f28c5e4b45c3383c6efcf7cc16166142ecf9a6f |
|
MD5 | 8a70a07b12e1a3b773c99a15f5c47ce2 |
|
BLAKE2b-256 | 267be598331e380e21f4c4726efc2b9e97a10b46c4966d7e60b559d73e1089db |