105 lines
3.1 KiB
Python
Executable File
105 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import cv2
|
|
import moviepy.editor as mp
|
|
|
|
MIN_INTERESTING_FRAMES = 20
|
|
MOVEMENT_THRESHOLD = 1000
|
|
|
|
def main():
|
|
# argparse
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('filename')
|
|
args = parser.parse_args()
|
|
|
|
# get video info
|
|
vid = cv2.VideoCapture(args.filename)
|
|
ret, colorFrame = vid.read()
|
|
frame = cv2.cvtColor(colorFrame, cv2.COLOR_BGR2GRAY)
|
|
fps = vid.get(cv2.CAP_PROP_FPS)
|
|
fnum = int(vid.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
dur = fnum // fps
|
|
print("video stats: \n"
|
|
f"fps: {fps}\n"
|
|
f"frames: {fnum}\n"
|
|
f"length: {int(dur//60):02}:{int(dur%60):02}\n")
|
|
|
|
# prepare to find interesting segments
|
|
print("finding interesting segments ...")
|
|
i = 0
|
|
clips = []
|
|
startFrame = 0
|
|
inSegment = False
|
|
|
|
# start a segment if we aren't already in one.
|
|
def maybeStartSegment(i):
|
|
nonlocal inSegment, startFrame
|
|
if inSegment == False:
|
|
inSegment = True
|
|
startFrame = i
|
|
print( f"found one! frame {i:8} to ... ", end="", flush=True)
|
|
|
|
# end a segment if we are in one, and then save the
|
|
# start and end frames if it was a long enough segment
|
|
def maybeEndSegment(i):
|
|
nonlocal inSegment
|
|
if inSegment == True:
|
|
inSegment = False
|
|
if i - startFrame > MIN_INTERESTING_FRAMES:
|
|
print( f"{i:6} ! ")
|
|
clips.append((startFrame, i))
|
|
else:
|
|
print( f"nvm, too short.")
|
|
|
|
# loop through each frame
|
|
while(True):
|
|
i += 1;
|
|
ret, colorFrame = vid.read()
|
|
|
|
# if theres no more frames, break the loop &
|
|
# maybe end the current segment
|
|
if not ret:
|
|
maybeEndSegment(i)
|
|
break;
|
|
|
|
# calculate the difference between the current & last frame
|
|
# then run the Canny algorithm to find edges within the
|
|
# diff. edges in the diff indicate that something is moving
|
|
# in the frame.
|
|
prev = frame
|
|
frame = cv2.cvtColor(colorFrame, cv2.COLOR_BGR2GRAY)
|
|
diff = cv2.subtract(frame, prev)
|
|
edges = cv2.Canny(diff, 100, 200)
|
|
|
|
# number of non zero (not true block) pixels in the edge frame.
|
|
# large number indicates edges which indicates movment.
|
|
nz = cv2.countNonZero(edges)
|
|
|
|
if nz > MOVEMENT_THRESHOLD:
|
|
maybeStartSegment(i)
|
|
else:
|
|
maybeEndSegment(i)
|
|
|
|
# finished looping
|
|
vid.release()
|
|
print("done! time to chop up the video :) ")
|
|
|
|
# convert the segment indicators from frame number to seconds
|
|
def frame2second(f):
|
|
return round(f / fps, 2)
|
|
clipsSeconds = [ (frame2second(x),frame2second(y)) for (x,y) in clips ]
|
|
print( clipsSeconds )
|
|
|
|
# slice that bitch up & export it!
|
|
movie = mp.VideoFileClip(args.filename)
|
|
clips = [ movie.subclip(s, e) for (s,e) in clipsSeconds ]
|
|
trimmed = mp.concatenate_videoclips(clips)
|
|
out_filename = args.filename.replace('.mp4', '') + '_trimmed.mp4'
|
|
trimmed.write_videofile(out_filename)
|
|
|
|
print("enjoy!")
|
|
|
|
if __name__ == "__main__":
|
|
main();
|