waveform80 / picamera

A pure Python interface to the Raspberry Pi camera module
https://picamera.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
1.57k stars 357 forks source link

Add ability to capture raw camera data #52

Closed waveform80 closed 10 years ago

waveform80 commented 10 years ago

Picamera's current "raw" capture capabilities only extend as far as outputting raw YUV or RGB data (i.e. the same thing raspistillyuv does), not the equivalent of raspistill -raw (which outputs a JPEG along with "truly" raw data from the camera prior to various bits of processing being performed). There's apparently some interest in getting access to "true" raw output and it doesn't look difficult so this should be added for the next release.

Need to consider the best method of doing this though: are people interested in JPEG+raw output (as with raspistill -raw) or do they just care about the raw bit (in which case it's a waste of time outputting the JPEG).

m1ari commented 10 years ago

I could be interested in this for a project I'm working on.

Ideally I'd like to be able to get both the Raw and jpg outputs although having them in separate files would be more useful rather than having to parse a jpg (or other image type) to get the raw data out.

NB: It may also be useful to add a note to the docs to show that the current raw formats are post GPU processing rather than the true raw data.

waveform80 commented 10 years ago

Good point about the docs - I'll definitely add that for the next release.

Turns out this issue is tied in to #59 (I think the raw bayer data gets included in a similar manner to the set of default Exif tags; at least it only seems to work when the still output port is set to opaque encoding instead of I420). I'm afraid that means it's unlikely that I'll be able to provide "pure" raw data outside of the JPEG and it definitely means that, like the Exif stuff mentioned in #59, the bayer data won't be accessible when performing high-speed video-port based captures. Still, it's not difficult to accomplish assuming I can figure out how to handle the port encoding stuff!

Anyway, all that means that if I can get #59 fixed for the next release (which I'm intending to at the moment), I'll get this one done as well as it's a trivial change on top of it.

SpectroEric commented 10 years ago

I like the PiCamera API and used it for the rgba – data in a stream successfully. For a small spectrometer I’m interested in the pure raw bayer data of the RaspberryPi Camera. With „raspistill –raw ..“ it works fine but to improve performance I think it would be better to work with PiCamera and streams. My little test below shows only a stream of a length of about 2,300,000 Bytes. Therefor the assert test below fails. So no raw data is. What can I do? The newest version (1.3) of PiCamera is installed.

import io
import time
import picamera

stream=io.BytesIO()
with picamera.PiCamera() as camera:
  camera.resolution = (2592, 1944)
  camera.capture (stream, format='jpeg', bayer=True)
  print format(stream.seek(0,2),',d')
  stream.seek (-6404096, io.SEEK_END )
  assert stream.read(4) == 'BRCM'
  camera.close()
waveform80 commented 10 years ago

Hmm - your code works just fine for me on picamera 1.3 (the captured stream has a size of over 9Mb, and the "BRCM" code appears 6.4Mb from the end). My suspicion is that you haven't actually got picamera 1.3 installed (under 1.2 the bayer keyword would simply be ignored by the encoder rather than raise an error). A simple way to test whether you've got 1.3 is to try raising the framerate above 30:

import picamera
with picamera.PiCamera() as camera:
    camera.resolution = (640, 480)
    camera.framerate = 60

Any version below 1.3 will report you can't go above 30fps (even if the firmware supports it), whilst 1.3 will permit it.

SpectroEric commented 10 years ago

Thank you for your helpful and quick response. Your version test worked fine – a method in PiCamera to show the version would be nice. Indeed I had two versions of PiCamera installed. The 1.2 Version was not load via apt-get so it was not removed when I uninstalled while upgrading. Unfortunately python’s sys.path preferred the old version. After manually removing that library everything works fine.

waveform80 commented 10 years ago

Good point about including the version in the library - I'll add that as an enhancement for the next release

mgrady3 commented 10 years ago

I know this is a bit old now but I am definitely interested in getting at the raw data from the camera for image analysis in a scientific application. What's the easiest way to go about pulling the raw bayer data from the exif assuming you give the bayer=True argument when using camera.capture()?

Specifically I am interested in calculating exact pixel intensities (brightness - the Y value) for use in an electron diffraction experiment and want to eventually be able to use the raw camera data before any post-processing by the GPU has been done. I do realize that this might not be the easiest task. I followed this thread, http://www.raspberrypi.org/forums/viewtopic.php?f=43&t=44918 , where they worked on a c based tool to convert the raw bayer data into an adobe DNG format but it didn't seem all that straightforward. I'd like to continue to do all the analysis in python if possible as well.

if its not going to be easy to implement in python for now I can live with just taking the post-processed yuv data direct from camera.capture() with the 'yuv' argument

waveform80 commented 10 years ago

This is probably something that deserves its own topic in the documentation. I'll open an enhancement ticket for this as I have a suspicion there's quite a few people wanting to play with this (and who probably would quite like something a bit simpler than C to do it in!). The short version is that the bayer data is tacked on as the last 6404096 bytes of the stream so you can easily extract it like so:

import io
import shutil
import picamera

with picamera.PiCamera() as camera:
    stream = io.BytesIO()
    camera.capture(stream, format='jpeg', bayer=True)
    stream.seek(-6404096, io.SEEK_END)
    with io.open('output.raw', 'wb') as f:
        shutil.copyfileobj(stream, f)

You can check the output is the raw data as the first four bytes should spell out 'BRCM' (this is what picamera's test suite checks when testing bayer data captures). As mentioned by jbeale in the form post you linked to, the first 32k of that data is a header, the rest is image data (except for the last 26112 bytes which are unknown purpose). If you don't care about the header, just add 32768 to the seek in the code above.

The trickier bit is getting colour out of the bayer data. This isn't something I've done before but reading through that thread I don't think it'll be terribly difficult once the raw data is loaded into a numpy array. Looks like it should involve a bit of slicing and stacking.

jason-curtis commented 5 years ago

If anyone's interested in an implementation of this (access to the raw data as a numpy array, as well as a simple demosaic to RGB) in a library that does not require the presence of camera hardware, check out my team's fork: https://github.com/OsmoSystems/picamraw/