Search code examples
pythonraspberry-pirgbbinaryfilespicamera

How to save RGB data from RPi Camera then save file to matlab/Python readable format?


I am taking multiple white light images in a row that I want to split into RGB images later on due to time constraints for my application. I currently save the raw RGB image as a .data but cannot figure out how to read the file back into an array to allow me to manipulate it in a separate script. Is there a better way to save this RGB data very quickly so that I have access to it later? or even better split it up into R G and B then save those images individually?

Camera Capture:

self.camera.capture('file_location.data', 'rgb')

Read back into Python (Seperate Script):

path = 'file_location.data'

with open(path, 'rb') as f:
  contents = f.read()

I am able to read the binary file but have not found how to convert contents into an array that I can manipulate.


Solution

  • Here's a way of doing what you ask - it saves the 7 images in a list in memory so that you can take the photos in rapid sequence and then flush them to disk at a more leisurely pace after your experiment is complete.

    You seem to be under the misapprehension that compression means data loss. In the case of PNG, the compression is loss-less, unlike JPEG which is lossy.

    #!/usr/bin/env python3
    
    import numpy as np
    from PIL import Image
    
    # Make 7 random RGB images 2592x1944 and append to list in memory
    imageList = []
    for i in range(7):
       print(f'Creating image {i}')
       im = np.random.randint(0,256,(1944,2592,3), dtype=np.uint8)
       imageList.append(im)
    
    # Show user length of list
    print(f'Number of images in list: {len(imageList)}')
    
    # Save images after experiment is complete
    for i,image in enumerate(imageList):
        filename = f'image-{i}.png'
        print(f'Saving image: {filename}')
        Image.fromarray(image).save(filename)
    

    Sample Output

    Creating image 0
    Creating image 1
    Creating image 2
    Creating image 3
    Creating image 4
    Creating image 5
    Creating image 6
    Number of images in list: 7
    Saving image: image-0.png
    Saving image: image-1.png
    Saving image: image-2.png
    Saving image: image-3.png
    Saving image: image-4.png
    Saving image: image-5.png
    Saving image: image-6.png
    

    If you run the program, you will see that the 7 images are created almost instantaneously, and only the saving to disk at the end takes a while.

    Here are the created files:

    -rw-r--r--@ 1 mark  staff  15132795  6 Aug 11:01 image-0.png
    -rw-r--r--  1 mark  staff  15132768  6 Aug 11:01 image-1.png
    -rw-r--r--  1 mark  staff  15132789  6 Aug 11:01 image-2.png
    -rw-r--r--  1 mark  staff  15132792  6 Aug 11:01 image-3.png
    -rw-r--r--  1 mark  staff  15132790  6 Aug 11:01 image-4.png
    -rw-r--r--  1 mark  staff  15132791  6 Aug 11:01 image-5.png
    -rw-r--r--  1 mark  staff  15132784  6 Aug 11:01 image-6.png
    

    If you want to analyse the memory usage, you can either run htop while the program is running and watch the RAM usage there, or you can run it like this:

    /usr/bin/time -l ./script.py 
    
            6.79 real         6.98 user         0.21 sys
           162914304  maximum resident set size
                   0  average shared memory size
                   0  average unshared data size
                   0  average unshared stack size
               40470  page reclaims
                   0  page faults
                   0  swaps
                   0  block input operations
                   0  block output operations
                   0  messages sent
                   0  messages received
                   0  signals received
                   9  voluntary context switches
                2620  involuntary context switches
         48621173737  instructions retired
         30872454100  cycles elapsed
           145956864  peak memory footprint
    

    Note that you could equally use OpenCV instead of PIL, just use:

    import cv2
    

    and, at the end

    cv2.imwrite(filename, image)
    

    Note that a Raspberry Pi has 4 CPU cores and Python tends to only use one, so if you wanted to be able to store more images, you could start say 3 additional processes that wait for images from the acquisition process and write them to disk. Then you would clear the RAM out of unsaved images at 3 times the rate. This is pretty simple with Redis or Python 3.8 multiprocessing shared memory. If you ran a Redis instance on your Raspberry Pi, it could run without WiFi (as it would be local), but you could pull the images afterwards (or real-time) from your PC for Matlab to process.