Capantonio95
Capantonio95

Reputation: 43

How can i load a image in Python, but keep it compressed?

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:

  • one time from Frame12 to Frame24,
  • second time from Frame2 to Frame7,
  • etc.

    load all images take me too much memory and load every time a new sequence is a long task to do.
    there is a function/method to load the image in a program, but keep compressed? Can I save these images on memory to be ready-to-use, but with low memory occupation?

    Upvotes: 4

    Views: 9824

  • Answers (2)

    Mark Setchell
    Mark Setchell

    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:

    enter image description here

    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

    trev0ck
    trev0ck

    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

    Related Questions