1 视频中的旋转信息

Android或者ios等手机上录制视频时,由于重力感应或者录制视频的摆放方式的问题会导致录制的视频拥有旋转信息。如果是横屏录制(手机逆时针旋转90度),则录制的视频时不带角度的。如果是竖屏录制(正常的拿手机的姿势),此时的录制的视频的旋转角度是90度。如果再旋转90度,此时一般音量键和关屏键朝下,此时的视频的旋转角度是180。以此类推。所以在手机上的视频一般会有4种角度的视频,播放时,要对视频资源进行旋转后再进行播放,不然视频就会出现各种反转、倾倒。

在本站文章https://www.stubbornhuang.com/1856/也分享了如何在C++中使用ffmpge sdk读取视频旋转角度以及使用OpenCV库根据旋转角度对视频进行旋转复原的代码,有兴趣可以看看。

2 为什么不直接使用opencv读取视频的旋转信息

使用opencv库单独读取视频时并不会读取到视频的旋转信息,这是因为视频中视频流的旋转信息通常存储在视频流的metadata元数据中,这个时候就需要使用scikit-video库,这个库封装了ffmpeg中ffporbe的方法,可以以字典的方式返回视频中的各种元信息。

3 使用scikit-video库获取视频的旋转信息并使用opencv对视频进行旋转复原

3.1 安装scikit-video

pip install scikit-video

3.2 使用scikit-video获取旋转信息

if __name__ == "__main__":
    file_name = "test.MOV"
    # get video info(rotate)
    video_metadata = skvideo.io.ffprobe(file_name)
    #video_tag_info = video_metadata['video']['tag']
    rotate_degree_info = -1.0
    for tag_info in video_metadata['video']['tag']:
        for key, val in tag_info.items():
            if val == "rotate":
                rotate_degree_info = float(tag_info["@value"])
                print("Info: video rotate degree info:{}".format(rotate_degree_info))
                break

3.3 使用Opencv的自带的旋转矩阵旋转视频帧

# 得到旋转角度之后,对视频帧旋转对应的负角度便可以得到正向的图像
def rotate_img_data(img_data, degree):
    h, w = img_data.shape[:2]
    (cx, cy) = (w / 2, h / 2)

    # 设置旋转矩阵
    M = cv2.getRotationMatrix2D((cx, cy), -degree, scale=1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # 计算图像旋转后的新边界
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # 调整旋转矩阵的移动距离(t_{x}, t_{y})
    M[0, 2] += (nW / 2) - cx
    M[1, 2] += (nH / 2) - cy

    img_rotated = cv2.warpAffine(img_data, M, (nW, nH))
    return img_rotated

3.4 完整代码

import cv2
import skvideo.io

# 得到旋转角度之后,对视频帧旋转对应的负角度便可以得到正向的图像
def rotate_img_data(img_data, degree):
    h, w = img_data.shape[:2]
    (cx, cy) = (w / 2, h / 2)

    # 设置旋转矩阵
    M = cv2.getRotationMatrix2D((cx, cy), -degree, scale=1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # 计算图像旋转后的新边界
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # 调整旋转矩阵的移动距离(t_{x}, t_{y})
    M[0, 2] += (nW / 2) - cx
    M[1, 2] += (nH / 2) - cy

    img_rotated = cv2.warpAffine(img_data, M, (nW, nH))
    return img_rotated

if __name__ == "__main__":
    file_name = "test.MOV"
    # get video info(rotate)
    video_metadata = skvideo.io.ffprobe(file_name)
    #video_tag_info = video_metadata['video']['tag']
    rotate_degree_info = -1.0
    for tag_info in video_metadata['video']['tag']:
        for key, val in tag_info.items():
            if val == "rotate":
                rotate_degree_info = float(tag_info["@value"])
                print("Info: video rotate degree info:{}".format(rotate_degree_info))
                break

    # read video sequence
    video_io = cv2.VideoCapture(file_name)
    all_frame_nums = video_io.get(cv2.CAP_PROP_FRAME_COUNT)
    read_status, video_frame = video_io.read()
    while read_status:
        # rotate the image if needs
        if abs(-1.0 - rotate_degree_info) > 1.0:
            video_frame = rotate_img_data(video_frame.copy(), rotate_degree_info)
        read_status, video_frame = video_io.read()

参考链接

  1. https://blog.csdn.net/m_buddy/article/details/111938447