javascriptflasklocal-storage

How do I change the opencv webcam of a python file using Flask?


I am working on a face recognition project that sends gen_frame() to video_feed to be rendered in my html file. However, I cannot find the right way to send the localStorage value to the Flask server. Anyone have some suggestions how I can change the webcam with localStorage?

Here is the python attendance_taker.py which contain the gen_frame method:

def gen_frame():
    cap = cv2.VideoCapture(0) # This is what I want to change using localstorage
    face_recognizer = Face_Recognizer()

    while True:
        success, frame = cap.read()
        if not success:
            break

        face_recognizer.process(frame)

        ret, buffer = cv2.imencode('.jpg', frame)
        frame = buffer.tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')`

Here is the javascript code:

window.addEventListener("DOMContentLoaded", function () {
    var webcamSelect = document.getElementById("webcamSelect");

    webcamSelect.addEventListener("change", function () {
        var selectedWebcamIndex = webcamSelect.selectedIndex;
        localStorage.setItem("selectedWebcamIndex", selectedWebcamIndex);
    });

    navigator.mediaDevices
        .enumerateDevices()
        .then((devices) => {
            var videoDevices = devices.filter(
                (device) => device.kind === "videoinput",
            );
            videoDevices.forEach((device, index) => {
                var option = document.createElement("option");
                option.value = index;
                option.text = device.label || `Webcam ${index + 1}`;
                webcamSelect.appendChild(option);
            });

            var selectedWebcamIndex = localStorage.getItem(
                "selectedWebcamIndex",
            );
            if (selectedWebcamIndex) {
                webcamSelect.selectedIndex = selectedWebcamIndex;
            }
        })
        .catch((error) => {
            console.error("Error enumerating devices:", error);
        });
});

app.py

@app.route('/video_feed')
def video_feed():
    return Response(gen_frame(), mimetype='multipart/x-mixed-replace; boundary=frame')

I tried using ajax from jquery, but is not working.


Solution

  • Regarding: Sending data back through to flask

    "I tried AJAX from jQuery, but it's not working", AJAX is perhaps a bit outdated, and if it's not working with jQuery perhaps use regular javascript

    That aside: you can do it off of a POST request directly in your flask server file like so:

    from flask import Flask, render_template, request
    import cv2
    
    
    app = Flask(__name__)
    
    
    def gen_frame(webcam_val):
      cap = cv2.VideoCapture(webcam_val)
      # ...
    
    @app.route('/your/route', methods=["GET", "POST"])
    def get_webcam_value():
      if request.method == 'POST': # method on POST (when form is submitted)
        value = request.form['value'] # gets the value of the input field with the attribute `value` (`name="value"`)
        gen_frame(value) # call your gen_frame function, and pass the value through
        
      return render_template('yourfile.html')
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>your file</title>
    </head>
    <body>
      
      <form action="your/action" method="POST"> <!-- create form with method `POST` -->
        <label>
          <input type="number" name="value" placeholder="camera" /> <!-- created an html input with type `number` and name `value` (to be accessed by our flask) -->
        </label>
    
        <input type="submit" value="change camera" /> <!-- to submit the form when the user is ready -->
      </form>
    
    </body>
    </html>
    

    I don't know how your file structure is setup nor your server code, so let me know if you need anything adjusted

    (posting this as a new answer not an edited one)