Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Fix inaccurate Live preview #23
While it's flagged in the documentation, the suggested workaround of setting the camera to full resolution doesn't appear to get the live preview and taken image to match.
For context, I'm creating a stop motion animation package. The 'onion-skinning' effect is working perfectly with the Alpha preview laid over the top of the last image taken (via Pygame), but since the live preview isn't an accurate representation of the actual image, it's impossible to align them.
If anyone has got a suggestion on how to post-process the image via PIL / Pygame in the short-term, I'd really appreciate the input. Any information on if/when there might be a fix / workaround would be really appreciated.
Thanks for the library - it's otherwise fantastic!
Interesting - I've never tried actually overlaying the preview with a taken image - I'd just assumed the two were the same based on a quick eye-balling of a few captures, and comments in the forums that this was the way to compensate. Is there any chance you could attach a capture of the overlay so I can see exactly how they're mis-aligned? There's a slight possibility that the fix for #21 (which I'm working on today) might be applied similarly to previews and captures, but it rather depends on what sort of mis-alignment we're looking at (smaller, larger, offset?).
In the meantime, assuming the mis-alignment we're talking about is, say, smaller (the captured area is larger than the preview), the Image.crop method in the PIL library is probably the simplest to work around it (assuming you can figure out the crop-box required):
import io import picamera from PIL import image with picamera.PiCamera() as camera: camera.resolution = camera.MAX_IMAGE_RESOLUTION stream = io.BytesIO() camera.capture(stream, format='jpeg') stream.seek(0) img = Image.open(stream) # Crop 10 pixels off the left and right, and 20 off the top and bottom cropped = img.crop((10, 20, 10, 20)) cropped.save('foo.jpg')
(untested - this is just off the top of my head)
Yes, the captured image is markedly larger than the preview - the final image is zoomed out compared to the preview (much more on the edges). Sorry, I don't have a preview to hand right now, but the demonstration images in your documentation are pretty accurate representations of the difference.
I've actually managed to get the preview and the capture at full resolution (using windowed mode for the preview) and the alpha preview and taken image then match! Sadly, at the average res for a Raspberry Pi screen (720p ish), you're only getting around a quarter of the actual image, so it's still not a good solution for my stop motion animation app, sadly.
I've tried exactly halving the resolution of the camera sensor / preview window to try and emulate the full-resolution match-up at a more usable resolution, but the same zoomed out mis-matching kicks in again. Frustrating!
The PIL method you've mentioned could work, thanks for that. It'll take a lot of eye-balling and guesswork, but it's certainly worth a try... I don't suppose you (or anyone) knows the maths surrounding the differences between preview / actual image? Any information might be useful (my maths is utterly abysmal).
I'll try and get an example of the overlay / taken image if possible.
Thanks again and keep up the great work.
Ahh, I probably need to make the docs clearer: the only time the preview matches the capture area at the moment is when the camera's resolution is set to maximum (2592x1944). At any resolution other than that, the preview is drawn from the 1920x1080 pixels at the centre of the camera's sensor (the "video area") and scaled to the requested resolution, while the capture uses the full area (scaled down to the requested resolution). That's what the bit at the end of the Preview vs Still Resolution is going on about. Unfortunately this just seems to be an artifact of the way the preview port of the camera works.
Come to think of it, though, there is one other occasion when the preview matches the capture area. Try using the "use_video_port=True" option on the capture methods; when the camera uses the video port for stills it should be selecting from the same region that the preview draws from. Unfortunately this comes with a bunch of caveats (no exif tags, certain effects disabled, and the images tend to look grainier).
I think those are your only two options right now - run at full res and scale images down with PIL/pygame afterward, or capture with use_video_port=True. If you need a hand with the maths just post the res you're capturing at and the res that you want - I'm sure I can bash together some simple code for it.
Having said all that, issue #21 may provide an answer to this. I've been working with the resizer and the camera's video port today and I think I've got it up to full resolution (albeit at a reduced framerate of 15fps). It's possible I can do the same for the preview system so it'll always match the capture area. I've haven't had the chance to experiment with this bit yet though.
Anyway, I'll leave this open for now but I suspect ultimately I'll be closing it as a dupe of #21 (assuming the resizer works with the preview the way I expect it will).
No dice - the 'use_video_port = True' option doesn't seem to affect the end results in any way with my code.
I'm guessing this is because I'm not using the stream method for capture (which is too grainy / low fidelity for my purpose)? Either that our I haven't got a grasp on how to use the option correctly.
So close, but yet so far - here's a gist of my current code, I'd really appreciate it if you'd take a look and see if the use_video_port option can be applied here (and how)...
At the moment I'm stuck with forcing full resolution on the sensor, using a full screen preview (which is squished to fit on my screen with black borders either side), scaling a preview image to display behind the camera preview (when in Alpha preview mode). It works for creating the onion-skinning effect, but since the images as so huge there's massive lag. Also, the end results are in 4:3, which isn't ideal for uploading stop motion animations to YouTube :)
All my problems would be solved if the the preview used the full camera sensor, regardless of the resolution you set the camera to. Do you think something like this would require a full-on firmware fix?
I've got a deadline on this of the end of the week on this and I'm wondering if I'm barking up the wrong tree.
Ah, good stuff - I take it you've managed to get a capture the same size as the preview (presumably in some wide-screen aspect ratio) using use_video_port=True? If so, that's probably your best route forward right now. Admittedly the quality won't be as good as using the capture port (which uses the full resolution of the sensor and performs some interpolation to produce a better quality image), but I'm hopeful I can add that capability with the resizer component. I've skimmed through the gist you linked to - looks good, though I guess it's a little out of date if you've got the use_video_port bit working. If I can find the time this week I'll have a go at using it with the development copy of picamera to see if I can get the full-quality stuff working.
Thanks for the advice and help.
I've uploaded the topic of our discussion, a RasPi camera module stop motion animation application, to github:
Feel free to have a play around (and tips on my terrible coding would be welcome).
Thanks again - you've been really helpful.
Given the resizer now (mostly) works, there's a couple of possible ways of solving the disparity between capture and preview sizes. The documentation should be enhanced for 1.2 to properly describe both methods (use_video_port or set full-res + resize), then I think we can reasonably close this.