1

I'm calling this script from a Tkinter GUI I've made, and one of my variables can't be called from one of my functions and I can't understand why it's happening?

I get a NameError that 'framevalues' isn't defined when I do a keypress to trigger one of my Tag functions.

Thanks in advance!

import cv2
import tkinter as tk
from tkinter.filedialog import askopenfilename


def main():
    framevalues = []
    count = 1
    selectedvideo = askopenfilename()
    selectedvideostring = str(selectedvideo)
    cap = cv2.VideoCapture(selectedvideo)
    length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    while (cap.isOpened()): 
        ret, frame = cap.read()

        # check if read frame was successful
        if ret == False:
                break
        # show frame first
        cv2.imshow('frame',frame)

        # then waitKey
        frameclick = cv2.waitKey(0) & 0xFF

        if frameclick == ord('a'):
            swingTag(cap)

        elif frameclick == ord('r'):
            rewindFrames(cap)

        elif frameclick == ord('s'):
            stanceTag(cap)

        elif frameclick == ord('d'):
            unsureTag(cap)

        elif frameclick == ord('q'):
            with open((selectedvideostring + '.txt'), 'w') as textfile:
                for item in framevalues:
                    textfile.write("{}\n".format(item))
            break

        else:
            continue

    cap.release()
    cv2.destroyAllWindows()

def stanceTag(cap):    
    framevalues.append('0' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def swingTag(cap):
    framevalues.append('1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length)
    print(framevalues) 

def unsureTag(cap):
    framevalues.append('-1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def rewindFrames(cap):
    cap.set(1,((int(cap.get(1)) - 2)))
    print (int(cap.get(1)), '/', length) 
    framevalues.pop()
    print(framevalues)  






if __name__ == '__main__':
    # this is called if this code was not imported ... ie it was directly run
    # if this is called, that means there is no GUI already running, so we need to create a root
    root = tk.Tk()
    root.withdraw()
    main()
Satish Prakash Garg
  • 2,213
  • 2
  • 16
  • 25

3 Answers3

3

framevalues is a local variable defined inside your main() and hence is not visible inside other functions. You can either make it global, i.e. define it before main() or you can pass it from main() to the other functions as normal function parameter, e.g.

def main():
    ...
    if frameclick == ord('a'):
        swingTag(cap, framevalues)  # pass it as a parameter
    ...
...
def swingTag(cap, framevalues):
    framevalues.append(...)  # now you are using local framevalues passed as parameter
  • Cheers all you guys, that's fixed the issue - I put my variables inside my main() function so that I could run the script from a GUI without it autoloading the tkinter file selection prompt. Passing framevalues and length to the other functions as parameters has fixed my problem. Thanks again! – KittenMittons Mar 20 '17 at 14:42
  • There is an alternative approach where don't need to change your function definitions. You can just expand the scope by using keyword **global**. Have a look at my answer as well. – Satish Prakash Garg Mar 20 '17 at 14:47
  • 1
    I would advice against using global variables whenever it can be avoided. In general it is considered a bad practice. The OP's code is the perfect example where we do not actually need global variables. Passing it as parameter makes perfect sense because it is immediately visible which function uses which variables. – HiFile.app - best file manager Mar 20 '17 at 14:50
1

framevalues is a variable local to main(). You'd need to pass framevalues as an argument, to all your functions that need it, for them to be able to access it.

Please read up on variable scoping. I suggest the answer in Short Description of the Scoping Rules?

Community
  • 1
  • 1
Sagar
  • 9,456
  • 6
  • 54
  • 96
1

When you assign a variable, you are creating that variable in the current scope i.e. local to the current function.

So, what you can do is defining framevalues variable as global. That can be achieved as following :

Replace

framevalues = [] 

with

global framevalues
framevalues = []

You do not need to change the rest of the code and this will work just fine.

Satish Prakash Garg
  • 2,213
  • 2
  • 16
  • 25