#python #opencv
Вопрос:
Я борюсь с созданием мини-видеоклипов(каждый из которых состоит из 10 видеоклипов) при записи моей веб-камеры с помощью open cv и python.
В принципе, я хочу вырезать видео с веб-камеры на 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)
Комментарии:
1. Я нахожу это немного большим кодом. можно ли это еще больше упростить? колба, вероятно, не нужна для воспроизведения проблемы. удалите все , что не является жизненно важным для возникновения проблемы. чем больше вещей там есть, тем меньше вероятность, что кто-нибудь на это посмотрит.
2. это длинный код, с запуском которого у нас могут возникнуть проблемы — сначала вы должны использовать
print()
илиlog
просмотреть все значения во всех переменных. Может быть, вы измените какое-то значение и не сбросите его позже.3. все переменные, создаваемые внешней функцией, являются глобальными, и вам не нужно использовать
global
внешние функции. Вам нужныglobal
только внутренние функции, чтобы сообщить функции, что она должна использовать внешнюю/глобальную переменную вместо создания локальной.4. вместо
os.mkdir
сtry/except
вы можете использоватьos.makedirs(..., exist_ok=True)
5. Я думаю, ваша проблема в том, что вы создаете так много потоков. В
TimerClass
цикле запуска, который каждые 10 секунд создает другой поток для запускаrecord
, но вы никогда не останавливаете предыдущий потокrecord
. Я думаю, что если бы вы использовалиprint()
, чтобы увидеть, какая часть кода выполняется, то вы ее увидите.
Ответ №1:
Что касается меня, проблема в том, что в цикле TimerClass
вы создаете новый поток каждые 10 секунд, но вы никогда не останавливаете предыдущий поток, и он все еще записывает кадры. Я бы написал фреймы напрямую, TimerClass
вместо того, чтобы использовать другой поток.
ИЛИ поток record()
должен проверить время и остановиться через 10 секунд.
Я использую timedelta
, чтобы рассчитать, когда прекратить запись одного файла и создать следующий. И я делаю это, TimerClass
но вы могли бы сделать что-то подобное в record()
VideoWriter(..., 25.0)
не пишет с 25fps
помощью, но это только информация для видеоплееров о том, как быстро отображается это видео. Чтобы получить 10-секундное видео, вам нужно спать 0.04
, потому 1s / 25fps = 0.04
что иначе вам пришлось бы записать 250 кадров (10 секунд * 25 кадров в секунду = 250 кадров в секунду).
Поскольку коду также требуется некоторое время для работы, мне пришлось бы использовать 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'--framern'
b'Content-Type: image/jpegrnrn' frame b'rn')
@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()