我有一个Django应用,可让您上传视频或图像,将其发送到OpenCV函数,该函数返回带有新注释的新图像/视频,然后将其显示在模板中。
对于图像来说,它工作得很好,但对于视频而言,它却没什么作用。
该视频在视图中(作为HTML5视频)以及跟随/ media / [path_to_file]均显示为不可用,但是当我使用VLC(或本地的某些其他桌面播放器)打开该视频时,该视频存在并按预期工作。
此外,我尝试删除了OpenCV功能,只保留了上传功能。当我上传普通视频时,一切都很好,但是当我尝试上传之前由OpenCV处理过的视频时,它再次显示为不可用。
我的问题是:与原始视频相比,opencv是否以任何方式更改了视频属性,以便Django无法再识别它?可能是什么问题?以及如何使opencv处理的视频在我的视图中可见?
处理后的视频也具有与原始视频相同的名称和扩展名(和类型)。
如果您有任何想法,那就比帮助还多。非常感谢!
编辑(包括代码)
views.py
class IndexView(View):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.context = dict()
def get(self, request, *args, **kwargs):
""" Action for GET requests """
upload_form = UploadForm()
self.context['upload_form'] = upload_form
return render(request, 'homepage/home.html', self.context)
def post(self, request, *args, **kwargs):
""" Action for POST requests """
upload_form = UploadForm(request.POST, request.FILES)
if upload_form.is_valid:
try:
uploaded_file = upload_form.save()
file_type = upload_form.cleaned_data['file'].content_type.split('/')[0]
# task = start_annotation_process.delay(uploaded_file.file.name, file_type)
task = add.delay(4, 5)
except ValidationError:
print('FAILED VALIDATION ERROR')
self.context['upload_status'] = 'failed'
return render(request, 'homepage/home.html', self.context)
except ValueError:
print('FAILED VALUE ERROR')
self.context['upload_status'] = 'failed'
return render(request, 'homepage/home.html', self.context)
self.context['upload_form'] = upload_form
self.context['task_id'] = task.task_id
self.context['uploaded_file'] = uploaded_file
self.context['upload_status'] = 'successfull'
self.context['content_type'] = upload_form.cleaned_data['file'].content_type
return render(request, 'homepage/home.html', self.context)
models.py
class UploadModel(models.Model):
""" Model for storing uploaded files """
file = models.FileField(upload_to='uploads/%Y/%m/%d/')
upload_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return 'UploadModel({file}, {date})'.format(file=self.file, date=self.upload_date)
class Meta:
db_table = 'UploadModel'
forms.py
class UploadForm(forms.ModelForm):
file = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': "custom-file-input",
'id':"input-file",
'aria-describedby':"inputGroupFileAddon01"}))
def clean_file(self):
file = self.cleaned_data.get('file')
if file != None:
file = self.cleaned_data['file'] # try to delete
file_type = file.content_type.split('/')[0]
if file_type == settings.FILE_TYPES[0]: # image
self.__validate_size(file, settings.MAX_UPLOAD_IMAGE_SIZE)
elif file_type == settings.FILE_TYPES[1]: # video
self.__validate_size(file, settings.MAX_UPLOAD_VIDEO_SIZE)
else:
print('File type ', file.content_type)
raise forms.ValidationError(
'File type not supported. It has to be an image or a video.')
return file
def __validate_size(self, file, upload_size):
if file.size > int(upload_size):
raise forms.ValidationError('The file size exceeds {upload_size}. '
'Current file size is {file_size}'.format(upload_size=filesizeformat(upload_size),
file_size=filesizeformat(file.size)))
class Meta:
model = UploadModel
exclude = ('upload_date',)
fields = ('file',)
urls.py(主页)
urlpatterns = [
path('', homepage_views.IndexView.as_view(), name='homepage'),
path('celery-progress', include('celery_progress.urls')), # the endpoint is configurable
path('download/<str:content_type>/<path:path>', homepage_views.download_file, name='download'),
]
urls.py(root应用)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('homepage.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
tasks.py(芹菜)
@shared_task(bind=True)
def start_annotation_process(self, file_path, file_type):
""" Celery task for starting the annotation process """
print('start task')
media_src_path = path.join(settings.MEDIA_ROOT, file_path)
media_dst_path = path.join(settings.MEDIA_ROOT, 'results', file_path)
media_res_path = path.join(settings.MEDIA_ROOT, 'results', path.dirname(file_path))
if not path.exists(media_res_path):
makedirs(media_res_path)
if file_type == 'image':
start_process_image(media_src_path, media_dst_path)
elif file_type == 'video':
start_process_video(media_src_path, media_dst_path)
move(media_dst_path, media_src_path)
print('finished task')
Opencv函数(FastObjectDetector
是一个类,它将预测注释并使用predict_img()
方法返回已处理的帧)
def start_process_video(source_path, dest_path, process_offline=True, rotate=False):
""" Start annotation process for video """
if not process_offline:
cfod = FastObjectDetector(score_threshold=0.5)
vstrm = VideoCameraStream(logger=cfod.logger,
process_func=cfod.predict_img,
info_func=cfod._DEBUG_INFO,
onclick_func=cfod.on_click,
hd=1,
camera=0)
if vstrm.video != None:
video_frame_shape = (vstrm.H, vstrm.W)
cfod.prepare(image_shape=video_frame_shape)
vstrm.play()
vstrm.shutdown()
if cfod.DEBUG:
cfod.show_fr_stats()
cfod.shutdown()
else:
cfod = FastObjectDetector(score_threshold=0.5)
FRAME_W, FRAME_H = 1280, 720
cfod.prepare(image_shape=(FRAME_H, FRAME_W))
video = cv2.VideoCapture(source_path)
fourcc = int(video.get(cv2.CAP_PROP_FOURCC))
fourcc = cv2.VideoWriter_fourcc(*'XVID')
fps = video.get(cv2.CAP_PROP_FPS)
frame_size = (FRAME_W, FRAME_H)
source_path, _ = os.path.splitext(source_path)
new_video = cv2.VideoWriter(dest_path, fourcc, fps, frame_size)
while (video.isOpened()):
ret, frame = video.read()
if ret:
frame = cv2.resize(frame, (FRAME_W, FRAME_H))
if rotate:
(cW, cH) = (FRAME_W // 2, FRAME_H // 2)
m = cv2.getRotationMatrix2D((cW, cH), -90, 1)
frame = cv2.warpAffine(frame, m, (FRAME_W, FRAME_H))
frame = cfod.predict_img(frame)
new_video.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
video.release()
new_video.release()
cv2.destroyAllWindows()
template.html
<video id="result-video" controls style="width:45vw; height:auto; max-height:40vh">
<p> view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a> </p>
</video>
<script type="text/javascript">
{% if task_id and upload_status == "successfull" %}
var progressUrl = "{% url 'celery_progress:task_status' task_id %}";
$('#btn-upload').addClass('disabled');
$(function () {
let options = {
onProgress: function(progressBarElement, progressBarMessageElement, progress){
console.log('ON PROCESS');
$('#div-progress').show();
$('#div-results').hide();
},
onSuccess: function(progressBarElement, progressBarMessageElement){
console.log('ON SUCCESS');
var d = new Date();
{% get_content_type content_type as type %}
{% if type == 'image' %}
$('.result-img').attr('src', '{{ uploaded_file.file.url }}?' + d.getTime());
{% elif type == 'video' %}
$('#result-video').html('<source src="{{ uploaded_file.file.url }}" type="{{ content_type }}">');
$('#result-video')[0].load();
{% endif %}
$('#div-progress').hide();
$('#div-results').show();
$('#btn-upload').removeClass('disabled')
}
};
CeleryProgressBar.initProgressBar(progressUrl, options);
});
{% endif %}
</script>
对于模板,我使用了celery_progress
的回调函数,在完成celery任务后添加了视频源。最终的HTML文件将在video标签中包含正确的来源。但是该视频也无法在/ media /网址后显示。
我希望这会有所帮助。谢谢。
答案 0 :(得分:0)
我自己解决了问题,因此,如果有人遇到与我相同的问题,请检查cv2.VideoWriter_fourcc(*'XVID')
中的编解码器。在尝试将编解码器设置为.mp4
时,我试图上传一个.avi
文件。
当上一行(fourcc = int(video.get(cv2.CAP_PROP_FOURCC))
)从上载的文件中获取编解码器并准备使用它时,这更令人尴尬。
我最终使用了AVC1
编解码器,并更改了代码以将任何上传的视频制作为.mp4
文件,只是为了确保不会重复出现此问题。
我希望这对某人有帮助。