How to load an image from a io.BytesIO object

3,237 views
Skip to first unread message

Federico daniele

unread,
May 12, 2014, 11:57:52 AM5/12/14
to kivy-...@googlegroups.com
Hi, I´m using a Raspeberry Pi with camera and kivy. The camera allows me to capture an image to a stream. The picamera docs  then shows how to load that into a PIL Image, as follows:

import io
import time
import picamera
from PIL import Image as PILImage
# Create the in-memory stream
stream = io.BytesIO()
with picamera.PiCamera() as camera:
    camera.start_preview()
    time.sleep(2)
    camera.capture(stream, format='jpeg')
# "Rewind" the stream to the beginning so we can read its content
stream.seek(0)
image = PILImage.open(stream)

I want to load that image to an foto(Image) widget, without having to write it to memory, I've tried:

        self.cam.capture(self.stream,'jpeg')
        self.cam.close()
        self.stream.seek(0)
        self.PILim= PILImage.open(self.stream)
        self.tex = Texture.create(size=(1240,980), colorfmt='rgb') 
        self.tex.blit_buffer(self.PILim.tostring())
        self.foto.texture = self.tex
        self.stream.seek(0)
        self.foto.reload()

I've also tried to load it directly from the stream, without using a PIL object, doing something like 

self.foto.source = self.stream

Getting an 'source only accepts string as source' error. 
I want to take advantage of not having to write the 'jpg' file to the sdcard, I guess it would be much faster if the image is already in RAM


Federico daniele

unread,
May 12, 2014, 2:05:52 PM5/12/14
to kivy-...@googlegroups.com
I forgot to mention., none of this worked

Federico daniele

unread,
May 21, 2014, 9:35:01 AM5/21/14
to kivy-...@googlegroups.com
I´ve managed to load the images from the picamera doing:

import io
import picamera as p
from kivy.graphics.texture import Texture
from kivy.graphics import Rectangle
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class testApp(App):
   
   
def build(self):    
       
self.b= BoxLayout()
       
self.image_composition = Image()
       
self.cam = p.PiCamera()
       
self.cam.resolution = 1600,896
       
self.stream=io.BytesIO()
       
self.cam.capture(self.stream, 'rgb')
       
self.cam.close()
       
self.stream.seek(0)
       
self.tex = Texture.create(size=(1600,896), colorfmt='rgb')
       
self.tex.blit_buffer(self.stream.getvalue(), colorfmt='rgb', bufferfmt='ubyte')
       
with self.image_composition.canvas:
           
Rectangle(texture = self.tex, size = (1600,896))
       
print 'final'
       
self.b.add_widget(self.image_composition)
       
return self.b


testApp
().run()


If someone use the code above, it must be noted that: 
1. the image in self.tex is upside down. This is easily solved using self.cam.vflip = True
2. the photo taken have a horizontal resolution that is multple of 32 and a vertical that is multiple of 16.  If we use a resolution other than that, the picamera module will round up the resolution and fill the space left with zeros (or something like that). So that must be taken into account when setting the texture size

The issue that I have now is that it seems that the rpi runs out of gpu RAM. I´m  not quite sure how to remove previous textures created this way, as I take several photos and then make a bigger image composition. 
I´ve already tried adding

Cache.remove('kv.texture')

but it doesn´t do the job.
Any Ideas??

Reply all
Reply to author
Forward
0 new messages