Python-视频处理-视频转字符动画(图像处理 cv2 moviepy Image)

一、 代码

import os
import cv2
import moviepy.editor as mp

from PIL import Image, ImageFont, ImageDraw


# 图片像素点字符数组
ASCII_CHAR = list("$B%314567890*WM#oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:oa+>!:+. ")
# 视频文件 .mp4 要保存的路径
SAVE_PATH = r"E:\b\node.js\complete-node-bootcamp\1-node-farm\learning"
# 视频文件 .mp4 转换为 帧图片 所在文件夹路径
CACHE_PATH = os.path.join(SAVE_PATH, "Cache")
# 帧图片 转换为 字符图片 所在文件夹路径
CHARACTER_PATH = os.path.join(SAVE_PATH, "Character")


def get_ascii(r, g, b, alpha=256):
    """
    将图片的像素点转换为字符数组中的字符
    :param r: 红
    :param g: 绿
    :param b: 蓝
    :param alpha: 亮度
    :return: 返回标准灰度数值的 ASCII_CHAR 数组
    """
    if alpha == 0:
        return ""

    length = len(ASCII_CHAR)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unit = (256.0 + 1) / length

    return ASCII_CHAR[int(gray/unit)]


def txt2image(file_name):
    """
    将 .jpg 图片 重新绘制为 字符图片
    :param file_name: 输出文件名称
    :return: 无返回值
    """
    img = Image.open(os.path.join(CACHE_PATH, file_name)).convert("RGB")
    img_width = img.width
    img_height = img.height
    img = img.resize((int(img.width / 100 * 100), int(img.height / 100 * 100)), Image.NEAREST)

    raw_width = img.width
    raw_height = img.height
    width = int(raw_width / 6)
    height = int(raw_height / 15)
    img = img.resize((width, height), Image.NEAREST)

    txt = ""
    colors = []
    for y in range(height):
        for x in range(width):
            pixel = img.getpixel((x, y))
            colors.append((pixel[0], pixel[1], pixel[2]))
            if len(pixel) == 4:
                txt += get_ascii(pixel[0], pixel[1], pixel[2], pixel[3])
            else:
                txt += get_ascii(pixel[0], pixel[1], pixel[2])
        txt += "\n"
        colors.append((255, 255, 255))

    img_txt = Image.new("RGB", (raw_width, raw_height), (255, 255, 255))
    new_img = ImageDraw.Draw(img_txt)
    font = ImageFont.load_default().font

    x = y = 0
    font_w, font_h = font.getsize(txt[1])
    font_h *= 1.37
    for row in range(len(txt)):
        if txt[row] == "\n":
            x += font_h
            y = -font_w
        new_img.text((y, x), txt[row], fill=colors[row])
        y += font_w

    img_txt = img_txt.resize((img_width, img_height), Image.NEAREST)
    img_txt.save(os.path.join(CHARACTER_PATH, file_name))


def video2jpg(file_path):
    """
    将 .mp4 视频文件拆分成 .jpg 帧图片
    :param file_path: 视频所在路径
    :return: 返回捕捉到的视频帧图片集
    """
    vc = cv2.VideoCapture(file_path)
    if vc.isOpened():
        r, frame = vc.read()
        if not os.path.exists(CACHE_PATH):
            os.mkdir(CACHE_PATH)
        os.chdir(CACHE_PATH)
    else:
        r = False

    convert_name = 0
    while r:
        frame = frame[0:1080, 272:2188]    # 图片裁剪
        # frame = cv2.resize(frame, (imgs_width, imgs_height))  # 图片大小重置
        cv2.imwrite(str(convert_name) + ".jpg", frame)
        txt2image(str(convert_name) + ".jpg")
        r, frame = vc.read()
        convert_name += 1

    print("当前视频 {} 转换的 .jpg 图片数量为: {}\n".format(file_path.split("\\")[-1], convert_name))

    return vc


def jpg2video(outfile_name, fps):
    """
    将图片合成视频
    :param outfile_name: 输出文件名
    :param fps: 帧频率
    :return: 无返回值
    """
    fourcc = cv2.VideoWriter_fourcc(*"MP4V")   # .mp4 格式的视频

    images = os.listdir(CACHE_PATH)
    img0 = Image.open(os.path.join(CACHE_PATH, images[0]))
    imgs_width = img0.width
    imgs_height = img0.height

    outfile_path = os.path.join(SAVE_PATH, outfile_name + ".mp4")

    vw = cv2.VideoWriter(outfile_path, fourcc, fps, (imgs_width, imgs_height))

    # os.chdir(CACHE_PATH)  # 输出经过处理后的 合成的 原来的 无声视频
    os.chdir(CHARACTER_PATH)   # 输出处理后的字符图片合成的无声视频
    for image in range(len(images)):
        frame = cv2.imread(str(image) + ".jpg")
        vw.write(frame)

    vw.release()


def video2mp3(file_path, outfile_name):
    """
    视频文件转换为音频文件
    :param file_path: 视频文件所在路径
    :param outfile_name: 输出的音频文件名
    :return: 无返回值
    """
    outfile_path = os.path.join(SAVE_PATH, outfile_name + ".mp3")
    if os.path.exists(outfile_path):
        os.remove(outfile_path)

    os.chdir(SAVE_PATH)
    video_clip = mp.VideoFileClip(file_path)
    video_clip.audio.write_audiofile(os.path.join(SAVE_PATH, outfile_name + ".mp3"))


def composite_video_and_mp3(video_path, mp3_path, outfile_name):
    """
    将视频文件和音频文件合成起来
    :param avi_file: 视频文件
    :param mp3_file: 音频文件
    :param outfile_name: 输出的视频文件名
    :return: 无返回值
    """
    outfile_path = os.path.join(SAVE_PATH, outfile_name + ".mp4")
    if os.path.exists(outfile_path):
        os.remove(outfile_path)

    os.chdir(SAVE_PATH)
    video_clip = mp.VideoFileClip(video_path)
    mp3_clip = mp.AudioFileClip(mp3_path)
    composite_clip = video_clip.set_audio(mp3_clip)
    composite_clip.write_videofile(outfile_path)


def remove_dir(file_path):
    """
    删除中间文件夹
    :param path: 文件夹路径
    :return: 无返回值
    """
    if os.path.exists(file_path):
        if os.path.isdir(file_path):
            files = os.listdir(file_path)
            for file in files:
                path = os.path.join(file_path, file)
                if os.path.isdir(path):
                    remove_dir(path)
                elif os.path.isfile(path):
                    os.remove(path)
            os.rmdir(file_path)

            return

        elif os.path.isfile(file_path):
            os.remove(file_path)

        return


if __name__ == '__main__':

    # 视频文件所在路径
    file_path = r"E:\b\node.js\complete-node-bootcamp\1-node-farm\learning\op.mp4"
    # 视频文件名
    file_name = file_path.split("\\")[-1]

    print("*********   开始视频转换    *********\n")
    print("*********   1. 视频转换为图片    *********\n")
    vc = video2jpg(file_path)
    FPS = vc.get(cv2.CAP_PROP_FPS)
    vc.release()
    print("当前视频 {} 转换为图片成功!\n".format(file_name))
    # exit()

    print("*********   2. 图片转换为视频    *********\n")
    outfile_name = file_path.split("\\")[-1].split(".")[0]
    print(outfile_name + ".mp4 开始生成...\n")
    jpg2video(outfile_name, FPS)
    print(outfile_name + ".mp4 生成完毕!\n")
    # exit()

    print("*********   3. 视频转换为音频    *********\n")
    print(outfile_name + ".mp3 开始生成...\n")
    video2mp3(file_path, outfile_name)
    print("\n" + outfile_name + ".mp3 生成完毕!\n")
    # exit()

    print("*********   4. 视频和音频合成为视频    *********\n")
    print(outfile_name + ".mp4 开始合成...\n")
    composite_video_and_mp3(os.path.join(SAVE_PATH, outfile_name + ".mp4"),
                            os.path.join(SAVE_PATH, outfile_name + ".mp3"),
                            outfile_name + "_new")
    print(outfile_name + ".mp4 合成完毕!\n")
    print("当前视频 {} 转换为新视频 {} 成功!\n".format(file_name, outfile_name + "_new" + ".mp4"))
    # exit()

    remove_dir(CACHE_PATH)
    remove_dir(CHARACTER_PATH)
    

二、示例

op_new

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值