有没有办法解决RecursionError:调用Python对象时超出了最大递归深度?

时间:2019-09-25 12:13:55

标签: python opencv recursion tkinter

我正在做一个自我调用的函数,但是我遇到了错误:RecursionError:调用Python对象时超出了最大递归深度,有没有办法解决?更具体地说,我在第35行得到它,好了,frame = cap.read() 由于程序中的.after功能,我无法放置while循环。

import cv2
from tkinter import *
import PIL
from PIL import Image, ImageTk

root = Tk()
root.bind('<Escape>', lambda e: root.quit())
lmain = Label(root)
lmain.pack()

print("[INFO] Making variables")
ImageSource = 0
window_name = "AutoCam"
width = 600
height = 800
cap = cv2.VideoCapture(ImageSource)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
print("[INFO] Made variables ")


def ShowFrame(frame):
    print("[INFO] making image.")
    cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    img = PIL.Image.fromarray(cv2image)
    imgtk = ImageTk.PhotoImage(image=img)
    lmain.imgtk = imgtk
    lmain.configure(image=imgtk)
    print("[INFO] After 10 initializing")
    lmain.after(10, CheckSource)
    print("[INFO] Showed image")


def CheckSource():
    ok, frame = cap.read()

    if ok:
        print("[INFO] Ok is triggered")

        if cv2.waitKey(1) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            cv2.waitKey(0)
            print("[INFO] Exiting app after command")

        ShowFrame(frame)

    else:

        lmain.after(10, CheckSource())


CheckSource()
root.mainloop()

任何人和所有帮助将不胜感激。 有人还能解释一下如何避免这种情况以备将来使用吗?

[编辑]

the error message is:
  Traceback (most recent call last):
   File "C:/Users/Gotta/Documents/AutoCamPy.py", line 52, in <module>
   CheckSource()
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
 [Previous line repeated 995 more times]
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 35, in CheckSource
  ok, frame = cap.read()
RecursionError: maximum recursion depth exceeded while calling a Python 
object

2 个答案:

答案 0 :(得分:1)

要以简单的方式处理此问题,可以编写try / except语句来捕获此错误。直到您确切知道错误是什么,您都可以使用全部捕获,但是我建议您在知道具体错误之后再处理具体错误。

那就是说,我对您的代码进行了一些更改,以对其进行一些清理并更严格地遵循PEP8标准。

您确实应该执行import tkinter as tk而不是使用*。这将有助于防止覆盖已导入的方法。

接下来,您的lambda会被杀死,而只需执行root.quit。我们想保存对命令的引用而不是执行它,我们通过删除括号来做到这一点。您的after after语句存在相同的问题。

最后,您导入PIL,然后专门从PIL导入。您不需要两者都做。如果您只需要ImageImageTk,则只需执行from PIL import Image, ImageTk,如果您需要PIL的许多功能,则可以简单地执行import PIL并使用PIL.前缀从那里。

这是带有try / except语句的清理代码。如果您有任何问题,请告诉我。

import tkinter as tk
from PIL import Image, ImageTk
import cv2


root = tk.Tk()
root.bind('<Escape>', root.quit)
lmain = tk.Label(root)
lmain.pack()
ImageSource = 0
window_name = "AutoCam"
width = 600
height = 800
cap = cv2.VideoCapture(ImageSource)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)


def show_frame(frame):
    cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    img = Image.fromarray(cv2image)
    imgtk = ImageTk.PhotoImage(image=img)
    lmain.imgtk = imgtk
    lmain.configure(image=imgtk)
    lmain.after(10, check_source)


def check_source():
    try:
        ok, frame = cap.read()
        if ok:
            if cv2.waitKey(1) & 0xFF == ord('q'):
                cv2.destroyAllWindows()
                cv2.waitKey(0)
            show_frame(frame)
        else:
            lmain.after(10, check_source)
    except:
        print('Connection failed for some reason!')


check_source()
root.mainloop()

答案 1 :(得分:1)

通过堆栈跟踪,您可以确定递归发生在第49行(该行已执行多次)

File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
File "C:/Users/Gotta/Documents/AutoCamPy.py", line 49, in CheckSource
  lmain.after(10, CheckSource())
 [Previous line repeated 995 more times]

它达到递归限制的原因是因为.after函数(https://effbot.org/tkinterbook/widget.htm#Tkinter.Widget.after-method)希望将回调函数作为第二个参数,但是您正在传递结果而是调用CheckSource。您应该传递CheckSource而不是CheckSource()作为第二个参数:

lmain.after(10, CheckSource)