Flask Opencv Recode mini 视频剪辑

Flask Opencv Recode mini Video clips

在使用 open cv 和 python.

录制我的网络摄像头时,我很难生成一个迷你视频剪辑(每个都是 10 秒的视频剪辑)

基本上我想将网络摄像头视频剪切成 10 秒时长的片段并存储在一个文件夹中。 当我做这个视频剪辑剪切但当我检查第一个视频剪辑有 100% 的完整视频。 第二个有大约 75% 的完整视频,第三个有大约 50% 等等。

那么我该如何解决这个问题。 我将把我的孔代码放在下面。希望你能帮助解决这个问题


camera = cv2.VideoCapture(0)
global rec, img, out
rec = 0

def gen_frames():
    global img
    while True:
        success, img = camera.read()

def record(out):
    global rec, img

    while(rec != False):
        time.sleep(0.05)
        out.write(img)

@app.route('/requests',methods=['POST','GET'])
def tasks():

    if request.form.get('rec') == 'Start/Stop Recording':
        global rec, img, out
        rec= not rec

        ############### This Part work when manualy recode on and off ###############

        # if rec:
        #     print("start")
        #     global out
        #     now=datetime.datetime.now()
        #     fourcc = cv2.VideoWriter_fourcc(*'XVID')
        #     p = os.path.sep.join(['clips', "vid_{}.avi".format(str(now).replace(":",''))])
        #     out = cv2.VideoWriter(p, fourcc, 25.0, size)
        #     thread = Thread(target = record, args=[out,])
        #     thread.start()

        # if(rec==False):
        #     print("stop")
        #     out.release()

        class TimerClass(threading.Thread):
            def __init__(self):
                threading.Thread.__init__(self)
                self.event = threading.Event()

            def run(self):
                while (rec != False) and not self.event.is_set():
                    now=datetime.datetime.now()
                    fourcc = cv2.VideoWriter_fourcc(*'XVID')
                    p = os.path.sep.join(['clips', "vid_{}.avi".format(str(now).replace(":",''))])
                    out = cv2.VideoWriter(p, fourcc, 25.0, size)
                    
                    thread = Thread(target = record, args=[out,])
                    thread.start()
                    self.event.wait(10)

            def stop(self):
                self.event.set()

        tmr = TimerClass()

        if(rec):
            print("start")
            tmr.start()

        if(rec==False):
            print("stop")
            tmr.stop()

    elif request.method=='GET':
        return render_template('index.html')
    return render_template('index.html')

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

至于我的问题是,在 TimerClass 的循环中,你每 10 秒创建一个新线程,但你永远不会停止前一个线程,它仍然记录帧。我会直接在 TimerClass 中写入帧,而不是使用另一个线程。

OR 线程 record() 应该检查时间并在 10 秒后停止。

我使用 timedelta 来计算何时停止录制一个文件并创建下一个文件。我在 TimerClass 中做,但你可以在 record()

中做类似的事情

VideoWriter(..., 25.0) 不会写成 25fps 但它只是视频播放器显示此视频的速度信息。要获得 10 秒的视频,您需要睡眠 0.04 因为 1s / 25fps = 0.04 否则您将不得不写入 250 帧(10s * 25fps = 250fps)。

因为代码也需要一些时间来工作,所以我必须使用 0.03 而不是 0.04 来获得 10 秒的视频。


完整的工作代码。

我使用 render_template_string 而不是 render_template 将所有内容都放在一个文件中 - 每个人都可以简单地复制和测试它。

from flask import Flask, Response, request, render_template, render_template_string
import cv2
import os
import datetime, time
import threading

# global varaibles

capture = False
rec = False
out = None
img = None

app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 300

camera = cv2.VideoCapture(0)

frame_width = int(camera.get(3))
frame_height = int(camera.get(4))
size = (frame_width, frame_height)

os.makedirs('./shots', exist_ok=True)
os.makedirs('./clips', exist_ok=True)

def gen_frames():
    global capture
    global img
    
    print('[DEBUG] gen_frames: start')

    while True:
        success, img = camera.read()
        
        if not success:
            break
        
        if capture:
            capture = False

            now = datetime.datetime.now()
            filename = "shot_{}.png".format(str(now).replace(":",''))
            path = os.path.sep.join(['shots', filename])

            print('[DEBUG] capture:', path)

            cv2.imwrite(path, img)

        frame = cv2.imencode('.jpg', img)[1].tobytes()
        
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/')
def index():
    #return render_template('index.html')
    return render_template_string('''
Go to <a href="/requests">FORM</a>
''')

# define class only once
class TimerClass(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.event = threading.Event()

    def run(self):
        seconds_10 = datetime.timedelta(seconds=10)
        
        while rec and not self.event.is_set():
            now = datetime.datetime.now()
            filename = "vid_{}.avi".format(str(now).replace(":", ''))
            path = os.path.sep.join(['clips', filename])
            
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            out = cv2.VideoWriter(path, fourcc, 25.0, size)

            end = now + seconds_10
            
            print('[DEBUG] end:', end)
            
            while now < end and rec and not self.event.is_set():
                if img is not None:  # `img` can be `numpy.array` so it can't check `if img:`
                    out.write(img)
                time.sleep(0.03)  # 1s / 25fps = 0.04  # it needs some time for code.
                now = datetime.datetime.now()
        
            out.release()
            
    def stop(self):
        self.event.set()

@app.route('/requests', methods=['POST', 'GET'])
def tasks():
    global capture
    global rec
    
    print('[DEBUG] click:', request.form.get('click'))
    print('[DEBUG] rec  :', request.form.get('rec'))
    
    if request.method == 'POST':
        if request.form.get('click') == 'Capture':
            capture = True

        if request.form.get('rec') == 'Start/Stop Recording':
            rec = not rec
    
            tmr = TimerClass()
    
            if rec:
                print("start")
                tmr.start()
            else:
                print("stop")
                tmr.stop()
    
    #return render_template_string('index.html')
    return render_template_string('''
<img src="/video_feed"><br/>
<form method="POST">
<button type="submit" name="click" value="Capture">Capture</button>
<button type="submit" name="rec" value="Start/Stop Recording">Start/Stop Recording</button>
</form>
''')

if __name__ == '__main__':
    thread_cam = threading.Thread(target=gen_frames)
    thread_cam.start()
    app.run(host='0.0.0.0', threaded=True)

编辑:

同线程record()

def record(seconds):
    now = datetime.datetime.now()
    
    filename = "vid_{}.avi".format(str(now).replace(":", ''))
    path = os.path.sep.join(['clips', filename])
    
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    out = cv2.VideoWriter(path, fourcc, 25.0, size)

    end = now + datetime.timedelta(seconds=seconds)
    
    print('[DEBUG] end:', end)
    
    while now < end and rec:
        if img is not None:  # `img` can be `numpy.array` so it can't check `if img:`
            out.write(img)
        time.sleep(0.03)  # 1s / 25fps = 0.04  # it needs some time for code.
        now = datetime.datetime.now()

    out.release()

# define class only once
class TimerClass(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.event = threading.Event()

    def run(self):
        length = 10
        while rec and not self.event.is_set():
            t = threading.Thread(target=record, args=(length,))
            t.start()
            self.event.wait(length)
            
    def stop(self):
        self.event.set()