首页 > 解决方案 > 如何处理 h264 格式的视频,修改每一帧并使用 openCV/ffmpeg 使用处理后的图像创建另一个 h264 格式的视频

问题描述

我想逐帧处理“h264”格式的视频。处理帧以添加某种噪声(例如椒盐噪声)并从处理后的图像(噪声图像)中重新创建“h264”格式的视频,其序列与原始“h264”视频相同。

我使用 openCV 进行了同样的尝试,但我没有得到任何可用的特定编解码器(cv2.VideoWriter 需要)来创建 h264 格式的视频。因此,我创建了嘈杂图像的 mp4 视频,然后使用 ffmpeg 将其从 mp4 转换为 h264 格式。但我想由于 h264 -> mp4 -> h264 转换,我从原始帧中丢失了太多信息。下面是我为此编写的代码。

import numpy as np
import os
from skimage.util import random_noise


def processVideo(videoPath, noiseType="", outVideoPath=""):
    """
    Add the specified noise in the provided video.

    videoPath: Video file path
    noiseType: noise type which needs to be added in the video.
                Supported noise types: gaussian, localvar, poisson, salt, pepper, s&p, speckle
    Returns:
        Noisy video path, in case of success
        None, in case of failure
    """
    if noiseType not in ['gaussian', 'localvar', 'poisson', 'salt', 'pepper', 's&p']:
        print "noiseType is not specified."
        return None
    videoPath = os.path.abspath(videoPath)
    print "The video path under process: {}".format(videoPath)
    if outVideoPath:
        outVideoPath = os.path.abspath(outVideoPath)
    else:
        outVideoPath = os.path.abspath(os.path.dirname(videoPath))

    if os.path.exists(videoPath):
        video = cv2.VideoCapture(videoPath)

        if os.path.isdir(outVideoPath):
            outVideoPath = os.path.join(outVideoPath, os.path.splitext(
                os.path.basename(videoPath))[0] + "_Noisy" + ".mp4")
        elif os.path.exists(outVideoPath):
            print "The given location already contains the file named {}.\nPlease delete the same.".format(outVideoPath)
            return None
        elif os.path.exists(os.path.dirname(outVideoPath)):
            outVideoPath = os.path.splitext(outVideoPath)[0] + ".mp4"
        else:
            print "The given location {} does not exists".format(os.path.dirname(outVideoPath))
            return None

        fourcc = cv2.VideoWriter_fourcc(*'MP4V')
        frame_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
        frame_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
        video_fps = int(video.get(cv2.CAP_PROP_FPS))
        totalFrames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
        print "Total Frames in video = ", totalFrames
        out = cv2.VideoWriter(outVideoPath, fourcc, video_fps, (frame_width, frame_height))

        while (video.isOpened()):
            ret, frame = video.read()
            if ret is True:
                noise_img = random_noise(frame, mode=noiseType)
                noise_img = np.array(255 * noise_img, dtype='uint8')
                out.write(frame)
            else:
                video.release()
                out.release()
                break
        return outVideoPath
    else:
        print "Provided Video Path: {} is not present in the specified location.".format(videoPath)
        return None


def mp4Toh264VideoConv(mp4VideoPath, h264VideoPath=""):
    mp4VideoPath = os.path.abspath(mp4VideoPath)
    print "h264 video:", os.path.abspath(h264VideoPath)
    if h264VideoPath:
        h264VideoPath = os.path.abspath(h264VideoPath)
    else:
        h264VideoPath = os.path.abspath(os.path.dirname(mp4VideoPath))

    if os.path.isdir(os.path.abspath(h264VideoPath)):
        h264VideoPath = os.path.join(h264VideoPath, os.path.splitext(os.path.basename(mp4VideoPath))[0] + ".h264")
    elif os.path.exists(h264VideoPath):
        print "The given location already contains the file named {}.\nPlease delete the same.".format(h264VideoPath)
        return None
    elif os.path.exists(os.path.dirname(h264VideoPath)):
        h264VideoPath = os.path.splitext(h264VideoPath)[0] + ".h264"
    else:
        print "The given location {} does not exists.".format(os.path.dirname(h264VideoPath))
        return None
    print "The h264 video path: ", h264VideoPath
    os.system('ffmpeg -i ' + mp4VideoPath + ' -an -vcodec libx264 -crf 23 ' + h264VideoPath)
    return h264VideoPath


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description='This script will add the specified noise in the given h264 video.')
    parser.add_argument('-i', '--inputVideo', help='Input h264 formated Video Path', required=True)
    parser.add_argument('-o', '--outputVideo', help='Output video path location', default="", required=False)
    parser.add_argument('-n', '--noiseType', help='Type of noise to add in the video', default='', required=True)

    args = vars(parser.parse_args())
    inputVideo = os.path.expanduser(args['inputVideo'])
    outputVideo = os.path.expanduser(args['outputVideo'])
    noiseType = args['noiseType']

    if os.path.splitext(inputVideo)[1].upper() != ".H264":
        print os.path.splitext(inputVideo)[1].upper()
        print "Noise Addition in {} formated video is not supported".format(os.path.splitext(inputVideo)[1])
        exit(-1)
    else:
        noisymp4Video = processVideo(videoPath=inputVideo, noiseType=noiseType, outVideoPath=outputVideo)
        if noisymp4Video:
            mp4Toh264VideoConv = mp4Toh264VideoConv(mp4VideoPath=noisymp4Video, h264VideoPath=outputVideo)
            exit(0)
        else:
            exit(-1)

我需要一些更好的方法来直接处理 h264 视频,在帧中进行一些修改并创建 h264 视频。如果 ffmpeg 和 openCV 组合可以做到这一点,我很好。我只需要一些更好的方法来防止由于 h264 -> mp4 -> h264 转换而造成的损失。

帮助将不胜感激。

标签: python-2.7opencvffmpegh.264

解决方案


推荐阅读