使用python制作字符视频(蔡徐坤唱跳rap字符视频)

Posted ypeijasd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用python制作字符视频(蔡徐坤唱跳rap字符视频)相关的知识,希望对你有一定的参考价值。

 我生成了一个蔡徐坤 唱、跳、RAP的字符视频,链接为:

蔡徐坤唱跳RAP字符视频

使用python将一个视频转换为字符视频

详细视频教程,总共8分钟。

用python制作字符视频详细教程(视频版)

文字教程见下文:

首先需要安装python

然后安装所需要的包:cv2、PIL

具体安装方法:

安装cv2

pip install opencv-python

安装PIL

pip install pillow

在安装过程中经常遇到安装时间过长、安装失败等问题。

可以在官网下载对应版本的whl文件,采用本地安装的方法。

opencv-python官方下载地址   

pillow官方下载地址

我的博客下载地址

下载时需要注意自己的电脑是32位还是64位,

需要注意自己电脑上装的python是多少版本的,

选择opencv_python和pillow时,要对应上才行。

此外还需要下载ffmpeg包,用来抽取视频中的声音,以及将声音添加到生成的字符视频中。

如果不配置ffmpeg的话,生成的视频是没有声音的。

下载时同样要注意自己的电脑是32位还是64位。

ffmpeg32位和64位下载地址

下载好ffmpeg包之后还需要配置环境变量。

等一切准备工作就绪之后,就可以运行python代码生成字符视频了,python代码如下。

import argparse
import os
import cv2
import subprocess
from cv2 import VideoWriter_fourcc
from PIL import Image, ImageFont, ImageDraw

class Video2CodeVideo:
    def __init__(self):
        self.config_dict = 
            # 原视频文件
            "input_file": "test.mp4",
            # 中间文件存放目录
            "cache_dir": "cache",
            # 是否保留过程文件。True--保留,False--不保留
            "save_cache_flag": True,
            # 使用使用的字符集
            "ascii_char_list": list("01B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1[]?-_+~<>i!lI;:oa+>!:+. "),
        

    # 第一步从函数,将像素转换为字符
    # 调用栈:video_2_txt_jpg -> txt_2_image -> rgb_2_char
    def rgb_2_char(self, r, g, b, alpha=256):
        if alpha == 0:
            return ''
        length = len(self.config_dict["ascii_char_list"])
        gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
        unit = (256.0 + 1) / length
        return self.config_dict["ascii_char_list"][int(gray / unit)]

    # 第一步从函数,将txt转换为图片
    # 调用栈:video_2_txt_jpg -> txt_2_image -> rgb_2_char
    def txt_2_image(self, file_name):
        im = Image.open(file_name).convert('RGB')
        # gif拆分后的图像,需要转换,否则报错,由于gif分割后保存的是索引颜色
        raw_width = im.width
        raw_height = im.height
        width = int(raw_width / 6)
        height = int(raw_height / 15)
        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 += self.rgb_2_char(pixel[0], pixel[1], pixel[2], pixel[3])
                else:
                    txt += self.rgb_2_char(pixel[0], pixel[1], pixel[2])
            txt += '\\n'
            colors.append((255, 255, 255))

        im_txt = Image.new("RGB", (raw_width, raw_height), (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], fill=colors[i])

            y += font_w
        name = file_name
        im_txt.save(name)


    # 第一步,将原视频转成字符图片
    # 调用栈:video_2_txt_jpg -> txt_2_image -> rgb_2_char
    def video_2_txt_jpg(self, file_name):
        vc = cv2.VideoCapture(file_name)
        c = 1
        if vc.isOpened():
            r, frame = vc.read()
            if not os.path.exists(self.config_dict["cache_dir"]):
                os.mkdir(self.config_dict["cache_dir"])
            os.chdir(self.config_dict["cache_dir"])
        else:
            r = False
        while r:
            cv2.imwrite(str(c) + '.jpg', frame)
            self.txt_2_image(str(c) + '.jpg')  # 同时转换为ascii图
            r, frame = vc.read()
            c += 1
        os.chdir('..')
        return vc

    # 第二步,将字符图片合成新视频
    def txt_jpg_2_video(self, outfile_name, fps):
        fourcc = VideoWriter_fourcc(*"MJPG")

        images = os.listdir(self.config_dict["cache_dir"])
        im = Image.open(self.config_dict["cache_dir"] + '/' + images[0])
        vw = cv2.VideoWriter(outfile_name + '.avi', fourcc, fps, im.size)

        os.chdir(self.config_dict["cache_dir"])
        for image in range(len(images)):

            frame = cv2.imread(str(image + 1) + '.jpg')
            vw.write(frame)

        os.chdir('..')
        vw.release()

    # 第三步,从原视频中提取出背景音乐
    def video_extract_mp3(self, file_name):
        outfile_name = file_name.split('.')[0] + '.mp3'
        subprocess.call('ffmpeg -i ' + file_name + ' -f mp3 -y ' + outfile_name, shell=True)

    # 第四步,将背景音乐添加到新视频中
    def video_add_mp3(self, file_name, mp3_file):
        outfile_name = file_name.split('.')[0] + '-txt.mp4'
        subprocess.call('ffmpeg -i ' + file_name + ' -i ' + mp3_file + ' -strict -2 -f mp4 -y ' + outfile_name, shell=True)

    # 第五步,如果没配置保留则清除过程文件
    def clean_cache_while_need(self):
        # 为了清晰+代码比较短,直接写成内部函数
        def remove_cache_dir(path):
            if os.path.exists(path):
                if os.path.isdir(path):
                    dirs = os.listdir(path)
                    for d in dirs:
                        if os.path.isdir(path + '/' + d):
                            remove_cache_dir(path + '/' + d)
                        elif os.path.isfile(path + '/' + d):
                            os.remove(path + '/' + d)
                    os.rmdir(path)
                    return
                elif os.path.isfile(path):
                    os.remove(path)
                return
        # 为了清晰+代码比较短,直接写成内部函数
        def delete_middle_media_file():
            os.remove(self.config_dict["input_file"].split('.')[0] + '.mp3')
            os.remove(self.config_dict["input_file"].split('.')[0] + '.avi')
        # 如果没配置保留则清除过程文件
        if not self.config_dict["save_cache_flag"]:
            remove_cache_dir(self.config_dict["cache_dir"])
            delete_middle_media_file()

    # 程序主要逻辑
    def main_logic(self):
        # 第一步,将原视频转成字符图片
        print("第一步,正在将原视频转成字符图片")
        vc = self.video_2_txt_jpg(self.config_dict["input_file"])
        # 获取原视频帧率
        fps = vc.get(cv2.CAP_PROP_FPS)
        print("获取原视频帧率:")
        print(fps)
        vc.release()
        print("已将原视频转成字符图片\\n")
        # 第二步,将字符图片合成新视频
        print("第二步,正在将字符图片合成新视频")
        self.txt_jpg_2_video(self.config_dict["input_file"].split('.')[0], fps)
        print(self.config_dict["input_file"], self.config_dict["input_file"].split('.')[0] + '.mp3')
        print("已将字符图片合成新视频\\n")
        # 第三步,从原视频中提取出背景音乐
        print("第三步, 正在从原视频中提取出背景音乐")
        self.video_extract_mp3(self.config_dict["input_file"])
        print("已从原视频中提取出背景音乐\\n")
        # 第四步,将背景音乐添加到新视频中
        print("第四步, 正在将背景音乐添加到新视频中")
        self.video_add_mp3(self.config_dict["input_file"].split('.')[0] + '.avi', self.config_dict["input_file"].split('.')[0] + '.mp3')
        print("已将背景音乐添加到新视频中\\n")
        # 第五步,如果没配置保留则清除过程文件
        self.clean_cache_while_need()
        print("字符视频制作完毕\\n字符视频为test-txt.mp4\\n")
        print("按任意键结束")
        a=input()

if __name__ == '__main__':
    obj = Video2CodeVideo()
    obj.main_logic()

注意要将源视频和python代码放在一个目录下,将原视频命名为test.mp4,运行结束后,会生成一个test-txt.mp4文件,就是我们想要的字符视频。

有问题欢迎交流

唱跳rap和篮球

唱、跳、rap和篮球

大中锋的学院要组织学生参观博物馆,要求学生们在博物馆中排成一队进行参观。他的同学可以分为四类:一部分最喜欢唱、一部分最喜欢跳、一部分最喜欢rap,还有一部分最喜欢篮球。如果队列中(k,k + 1,k+1,k + 2,k+2,k + 3,k+3)位置上的同学依次,最喜欢唱、最喜欢跳、最喜欢rap、最喜欢篮球,那么他们就会聚在一起讨论蔡徐坤。大中锋不希望这种事情发生,因为这会使得队伍显得很乱。大中锋想知道有多少种排队的方法,不会有学生聚在一起讨论蔡徐坤。两个学生队伍被认为是不同的,当且仅当两个队伍中至少有一个位置上的学生的喜好不同。由于合法的队伍可能会有很多种,种类数对998244353取模。

Input

输入数据只有一行。每行55个整数,第一个整数n,代表大中锋的学院要组织多少人去参观博物馆。接下来四个整数a、b、c、d,分别代表学生中最喜欢唱的人数、最喜欢跳的人数、最喜欢rap的人数和最喜欢篮球的人数。保证(a+b+c+d ge n)

Output

每组数据输出一个整数,代表你可以安排出多少种不同的学生队伍,使得队伍中没有学生聚在一起讨论蔡徐坤。结果对998244353取模。

Sample Input 1

4 4 3 2 1

Sample Output 1

174

Sample Input 2

996 208 221 132 442

Sample Output 2

442572391

思路:

(令f_x=(n-4x)!sumlimits_{i=0}^asumlimits_{j=0}^bsumlimits_{k=0}^csumlimits_{w=0}^d[a+b+c+d=n-4x]frac{1}{i!j!k!w!})

(ans=sumlimits_{i=0}^{min{a,b,c,d,lfloorfrac{n}{4} floor}}(-1)^i(^{n-3i}_{ i})f_i)

证明:

后面把讨论蔡徐坤的段叫(jntm)

(考虑枚举jntm的数量,进行容斥)

(假设f_i为在去掉jntm后的方案数)

(ecause 每个jntm长度4)

( herefore 有C_{n-3i}^i的方案数)

( herefore ans=sumlimits_{i=0}^{min{a,b,c,d,lfloorfrac{n}{4} floor}}(-1)^i(^{n-3i}_{ i})f_i)

(考虑枚举剩下的位置中有多少个j,n,t,m)

(f_x=sumlimits_{i=0}^asumlimits_{j=0}^bsumlimits_{k=0}^csumlimits_{w=0}^d[a+b+c+d=n-4x]frac{(n-4x)!}{i!j!k!w!}=(n-4x)!sumlimits_{i=0}^asumlimits_{j=0}^bsumlimits_{k=0}^csumlimits_{w=0}^d[a+b+c+d=n-4x]frac{1}{i!j!k!w!})

(发现可以NTT优化卷积,时间复杂度O(n^2log_2n))

(mathfrak{Talk is cheap ,show you the code.})

#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
# define read read1<int>()
# define Type template<typename T>
Type inline T read1(){
    T n=0;
    char k;
    bool fl=0;
    do (k=getchar())=='-'&&(fl=1);while('9'<k||k<'0');
    while(47<k&&k<58)n=(n<<3)+(n<<1)+(k^48),k=getchar();
    return fl?-n:n;
}
inline int r(int mod){
    int n=0;
    char k;
    bool fl=0;
    do (k=getchar())=='-'&&(fl=1);while('9'<k||k<'0');
    while(47<k&&k<58)n=(10ll*n+(k^48))%mod,k=getchar();
    return fl?mod-n:n;
}
# define f(i,l,r) for(int i=(l);i<=(r);++i)
# define fre(k) freopen(k".in","r",stdin);freopen(k".ans","w",stdout)
# define ll int64_t
class Array{
    private:
        vector<int>a;
    public:
        Array(const int size,const int f):a(size,f){}
        void push(int n){a.push_back(n);}
        Array(int* l=NULL,int* r=NULL){while(l!=r)push(*l),++l;}
        inline int size(){return a.size();}
        inline int& operator [] (const int x){return a[x];}
        void resize(int n){a.resize(n);}
        void clear(){a.clear();}
        void swap(){reverse(a.begin(),a.end());}
        int& top(){return a[a.size()-1];}
        void pop(){a.pop_back();}
        Array& operator %= (const int k){
            for(int i=0;i<size();++i)
                a[i]%=k;
            return *this;
        }
};
const int mod=998244353,g=3,inv2=499122177;
Array operator -(Array a,Array b){
    int N=a.size(),M=b.size();
    Array t;
    for(int i=0;i<N||i<M;++i){
        t.push((i<N?a[i]:0)-(i<M?b[i]:0));
        if(t.top()<0)t.top()+=mod;
    }
    return t;
}
Array operator +(Array a,Array b){
    int N=a.size(),M=b.size();
    Array t;
    for(int i=0;i<N||i<M;++i){
        t.push((i<N?a[i]:0)+(i<M?b[i]:0));
        if(t.top()>=mod)t.top()-=mod;
    }
    return t;
}
Array operator *(Array a,int n){
    int N=a.size();
    for(int i=0;i<N;a[i]=(ll)a[i]*n%mod,++i);
    return a;
}
Array operator *(int n,Array a){return a*n;}
int qkpow(int b,int m,int mod){
    int tem=b,ans=1;
    for(;m;m>>=1,tem=(ll)tem*tem%mod)
        if(m&1)ans=(ll)ans*tem%mod;
    return ans;
}
int* NTT(const int len,Array& a,const bool Ty,int* r=NULL){
    if(!r){
        r=new int[len];
        r[0]=0;int L=log2(len);
        f(i,0,len-1)
            r[i]=(r[i>>1]>>1)|((i&1)<<L-1);
    }
    f(i,0,len-1)
        if(i<r[i])swap(a[i],a[r[i]]);
    for(int i=1;i<len;i<<=1){
        int T=qkpow(Ty?g:332748118,(mod-1)/(i<<1),mod);
        for(int W=i<<1,j=0;j<len;j+=W){
            ll omega=1;
            for(int k=0;k<i;++k,omega=omega*T%mod){
                ll x(a[j+k]),y(omega*a[i+j+k]%mod);
                a[j+k]=x+y;(a[j+k]>=mod)&&(a[j+k]-=mod);
                a[i+j+k]=x-y+mod;(a[i+j+k]>=mod)&&(a[i+j+k]-=mod);
            }
        }
    }
    return r;
}
Array operator * (Array x,Array y){
    int n=x.size()-1,m=y.size()-1;
    int limit=1;
    while(limit<=n+m)limit<<=1;
    Array ans;
    x.resize(limit+1);
    y.resize(limit+1);
    int *r;
    r=NTT(limit,x,1);
    NTT(limit,y,1,r);
    f(i,0,limit)x[i]=(ll)x[i]*y[i]%mod;
    NTT(limit,x,0,r);
    int tem=qkpow(limit,mod-2,mod);
    f(i,0,n+m)ans.push((ll)x[i]*tem%mod);
    return ans;
}
Array& operator *= (Array& x,Array y){
    return x=x*y;
}
void Rev(Array &x,Array y){
    int n=x.size()-1,m=y.size()-1;
    int limit=1;
    while(limit<=n+m)limit<<=1;
    Array ans;
    x.resize(limit+1);
    y.resize(limit+1);
    int *r;
    r=NTT(limit,x,1);
    NTT(limit,y,1,r);
    f(i,0,limit)x[i]=(ll)(2ll-(ll)x[i]*y[i]%mod+mod)%mod*y[i]%mod;
    NTT(limit,x,0,r);
    int tem=qkpow(limit,mod-2,mod);
    f(i,0,n+m)x[i]=(ll)x[i]*tem%mod;
    x.resize(n+m+1);
}
Array Inv(Array a){
    int N=a.size();
    // printf("%d
",N);
    if(N==1)return Array(1,qkpow(a[0],mod-2,mod));
    Array b=a;b.resize(N+1>>1);
    b=Inv(b);b.resize(N);
    Rev(a,b);
    a.resize(N);
    return a;
}
Array operator / (Array x,Array y){
    int N=x.size()-1,M=y.size()-1;
    if(N<M)return Array(1,0);
    x.swap();y.swap();
    y.resize(N-M+1);
    x*=Inv(y);
    x.resize(N-M+1);
    x.swap();
    return x;
}
Array sqrt(Array x){
    int N=x.size();
    if(N==1)return Array(1,1);
    Array y=x;
    y.resize(N+1>>1);
    y=sqrt(y);
    y.resize(N);
    Array z=Inv(y);
    x*=z;x.resize(N);
    return inv2*(y+x);
}
Array diff(Array x){
    for(int i=0;i+1<x.size();++i)
        x[i]=(ll)x[i+1]*(i+1)%mod;
    x.pop();
    return x;
}
Array integral(Array x){
    for(int i=x.size();--i;)
        x[i]=(ll)x[i-1]*qkpow(i,mod-2,mod)%mod;
    x[0]=0;
    return x;
}
Array ln(Array x){
    int N=x.size();
    x=integral(diff(x)*Inv(x));
    x.resize(N);
    return x;
}
Array exp(Array x){
    int N=x.size();
    if(N==1)return Array(1,1);
    Array y=x;
    y.resize(N+1>>1);
    y=exp(y);
    y.resize(N);
    y[0]=1;
    ++x[0];
    y*=(x-ln(y));
    y.resize(N);
    return y;
}
int fac[1001],n(read),a(read),b(read),c(read),d(read),inv[1001];
Array x,y,z,w;
int C(int n,int m){return (ll)fac[n]*inv[n-m]%mod*inv[m]%mod;}
int sigma(int l){
    int ans=C(n-l*3,l),A=a-l,B=b-l,C=c-l,D=d-l;
    x.clear();y.clear();z.clear();w.clear();
    f(i,0,A)x.push(inv[i]);
    f(i,0,B)y.push(inv[i]);
    f(i,0,C)z.push(inv[i]);
    f(i,0,D)w.push(inv[i]);
    int limit=1;
    while(limit<=A+B+C+D)limit<<=1;
    x.resize(limit+1);
    y.resize(limit+1);
    z.resize(limit+1);
    w.resize(limit+1);
    int *r;
    r=NTT(limit,x,1);
    NTT(limit,y,1,r);
    NTT(limit,z,1,r);
    NTT(limit,w,1,r);
    f(i,0,limit)x[i]=(ll)x[i]*y[i]%mod*z[i]%mod*w[i]%mod;
    NTT(limit,x,0,r);
    int tem=qkpow(limit,mod-2,mod);
    return (ll)ans*fac[n-(l<<2)]%mod*x[n-(l<<2)]%mod*tem%mod;
}
int main(){
    fac[1]=fac[0]=inv[0]=inv[1]=1;
    for(int i=2;i<=1000;++i)
        inv[i]=qkpow(fac[i]=(ll)fac[i-1]*i%mod,mod-2,mod);
    int s=min(n>>2,min(a,min(b,min(c,d)))),ans=0;
    for(int i=0;i<=s;++i)
        if(i&1)ans=(ans-sigma(i)+mod)%mod;
        else ans=(ans+sigma(i))%mod;
    printf("%d",ans);
    return 0;
}

以上是关于使用python制作字符视频(蔡徐坤唱跳rap字符视频)的主要内容,如果未能解决你的问题,请参考以下文章

唱跳rap和篮球

Web在线聊天室(完结) --- 注册用户+ip地址

Web在线聊天室(完结) --- 注册用户+ip地址

TJOI 2019唱跳rap和篮球

pygame游戏用Python实现一个蔡徐坤大战篮球的小游戏,可还行?附源码

蔡徐坤多大了?