djangodjango-viewsvideo-streamingstreaminghttpresponse

How to pass a variable from video view1 (which is inside view2) to view2's template in Django


I have a view home:

def home(request):
    return render(request, 'detection/home.html')

And here is its' template templates/detection/home.html:

{% extends "detection/base.html" %}

{% block content %}

<h1>Camera View</h1>

<img src="{% url 'cam-feed' %}"></img>

{% endblock content %}

which is based on templates/detection/base.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>Document</title>
</head>
<body>
    {% block content %}
    {% endblock content %}
</body>
</html>

In this page, as can be seen from home.html, I show camera output using view cam_feed:

def cam_feed(request):
    return StreamingHttpResponse(gen(VideoCamera(), content_type="multipart/x-mixed-replace;boundary=frame")

which uses the class VideoCamera which is an openCV class to show the camera and which outputs a prediction variable in get_frame:

class VideoCamera(object):
    def __init__(self):
        self.video = cv2.VideoCapture(0)

    def __del__(self):
        self.video.release()

    def get_frame(self):
        _, image = self.video.read()

        ### All the detections

        # Person Existence Classification
        # RGB_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        im = Image.fromarray(image)
        im = im.resize((128, 128))
        img_array = np.array(im)
        img_array = np.expand_dims(img_array, axis=0)
        prediction = int(model.predict(img_array)[0][0])
        
        _, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

cam_feed also uses function gen which passes the camera output in the appropriate form:

def gen(camera):
    while True:
        frame = camera.get_frame()
        yield(b'--frame\r\n'
              b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

How can I send the variable prediction returned from VideoCamera class above (preferably every time a new frame is received and the prediction is made), to template home.html, so that I can output it for the user to see. I know that I can normally pass a dictionary context to home.html but I cannot see a way to pass it from function gen to view home as it is called inside StreamingHttpResponse which is called in <img> tag of home.html.


Solution

  • If you only want to get the prediction for one frame, can't you just add a method for the prediction and call that method in the template-view like this?:

    # where VideoCamera is defined:
    class VideoCamera(object):
        def __init__(self):
            self.video = cv2.VideoCapture(0)
    
        def __del__(self):
            self.video.release()
    
        def get_frame(self):
            # unchanged...
    
        def get_prediction(self):
            _, image = self.video.read()
    
            ### All the detections
    
            # Person Existence Classification
            # RGB_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            im = Image.fromarray(image)
            im = im.resize((128, 128))
            img_array = np.array(im)
            img_array = np.expand_dims(img_array, axis=0)
            prediction = int(model.predict(img_array)[0][0])
            return prediction
    
    # in views.py:
    def home(request):
        cam = VideoCamera()
        prediction = cam.get_prediction()
        return render(request, 'detection/home.html', context={'prediction': prediction})
    

    Also you might want to look at django-channels