Python 小型课设作业,仅200行代码,使用youtube-dl下载视频,使用OpenCV和ffmpeg处理视频成字符视频

一、程序背后的小故事:       

      因为不想像传统的课设作业一样做一个很多人做过的小游戏,管理程序等,所以花了很长时间在选择一个有趣的程序方向,突然想起来以前看到的字符跳舞视频,突然引起了我的兴趣。分析字符视频的创建流程,想到了利用OpenCV将视频分解成一帧一帧的,然后再对每个图片进行处理。

       在处理每帧图片时,可以通过灰度来区分色块,计算每个图片各色块的灰度,将256灰度映射到70个字符上,从而形成字符图片,再利用OpenCV将逐帧字符图片合成成字符视频。这样合成的视频是没有声音的,再利用ffmpeg工具将原视频中的音频分离出来,再与字符视频合成。

      本以为大功告成了,突然想到找测试视频时候的窘况,各大网站都不支持直接下载视频。决定再加一个输入视频真实网站直接下载视频的功能,方便视频转换成字符视频。利用youtube-dl模块的功能,完成了输入视频真实网址,再选择视频和音频组合下载不同质量的视频。经过测试,可以下载Bilibili,Youtube等视频网站的视频。

二、程序流程图:

       设计这种程序先大致想一下流程,如果不是要交报告想来我也是不会画流程图的,呜呜呜。随手一画,别太较真。

三、代码部分:

1、通过灰度来区分色块,计算每个图片各色块的灰度,将256灰度映射到70个字符,将逐帧图片转换成字符图片(处理逐帧图片核心代码)这个其实是copy了网上其他大佬处理字符图片的办法,嘿嘿嘿

def get_char(r, g, b, alpha=256):  # alpha透明度
    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 PictureToChar(folder_path, ascii_path, c):
    print("开始将图片转为字符型:")
    # 循环读取逐帧图片
    for icount in range(1, c):
        IMG = folder_path + str(icount) + '.jpg'  # 文件路径
        if os.path.exists(IMG):
            im = Image.open(IMG)
            # 视频分割后图片的长与宽,与合成视频时要相统一,保存下来,合成字符视频时用到
            asciiImage = im
            WIDTH = int(im.width / 6)  # 高度比例为原图的1/6较好,由于字体宽度
            HEIGHT = int(im.height / 15)  # 高度比例为原图的1/15较好,由于字体高度
            im_txt = Image.new("RGB", (im.width, im.height), (255, 255, 255))
            im = im.resize((WIDTH, HEIGHT), Image.NEAREST)
            txt = ""
            colors = []
            for i in range(HEIGHT):
                for j in range(WIDTH):
                    pixel = im.getpixel((j, i))
                    colors.append((pixel[0], pixel[1], pixel[2]))  # 记录像素颜色信息
                    if (len(pixel) == 4):
                        txt += get_char(pixel[0], pixel[1], pixel[2], pixel[3])
                    else:
                        txt += get_char(pixel[0], pixel[1], pixel[2])
                txt += '\n'
                colors.append((255, 255, 255))
            dr = ImageDraw.Draw(im_txt)
            font = ImageFont.load_default().font  # 获取字体
            x = y = 0
            # 获取字体的宽高
            font_w, font_h = font.getsize(txt[1])
            font_h *= 1.37  # 调整后更佳
            # ImageDraw为每个ascii码进行上色
            for i in range(len(txt)):
                if (txt[i] == '\n'):
                    x += font_h
                    y = -font_w
                dr.text([y, x], txt[i], colors[i])
                y += font_w
            # 输出
            name = str(icount) + '.jpg'
            print(name)
            im_txt.save(ascii_path + str(icount) + '.jpg')
    return asciiImage

2、原视频分割为逐帧图片

def VideoToPicture(path):
    # 进行视频的载入
    vc = cv2.VideoCapture(path)
    print("开始将原视频分割为图片:")
    c = 0
    # 判断载入的视频是否可以打开
    ret = vc.isOpened()
    # 循环读取视频帧
    while ret:
        c = c + 1
        # 进行单张图片的读取,ret的值为True或者Flase,frame表示读入的图片
        ret, frame = vc.read()
        if ret:
            # 存储为图像
            cv2.imwrite(folder_path + str(c) + '.jpg', frame)
            # 输出图像名称
            print(folder_path + str(c) + '.jpg')
            # 在一个给定的时间内(单位ms)等待用户按键触发,1ms
            cv2.waitKey(1)
        else:
            break
    # 视频释放
    vc.release()
    return c

3、将字符图片合成字符视频,当然,这个时候是没声音的,还需要后续合成。

def charToVideo(ascii_path, asciiImage, path, c, finalVideo_path):
    # 不同视频编码对应不同视频格式
    if path.endswith(".mp4"):
        fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')  # 这里是mp4格式,文件名后缀为.mp4
    elif path.endswith(".avi"):
        fourcc = cv2.VideoWriter_fourcc('I', '4', '2', '0')  # (例:'I','4','2','0' 对应avi格式)
    elif path.endswith(".flv"):
        fourcc = cv2.VideoWriter_fourcc('F', 'L', 'V', '1')  # 该参数是Flash视频,文件名后缀为.flv

    print("开始将字符型图片变为视频:")
    # 输出视频参数设置,包含视频文件名、编码器、帧率、视频宽高(此处参数需和字符图片大小一致)
    video_file = finalVideo_path + 'out' + '_' + 'ascci' + '_' + path
    videoWriter = cv2.VideoWriter(video_file, fourcc, 30.0,
                                  (asciiImage.width, asciiImage.height))
    # 循环读取图片
    for i in range(1, c):
        filename = ascii_path + str(i) + '.jpg'
        # 判断图片是否存在
        if os.path.exists(filename):
            img = cv2.imread(filename=filename)
            # 在一个给定的时间内(单位ms)等待用户按键触发,100ms
            cv2.waitKey(100)
            # 将图片写入视频中
            videoWriter.write(img)
            print(str(i) + '.jpg' + ' done!')
    # 视频释放
    videoWriter.release()
    print("字符视频已成功生成!!!")
    return video_file

4、分离原视频中的音乐和字符视频合并,形成有声音的字符视频

def VideoToMp3(path, finalVideo_path):  # 分离原视频中的音乐
    outMusic_name = finalVideo_path + path.split('.')[0] + '.mp3'  # 将原视频文件后缀名去掉加上.mp3
    os.system(f"ffmpeg -i {path} -vn {outMusic_name} ")
    return outMusic_name

def VideoAddMp3(video_file, outMusic_name):  # 将分离出来的原视频中的音乐和字符视频合并
    video_final = finalVideo_path + 'Final' + '_' + '_' + path
    os.system(f"ffmpeg -i {outMusic_name} -i {video_file} {video_final}")

5、视频下载功能(利用youtube-dl下载视频,如果下载有问题可能是重命名的问题,去掉让他直接用解析的网站的名字命名就好了)

def linkToVideo(link_url):
    #将链接中的视频下载
     
     os.system(f"youtube-dl -F {link_url}")
     print("====请按’视频序号+音频序号‘顺序选择输入视频和音频组合,如果只有一个就只输入一个数字===== ")
     num = input()
     VideoDownload_name = input("请给下载视频重命名:  ")
     os.system(f"youtube-dl -f {num} {link_url} -o {VideoDownload_name}")

以上是部分重要函数部分代码,整个项目已上传Github仓库:Github仓库https://github.com/Dddwaiting/Python

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值