Close

Working with the raspberry pi v2 camera, raw and sliced data

A project log for Getting Cozy with the Diffraction Limit

Do you hate the diffraction limit when you take an image of a scene? Me too! Here is a story of trying to do my best to correct it!

sciencedude1990sciencedude1990 04/03/2021 at 15:280 Comments

The raspberry pi v2 camera (i.e., the Sony image sensor) is great since it has small unit size for the imaging pixels.  Getting the raw information from the sensor is straightforward, but speed is important for getting the training done on this setup.

First thing - let's not burn the sd card!  So, if you are taking lots of images, create a ramdisk to place those images!

First, make the directory:

sudo mkdir /mnt/ramdisk

Edit the rc.local file

sudo nano /etc/rc.local

Add the lines above exit 0

mount -o size=30M -t tmpfs none /mnt/ramdisk

/bin/chown pi:root /mnt/ramdisk

/bin/chmod 777 /mnt/ramdisk

Reboot, then check the file with

df -h

Now, start raspistill.  In this case, we will leave it running.  This way, you can take time lapse photos very quickly.  Here is the command (using MATLAB syntax, but you could start it with anything that can ssh into the pi):

['nohup raspistill -n -t 0 -drc off -ss ' num2str(shutter_time) ' -ex off -awb off -ag ' num2str(analog_gain) ' -dg ' num2str(digital_gain) ' -r -s -o /mnt/ramdisk/' f_name_img ' > /dev/null 2>&1 &']

Next, get the process id from:

pgrep raspistill

And then to take a picture, you use a modified version of the kill command (strange, but it works):

['kill -USR1 ' num2str(raspistill_pid)]

Next - as you might have noticed, I don't need the whole raw image.  I just need a part of it.  You can write a small python script that resides on the pi that can slice the raw image.  Once the .jpg file has been created, you run the python script to slice out what you need to produce a .bin file.

['python test.py -i /mnt/ramdisk/' f_name_img ' -o /mnt/ramdisk/' f_name_bin ' -s ' num2str(slice_row) ' -f ' num2str(N_slice)];  

Here is the listing of test.py - pardon the indenting - you'll have to double check it if you use this script...

#!/usr/bin/python

# imports
import sys, getopt, io, os

# main, usage from the pi@raspberrypi command line:
# python test.py -i /mnt/ramdisk/image_1.jpg -o /mnt/ramdisk/hi.bin
def main(argv):
    inputfile = ''
    outputfile = ''
    startrow = 0
    stoprow = 0

    # Get the inputfile and outputfile, and the start and stop row from the input arguments
    try:
        opts, args = getopt.getopt(argv,"hi:o:s:f:",["ifile=","ofile=","snum=","fnum="])
    except getopt.GetoptError:
        print 'test.py -i <inputfile> -o <outputfile> -s <startrow> -f <stoprow>'
        sys.exit(2)

    for opt, arg in opts:
        print arg
        if opt == '-h':
            print 'test.py -i <inputfile> -o <outputfile> -s <startrow> -f <stoprow>'
            sys.exit()
        elif opt in ("-i", "--ifile"):
            inputfile = arg
        elif opt in ("-o", "--ofile"):
            outputfile = arg
        elif opt in ("-s", "--snum"):
            startrow = int(arg)
        elif opt in ("-f", "--fnum"):
            stoprow = int(arg)

    # echo the input and output file names
    print 'Input file is ', inputfile
    print 'Output file is ', outputfile
    print 'Starting row ', startrow
    print 'Stop row ', stoprow

    isfile = False

# Better be a filename...
    if isinstance(inputfile, str) and os.path.exists(inputfile):
        isfile = True
    else:
        raise ValueError

    if isfile:
        # open the file and read the data, in bytes
        file = open(inputfile, 'rb')
        img = io.BytesIO(file.read())
    else:
        raise ValueError

    # from the back of the file, the raw is the "offset"
    offset = 10270208
    data = img.getvalue()[-offset:]

    # make sure the first bytes of the raw part at BRCM
    assert data[:4] == 'BRCM'.encode("ascii")

    # Check the start and stop row inputs
    assert startrow >= 0
    assert stoprow >= 1
    assert (startrow + stoprow) <= 2479

    # Slice out the rows
    data_slice = data[(32768 + startrow * 4128) : (32768 + (startrow + stoprow - 1) * 4128 + 4128)]

    # save the binary to the output file
    f = open(outputfile, 'wb')
    f.write(data_slice)
    f.close()

if __name__ == "__main__":
   main(sys.argv[1:])

#### Done script

So, now you can load the .bin file which just has the rows of the image that you need!  Here is the MATLAB code that reads the binary raw file.

function [ret] = load_bin_raw_v2(f_name)

%% Load the binary values
% Open the jpg file
f = fopen(f_name, 'r');

% Read the file, assuming 8 bit values
bin = fread(f, '*uint8');

% Close the file
fclose(f);

%% Get the raw data and convert
% Reshape
raw_data_reshape = reshape(bin, 4128, []);

% Crop
raw_data_crop = uint16(raw_data_reshape(1 : 4100, :));

% Index for the MSBs and LSBs
temp_ind = 1 : 4100;
temp_ind = reshape(temp_ind, 5, []);

% MSBs
temp_ind_msb = temp_ind(1 : 4, :);
temp_ind_msb = reshape(temp_ind_msb, [], 1);

% LSBs
temp_ind_lsb = reshape(temp_ind(5, :), [], 1);

% The output
output = bitshift(raw_data_crop(temp_ind_msb, :), 2);
output(1 : 4 : end, :) = output(1 : 4 : end, :) + bitand(bitshift(raw_data_crop(temp_ind_lsb, :), -6), 3);
output(2 : 4 : end, :) = output(2 : 4 : end, :) + bitand(bitshift(raw_data_crop(temp_ind_lsb, :), -4), 3);
output(3 : 4 : end, :) = output(3 : 4 : end, :) + bitand(bitshift(raw_data_crop(temp_ind_lsb, :), -2), 3);
output(4 : 4 : end, :) = output(4 : 4 : end, :) + bitand(bitshift(raw_data_crop(temp_ind_lsb, :), -0), 3);

ret = output';

Discussions