OpenCV - 视频质量不错但帧被旋转了90度。

6
我们在移动客户端上保存了一段视频并将其发送到服务器。在服务器上,我使用以下代码来保存视频帧:>
import skvideo.io
import cv2

haar = 
'/home/ubuntu/opencv/data/haarcascades/haarcascade_frontalface_alt.xml'
face_cascade = cv2.CascadeClassifier(haar)

ret = True

video = 'my_video.mov'
i = 0
while ret == True:
    cap = skvideo.io.VideoCapture(video)
    ret, frame = cap.read()
    cv2.imwrite('frame_'+str(i)+'.jpg',frame)
    i+=1

当我们在Windows Media Player或iTunes上播放视频时,它看起来很好。也就是说,播放器知道如何定位它。

但是skvideo.io不知道,而且我们保存的那些帧被逆时针旋转了90度。

我们如何将信息嵌入视频文件(.mov文件),以便skvideo知道正确的方向?


使用 skvideo.io 而不是 cv2.VideoCapture API 的任何原因? - ZdaR
3个回答

7

skvideo出现故障,无法读取可用的元数据。在移动设备拍摄的视频中,可能存在旋转参数,但元数据包含此参数。skvideo团队发布了修复程序,当前版本1.1.7从移动设备读取元数据,指示视频应该旋转。因此,skvideo.io.vread旋转文件:

1)使用更新的skvideo版本1.1.7,可以克隆到https://github.com/scikit-video/scikit-video

2)您可以使用以下代码读取视频中的所有帧,很可能会读取元数据

import skvideo.io
videogen = skvideo.io.vread(f.name)

如果视频是竖屏拍摄的,这将自动旋转视频。

3) 在skvideo仓库上创建了一个问题,可供进一步参考:https://github.com/scikit-video/scikit-video/issues/40


如果您给我的解决方案点赞,我不会感到冒犯! :) - Alejandro Simkievich
确认即使使用OpenCV 4仍然存在此问题...对我来说,使用scikit-video可以解决这个问题,因为它与ffmpeg集成以读取视频方向/旋转元数据。 - Daniel Sposito
似乎在OpenCV 4.5中已经解决了 https://github.com/opencv/opencv/issues/15499 - Ta946

4
看起来 OpenCV 在使用 VideoCapture() 时似乎没有记录视频文件的旋转元数据,因为你可以看到它存储的 propId。我不确定 scikit-video 是否有记录。他们似乎有一个名为 ffprobe 的元数据提取器,可以提取旋转信息。请参见此处以查看调用和输出示例。这将显示大量的元数据,但没有旋转信息,可能是因为它没有被设置或者是某种类型的电影没有旋转元数据。另一种获取旋转元数据的方法是直接从 ffmpeg 中读取元数据。我找到了一个 旧的 StackOverflow 回答,其中编写了一小段 Python 代码,可以使用 ffmpeg 从视频中提取旋转元数据。

@AlejandroSimkievich 如果您使用 scikit-videoffmpeg 找到了精确的解决方案,那么您应该编辑原始问题并分享它,以便其他有同样问题的人可以轻松找到可行的解决方案! - alkasm

1
我安装了'ffmpeg' ('ffprobe')。我的电脑是Ubuntu 18.04。 然后,在Python中,get_rotation()函数对我起作用了。
函数代码:
import subprocess
import shlex
import json
def get_rotation(self, file_path_with_file_name):
    cmd = "ffprobe -loglevel error -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1:nk=1"
    args = shlex.split(cmd)
    args.append(file_path_with_file_name)
    ffprobe_output = subprocess.check_output(args).decode('utf-8')
    if len(ffprobe_output) > 0:  # Output of cmdis None if it should be 0
        ffprobe_output = json.loads(ffprobe_output)
        rotation = ffprobe_output
    else:
        rotation = 0
    return rotation

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接