无法在Django中查看opencv处理的视频

时间:2018-09-21 15:08:52

标签: python django opencv video

我有一个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 /网址后显示。

我希望这会有所帮助。谢谢。

1 个答案:

答案 0 :(得分:0)

我自己解决了问题,因此,如果有人遇到与我相同的问题,请检查cv2.VideoWriter_fourcc(*'XVID')中的编解码器。在尝试将编解码器设置为.mp4时,我试图上传一个.avi文件。

当上一行(fourcc = int(video.get(cv2.CAP_PROP_FOURCC)))从上载的文件中获取编解码器并准备使用它时,这更令人尴尬。

我最终使用了AVC1编解码器,并更改了代码以将任何上传的视频制作为.mp4文件,只是为了确保不会重复出现此问题。

我希望这对某人有帮助。

相关问题