Cannot Access Variable In While Loop Inside Function Python

Issue

I have a program that is involved with flask and python, It is actually part of a larger program that recognizes license plates and does other things at the same time, I want to access a variable that is inside a while loop and that loop is inside a function. The boxes variable at the bottom of the code is the variable I am talking about but no matter what I try, it is not possible. The final result is : NameError: name ‘boxes’ is not defined. I am really confused now how to solve this problem, Is there anyone who can help me? In these situations, how can I access my variable from outside the function? Even though I changed the variable to global, it is still not accessible. This is one of the ways I tried

This is Flask.py

from flask import Flask, render_template, Response
from camera import CameraStream
import cv2
import os
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as viz_utils
from object_detection.builders import model_builder
from object_detection.utils import config_util
import tensorflow as tf
from keras.models import load_model
from keras.preprocessing.image import img_to_array
import numpy as np
import functools
import imutils
import math
from datetime import datetime
import mysql.connector as mysql
import time

app = Flask(__name__)

cap = CameraStream().start()


@app.route('/')
def index():
    """Video streaming home page."""
    return render_template('index.html')

##################################################################################
#### Load Check points, config files, labelmap and Detect License plate Object ###
##################################################################################
CONFIG_PATH = './pipeline.config'
CHECKPOINT_PATH = './training'
# Load pipeline config and build a detection model
configs = config_util.get_configs_from_pipeline_file(CONFIG_PATH)
detection_model = model_builder.build(model_config=configs['model'], is_training=False)

# Restore checkpoint
ckpt = tf.compat.v2.train.Checkpoint(model=detection_model)
ckpt.restore(os.path.join(CHECKPOINT_PATH, 'ckpt-52')).expect_partial()

@tf.function
def detect_fn(image):
    image, shapes = detection_model.preprocess(image)
    prediction_dict = detection_model.predict(image, shapes)
    detections = detection_model.postprocess(prediction_dict, shapes)
    return detections

category_index = label_map_util.create_category_index_from_labelmap('label_map.pbtxt')

def streaming():
    while cap:
        frame = cap.read()

        # Check That If Frame Is Capturing Or Not
        if frame is None:
            print("disconnected!")

        # You Can Adjust The Streaming Window size 
        frame = cv2.resize(frame, (0,0), fx=0.4, fy=0.4)

        image_np = np.array(frame)

        input_tensor = tf.convert_to_tensor(np.expand_dims(image_np, 0), dtype=tf.float32)
        detections = detect_fn(input_tensor)

        num_detections = int(detections.pop('num_detections'))
        detections = {key: value[0, :num_detections].numpy()
                for key, value in detections.items()}
        detections['num_detections'] = num_detections

        # detection_classes should be ints.
        detections['detection_classes'] = detections['detection_classes'].astype(np.int64)

        label_id_offset = 1
        image_np_with_detections = image_np.copy()

        viz_utils.visualize_boxes_and_labels_on_image_array(
                    image_np_with_detections,
                    detections['detection_boxes'],
                    detections['detection_classes']+label_id_offset,
                    detections['detection_scores'],
                    category_index,
                    use_normalized_coordinates=True,
                    max_boxes_to_draw=5,
                    min_score_thresh=.8,
                    agnostic_mode=False)

        detection_thereshold = 0.7
        image = image_np_with_detections
        # Scores, boxes and classes above threhold
        scores = list(filter(lambda x: x> detection_thereshold, detections['detection_scores']))
        global boxes
        boxes = detections['detection_boxes'][:len(scores)]
        classes = detections['detection_classes'][:len(scores)]

        frame = cv2.imencode('.jpg', image_np_with_detections)[1].tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concate frame one by one and show result

print(boxes)

@app.route('/video_feed')
def video_feed():
    """Video streaming route. Put this in the src attribute of an img tag."""
    return Response(streaming(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == '__main__':
    app.run(host='127.0.0.1', threaded=True)

This is camera.py

from threading import Thread, Lock
import cv2


class CameraStream(object):
    def __init__(self, src="rtsp://admin:[email protected]:554/1/1"):
        self.stream = cv2.VideoCapture(src)

        (self.grabbed, self.frame) = self.stream.read()
        self.started = False
        self.read_lock = Lock()

    def start(self):
        if self.started:
            print("already started!!")
            return None
        self.started = True
        self.thread = Thread(target=self.update, args=())
        self.thread.start()
        return self

    def update(self):
        while self.started:
            (grabbed, frame) = self.stream.read()
            self.read_lock.acquire()
            self.grabbed, self.frame = grabbed, frame
            self.read_lock.release()

    def read(self):
        self.read_lock.acquire()
        frame = self.frame.copy()
        self.read_lock.release()
        return frame

    def stop(self):
        self.started = False
        self.thread.join()

    def __exit__(self, exc_type, exc_value, traceback):
        self.stream.release()

Solution

I cannot find the boxes variable declared anywhere except inside the function.

If you want to use the global keyword, you need to actually have a global variable with that name. Long story short, a global variable needs to be declared outside any function.

You might want to do something like:

boxes = None  # or whatever you want the initial value to be

def streaming():
    ....
    global boxes
    boxes = detections['detection_boxes'][:len(scores)]
    ....

print(boxes)

However, please keep in mind that using global variables is not considered a good practice. If you overwrite the BOXES variable in the streaming() method, why do you need it to be global? If it’s just so you can print it, you can do so inside the function.

You can read more about global variables here: Why are global variables evil?

Answered By – cosminp

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published