1

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.

BUStudent
  • 15
  • 4
  • can you provide an example of your data file? – Teejay Bruno Aug 03 '21 at 20:21
  • How many images do you need to save in a row? What are the height and width of the images in pixels please? The normal way to save an image is in a PNG or JPEG file. What are the time constraints exactly, please? – Mark Setchell Aug 03 '21 at 22:05
  • @MarkSetchell I have to take 7 images in a row. I take an image then move a motor, take image move motor etc. I need this process to be as fast as possible. I believe I have it at 20 seconds for all 7 images as of now (outputting ```.data``` files). At each motor position I take a white light image and another background image (no light) and want to save these image as RGB output in order to later extract the R G and B components into 3 separate images. I cannot use PNG or JPEG in this situation. I need to either save the RGB data by itself or separate the images very quickly during imaging. – BUStudent Aug 04 '21 at 11:54
  • @MarkSetchell The height and width is the max resolution of the camera (2592x1944). I have thought of saving these images to an array then saving all 7 images after the process is done but haven't tried yet. Unsure of whether a raspberry Pi 3B+ has enough RAM to handle that large of an Array. 7*(2592x1944x3) – BUStudent Aug 04 '21 at 11:56
  • Those images are only 15MB each, so 7 will take around 105MB which should be pretty easy for a RasPi. You don't need it as a single contiguous array, you could have a list of 7 images. – Mark Setchell Aug 04 '21 at 12:02
  • You can do a quick test with `im = np.zeros((7,2592,1944,3), dtype=np.uint8)` to see if it works and `print(im.size)` to see the size. – Mark Setchell Aug 04 '21 at 12:11
  • @MarkSetchell Great thank your for the insight I will try this out. – BUStudent Aug 04 '21 at 12:43
  • Can you explain why you cannot use PNG or JPEG please? – Mark Setchell Aug 05 '21 at 09:47
  • I do not want the images to be compressed so as of now I am saving as a tiff file. Ideally I want to save the raw image data into a data file to allow for post processing of the image, but cannot figure out how to save this information into a readable file format. – BUStudent Aug 05 '21 at 13:09
  • It actually seems that tiff is probably the easier route for me to take in terms of its ease of use in Matlab and Python. I am by far an amateur with these topics. Do you know of any helpful online resources that would provide information of different types of image files and compression/processing? – BUStudent Aug 05 '21 at 13:57
  • Wikipedia is a very good source, try Googling `wiki tiff` or `wiki JPEG`. How much RAM does your RasPi have? Try `head -1 /proc/meminfo` Is your RasPi on wired Ethernet? Or wifi? Which model RasPi is it? – Mark Setchell Aug 05 '21 at 14:52
  • We are using a RPi 3B+ that has 895516 kB RAM. It will likely be connected to Wifi but may not be in some situations depending on the situation so I would just assume no Wifi connection – BUStudent Aug 05 '21 at 17:58

1 Answers1

0

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.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432