title: Taking photos with Flask displays slowly
body: <p>I'm trying to take photos with flask and opencv. The idea is that going to a URL <code>&lt;flask-servers-ipaddress&gt;:5000/take-photo</code> will take a photo and display it in the browser.</p>
  <p>Unfortunately, the data is loading very slowly... my attempts at speeding it up have not worked.</p>
  <p><a href="https://i.stack.imgur.com/jqR0l.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jqR0l.gif" alt="enter image description here" /></a></p>
  <h1>Simple Code</h1>
  <p>Run as a standard flask app (<code>flask run --host=0.0.0.0</code>). You can then load the photo on any local device by going to <code>&lt;flask-server-ipaddress&gt;:5000/take-photo</code></p>
  <pre class="lang-py prettyprint-override"><code>import cv2
  import flask
  
  app = flask.Flask(__name__)
  
  # Setup camera
  cap = cv2.VideoCapture(0)
  cap.set(cv2.CAP_PROP_BUFFERSIZE, 5)
  
  @app.route('/')
  def hello_world():
      return 'Hello, World!'
  
  @app.route('/take-photo')
  def take_photo():
      ret, frame = cap.read()
      success, encoded_image = cv2.imencode('.png', frame)
      resp = flask.make_response(encoded_image.tobytes())
      resp.content_type = &quot;image/jpeg&quot;
      return resp
  </code></pre>
  <h1>Multiprocessing version</h1>
  <p>Here I tried to speed it up by reading frames in a separate process and passing them through a queue... it didn't work. In retrospect the slowdown is probably in flask since the image starts loading quickly but takes a long time to finish.</p>
  <pre class="lang-py prettyprint-override"><code>import cv2
  import flask
  import time
  
  from multiprocessing import Process, Queue
  
  app = flask.Flask(__name__)
  
  def camera_process(queue):
      cap = cv2.VideoCapture('/dev/video0')
      cap.set(cv2.CAP_PROP_BUFFERSIZE, 6)
  
      while True:
          # Read the frame
          ret, frame = cap.read() 
  
          # If the encoding was successful, put it in the queue and clear
          if ret:
              queue.put(frame)
  
          # Clear out any old frames
          if queue.qsize() &gt; 1:
              queue.get()
  
          time.sleep(1/24)
  
  queue = Queue(2)
  process = Process(target=camera_process, args=(queue,))
  process.start()
  
  @app.route('/')
  def hello_world():
      return 'Hello, World!'
  
  @app.route('/take-photo')
  def take_photo():
      frame = queue.get()
      success, encoded_image = cv2.imencode('.png', frame)
      resp = flask.make_response(encoded_image.tobytes())
      resp.content_type = &quot;image/jpeg&quot;
      return resp
  </code></pre>
  <h1>System Notes</h1>
  <ul>
  <li>Client computer is a recent laptop (gen11 i5, etc). <code>top</code> shows that most resources are free</li>
  <li>Flask server is a raspberry pi 4, 8GB RAM. Likewise, <code>top</code> shows most resources to be free (except when running the multiprocessing code with no <code>time.sleep</code>)
  <ul>
  <li>Camera is a USB webcam</li>
  </ul>
  </li>
  </ul>