Reputation: 43
I have a series of images, all available both on JP2 and PNG, and I need to load this image on a python program to show them in a sequence. Now I need only show a part of the sequence, for example:
Upvotes: 4
Views: 9824
Reputation: 207465
You can read the lovely, small JPEG/PNG/JP2 images into memory as a bunch of bytes and hold them there compressed with the same size as they have on disk and then uncompress them from memory when you need them.
First, let's look at the memory required by a 1280x1024 image of RGB888 in memory - its a whopping 3.9MB:
# Decompressed image in memory takes 3.9MB memory
im = np.zeros([1280,1024,3], dtype=np.uint8)
# print(im.nbytes) => 3932160
Now let's look at a JPEG the same size:
Here it is on disk, with ls -l
:
-rw-r--r--@ 1 mark staff 47276 2 Apr 17:13 image.jpg
And here it is still compressed in memory, also at 47kB or just 1.2% of the size:
# Same image as JPEG takes 47kB of memory
with open('image.jpg','rb') as f:
jpg = f.read()
# print(len(jpg)) => 47276
Now when you want an image, decompress it from memory rather than from disk
# Read with 'imageio'
from io import BytesIO
import imageio
numpyArray = imageio.imread(BytesIO(jpg))
# print(numpyArray.shape) =>(1024, 1280, 3)
# Or, alternatively, and probably faster, read with OpenCV
import cv2
numpyArray = cv2.imdecode(np.frombuffer(jpg,dtype=np.uint8), -1)
# print(numpyArray.shape) =>(1024, 1280, 3)
Another, totally different option that will decode miles faster, but will only reduce the memory footprint by a factor of 3 is to palettise the images. You reduce the number of colours down to less than 256 unique colours, and store a palette with 256 colours. At each pixel location, you then store a single byte which is the index into the palette, rather than 3 bytes of RGB. This will reduce your memory usage from 3.9MB/image to 1.3MB/image. It will not require any decoding. but may result in slight loss of colour fidelity and/or banding - which may or may not be an issue depending on the quality of your camera/images.
That looks something like this:
from PIL import Image
import numpy as np
im = Image.open('image.jpg')
# Make into Numpy array - size is 3.9MB
a = np.array(im)
# Now make a 256 colour palletised version
p = im.convert('P',palette=Image.ADAPTIVE)
# Make into Numpy array - size is now only 1.3MB
a = np.array(p)
Upvotes: 5
Reputation: 9
PIL is the Python Imaging Library which provides the python interpreter with image editing capabilities.
Windows: Download the appropriate Pillow package according to your python version. Make sure to download according to the python version you have.
To import the Image module, our code should begin with the following line:
from PIL import Image
Open a particular image from a path
#img = Image.open(path)
# On successful execution of this statement,
# an object of Image type is returned and stored in img variable)
try:
img = Image.open(path)
except IOError:
pass
# Use the above statement within try block, as it can
# raise an IOError if file cannot be found,
# or image cannot be opened.
Retrieve size of image: The instances of Image class that are created have many attributes, one of its useful attribute is size.
from PIL import Image
filename = "image.png"
with Image.open(filename) as image:
width, height = image.size
#Image.size gives a 2-tuple and the width, height can be obtained
Some other attributes are: Image.width, Image.height, Image.format, Image.info etc.
Save changes in image: To save any changes that you have made to the image file, we need to give path as well as image format.
img.save(path, format)
# format is optional, if no format is specified,
#it is determined from the filename extension
from PIL import Image
def main():
try:
#Relative Path
img = Image.open("picture.jpg")
width, height = img.size
img = img.resize((width/2, height/2))
#Saved in the same relative location
img.save("resized_picture.jpg")
except IOError:
pass
if __name__ == "__main__":
main()
Upvotes: -1