1

I have the following code:

import cv2
import numpy as np
import time
import datetime
from flask import *
import random

from threading import Thread


app = Flask(__name__)


def Tracking():
    lower = np.array([35, 192, 65])
    upper = np.array([179, 255, 255])

    video = cv2.VideoCapture(1, 0)

    times = []
    total = 0
    is_round = False

    while True:
        success, img = video.read()
        image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(image, lower, upper)
        blur = cv2.GaussianBlur(mask, (15, 15), 0)

        circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 1, 14,
                                   param1=34, param2=10, minRadius=4, maxRadius=10)

        circles = np.uint16(np.around(circles))

        if (len(circles[0, :]) == 7) and not is_round:
            start_time = time.time()
            is_round = True
            curr_count = 0
            round_total = 0

        elif is_round:
            if len(circles[0, :]) == 1:
                end_time = time.time()
                is_round = False
                time_taken = end_time - start_time
                print('time: ', str(
                    datetime.timedelta(seconds=time_taken))[2:7])

                times.append(time_taken)
                average = sum(times) / len(times)
                print('Avg time: ', str(
                    datetime.timedelta(seconds=average))[2:7])

            elif len(circles[0, :]) < 7:
                curr_count = (7 - round_total) - len(circles[0, :])
                total += curr_count
                round_total += curr_count

            for i in circles[0, :]:
                cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
                cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)

        yield total  


@app.route("/")
def home():
    return render_template('theme1.html')


gen_total = Tracking()  # initate the function out of the scope of update route


@app.get("/update")
def update():
    global gen_total  

    return str(next(gen_total))


if __name__ == "__main__":
    app.run(debug=True)

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <link rel= "stylesheet"  href= "{{ url_for('static', filename='styles.css')}}">

</head>
<body>

    <div class="data">
    <p id="output"></p>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
    <script>
        function update(){
            $.get("/update", function(data){
                $("#output").html(data)
            });
        }
        update()
        var intervalId = setInterval(function() {
            update()
        }, 10000);

    </script>
        
</body>
</html>

I am trying to get the variable 'average' to print to the webpage, i have already added 'total' to the webpage but i am not sure how to add average, this variable will not always have a value as a certain thing has to happen before it is given a value, any help would be appriciated. I am also not sure if this has to be converted to a string to be displayed, ajax is used in the html file to update the page every so often.

15
  • Did you try yielding both values and returning them both from /update? Commented Jul 23, 2022 at 1:34
  • i tried it earlier but maybe i did it wrong.... i'm currently trying it again but when i try to return average in /update it says code is unreachable... also the average variable will not always have a value as a certain thing has to happen before it is given a value, will that be a problem? Thanks Commented Jul 23, 2022 at 1:49
  • I have no idea what your algorithm is or what you plan to do with the missing data, so that's up to you to decide. Maybe fill it in with None. Commented Jul 23, 2022 at 1:51
  • I have tried yielding average and i deleted the return str(next(gen_total)) and replaced it with return str(datetime.timedelta(seconds=average))[2:7] however nothing shows up on the webpage.. i'm getting an error NameError: name 'average' is not defined Commented Jul 23, 2022 at 2:01
  • Maybe try yield dict(total=total, average=average), then respond with a JSON pair to the front end, jsonify(next(gen_total)). I wouldn't worry about date formatting until you have the data heading through the response correctly. Commented Jul 23, 2022 at 2:08

1 Answer 1

1

To yield multiple values from your generator, either use a tuple, list, class, dictionary or other data structure. I'd suggest a dict which is simple but has nice naming semantics. yield dict(total=total, average=average).

Since average is inside of a conditional branch, it's possible that yield is reached without actually initializing this variable, which is illegal. Set a default value that's unconditionally within scope of the yield statement so it's guaranteed to have a value.

Finally, return it as JSON to the client rather than text using Flask's jsonify.

Here's a simplified example you can adapt:

app.py

from flask import Flask, jsonify, render_template


app = Flask(__name__)


def track():
    total = 0
    average = 0

    while True:
        if 1 == 1:
            average += 2

        total += 1
        yield dict(total=total, average=average)


@app.route("/")
def home():
    return render_template("theme1.html")


@app.get("/update")
def update():
    return jsonify(next(gen_total))


if __name__ == "__main__":
    gen_total = track()
    app.run(debug=True)

templates/theme1.html

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Document</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
  <div class="data">
    <p id="average"></p>
    <p id="total"></p>
  </div>
  <script>
function update() {
  $.get("/update", function (data) {
    $("#average").text("average " + data.average);
    $("#total").text("total " + data.total);
  });
}
update();
var intervalId = setInterval(update, 10000);
  </script>
</body>
</html>
Sign up to request clarification or add additional context in comments.

10 Comments

hey, i've added the jsonify line to my code... that has removed the brackets.. now how do i make it so in html average and total have their own variables so i can seprately edit css? Thanks
becuase at the minute they are both assigned the output value i think
Just add another output element with a different id. It's a small modification of the code you already have. See update. I hope you can take it from here.
average [object HTMLParagraphElement] total [object HTMLParagraphElement]
That's the output i'm currently getting
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.