我正在尝试制作一个程序,该程序删除视频中的背景,以便仅显示前景。它适用于短片,但长片则成倍地减慢速度,并开始使用越来越多的内存,从而使程序崩溃。
我尝试删除for循环中使用的变量,如下面的代码所示。
def video_generator(name_of_video, video, cap, number_of_frames):
check, frame = cap.read()
A = np.array([])
a = np.array([])
if cap.isOpened():
width = int(cap.get(3))
height = int(cap.get(4))
dims = (height, width)
while cap.isOpened():
check, frame = cap.read()
if check:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY).flatten()
A = np.append(A, gray)
a = np.append(a, 'row')
image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
break
B = np.resize(A, (number_of_frames, width * height))
U, S, V = decomposition.randomized_svd(B, 2)
background = U @ np.diag(S) @ V
foreground = ([])
def generate_frames(B, background):
for i in range(number_of_frames):
foreground = np.reshape(B[i] - background[i], dims)
frame = plt.imshow(foreground, cmap = 'gray')
plt.savefig('D:/Python_Programs/BR_SVD/Frames/' + name_of_video + '/file_' + str(i + x * number_of_frames).zfill(2) + '.png')
del frame
del foreground
gc.collect()
generate_frames(B, background)
if number_of_frames_initial <= 200:
cap = cv2.VideoCapture(video)
video_generator(name_of_video, video_initial, cap_initial, number_of_frames_initial)
else:
number_of_videos = int(number_of_frames_initial/200 + 1)
time_of_videos = duration/number_of_videos
for x in range (number_of_videos):
subprocess.call ([
'ffmpeg', '-i', video_initial, '-ss', str(time_of_videos * x), '-t', str(time_of_videos), 'D:/Python_Programs/BR_SVD/Temp_Videos/video_%02d.mp4' % x])
video = 'D:/Python_Programs/BR_SVD/Temp_Videos/video_%02d.mp4' % x
cap = cv2.VideoCapture(video)
number_of_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
video_generator(name_of_video, video, cap, number_of_frames)
del B
del background
gc.collect()
答案 0 :(得分:0)
关于Python如何进行垃圾回收(除了源代码本身),没有确切的资源,但是这3个链接应该给你一个很好的主意。
更新
来源实际上很有帮助。从中获得多少取决于您对C的理解程度,但是注释实际上非常有帮助。跳到collect()函数,注释会很好地解释该过程(尽管在技术上非常严格)。
答案 1 :(得分:0)
作为对您的顶级问题的解答:明确del
指向对象的最后一个引用并调用gc.collect()
是手动清除Python拥有的RAM的最接近的方法,而这两个都不是通常是必需的。当函数退出时(就像每个本地名称都是del
ed一样),函数的局部变量会自动清除,并且默认情况下,循环GC会每隔几百个分配运行一次,通常这很好,除非您有大量的对象参与循环。除此之外,一般规则是显式调用清理方法(或更好的方法是,在可用时使用with
语句)以确保资源被及时释放,并且引用的保留时间不要超过您的需要(如果您愿意,保持全局list
并保持append
的状态,因为您要求永久保留这些东西,所以任何GC都无法拯救您。
有关具体建议:
我相信您在使用cap.release()
对象时应该在其上调用VideoCapture
;在range(number_of_videos)
上的每个循环中都保留一个开放可能会占用相当长的一段时间。从理论上讲,文档声称析构函数为您调用release
,但是最好明确地调用它,以确保确定,特别是因为引用循环出奇的容易触发,并且可能导致延迟(或者写得不好或使用Python的情况) 2个扩展模块,完全阻止)您期望的清理。
您反复打给np.append
的电话也会使您放慢速度; np.append
创建输入的副本并追加到输入中,这将以Schlemiel the Painter's algorithm的形式出现;每个新框架最终都会复制之前的所有数据以及新数据,并且先前的数据会不断增长。我建议保持A
/ a
为您调用list
的普通Python .append
,并仅在末尾重新组合一次,以避免内存复制的二次增长
我还要注意,您的del B
和del background
毫无意义;它们仅存在于video_generator
的范围内,并且您正在尝试del
处于全局范围内(无论如何,在清理它们之后,并且从从不/ em>存在)。通常不需要显式的del
名称;当函数退出时(假设不存在其他引用),将清理本地人,因此您尝试在不需要时执行运行时的工作。