user898082
user898082

Reputation:

Good way to capture an image to memory and serve it with flask

I have a Raspberry Pi with an attached webcam and a python flask-script that sends out some informations as jsons and under the route /image.jpg an image.

In the past i capture the image to storage and served it from there but I feel it's more elegant (?) to only have it in memory.

I tried several iterations of something like this

class Repository( ):
    def __init__( ... ):

        self.temperature = None
        ...
        self.image = None
        ...
        self._config = {
            ...
            "camera":           picamera.PiCamera( ),
            ...
            }

    def initialize( self ):
        ...
        self._create_image( )
        ...

    def _create_image( self ):
        self._config[ "camera" ].rotation = 180
        self._config[ "camera" ].annotate_background = picamera.Color( 'black' )
        self._config[ "camera" ].annotate_text = get_time_stamp( )
        self._config[ "camera" ].annotate_text_size = 25
        self._config[ "camera" ].flash_mode = 'auto'

        # old way: self._config[ "camera" ].capture( '/app/public/' + "image.jpg", quality = 100 )
        
        stream = BytesIO()
        self._config[ "camera" ].start_preview()
        sleep(2)
        self._config[ "camera" ].capture( stream, quality = 100, format = 'jpeg' )
        # "Rewind" the stream to the beginning, so we can read its content
        stream.seek( 0 )
        self.image = stream

and then serve it like this

@app.route( "/test/image.jpg" )
def return_image( ):
    return send_file( data.image, mimetype = 'image/jpeg' )

I can see the image once (and since i have job that recalls _create_image every 60sec), every 1 minute. between that I get:

ValueError: I/O operation on closed file.

which makes sense, thinking that I needed to reverse the stream in the first place. So I tried something naive like this:

@app.route( "/test/image.jpg" )
def return_image_test( ):
    test = data.image
    data.image.seek( 0 )
    return send_file( test, mimetype = 'image/jpeg' )

Well it seems like i am not understanding these streams and their nature of exhausting correctly. I bet the solution here is simple but I cannot wrap my head around it. obviously having something that I need to reverse every time also seems suboptimal. But I wasnt able to come up with a better way how flask could send out images.

please send help.

(in case that is important, i use waitress to serve this thing)

serve( app, host = "0.0.0.0", port = 80 )

Upvotes: 1

Views: 607

Answers (1)

user898082
user898082

Reputation:

Ok,

all I had to do was

    # save the read bytes instead of the stream
    self.image = stream.read()

and returning it like this

@app.route( "/image.jpg" )
def return_image( ):
    response = make_response( data.image )
    response.headers.set( 'Content-Type', 'image/jpeg' )
    return response

Upvotes: 1

Related Questions