[Generate sketches from video pictures and resynthesize them]

A short and fun code to convert video pictures into sketch pictures and videos

Tools used

1. Pycharm python3.8
2. Picture PIL numpy ffmepg
3. Video extraction audio moviepy
4. Video to picture cv2
5. Audio and video synthesis subprocess

Picture to sketch

from PIL import Image
import numpy as np
import os
import time

for i in range(0, len(os.listdir('./image1'))):
    img = os.listdir('./image1')[i]
    img_number = img.split('.')[0]
    a = np.asarray(Image.open("./image1/%s" % img).convert('L')).astype('float')
    time.sleep(0.5)
    depth = 10.  # (0-100)
    grad = np.gradient(a)  # 取图像灰度的梯度值
    grad_x, grad_y = grad  # 分别取横纵图像梯度值
    grad_x = grad_x * depth / 100.
    grad_y = grad_y * depth / 100.
    A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
    uni_x = grad_x / A
    uni_y = grad_y / A
    uni_z = 1. / A

    vec_el = np.pi / 2.2  # 光源的俯视角度,弧度值
    vec_az = np.pi / 4.  # 光源的方位角度,弧度值
    dx = np.cos(vec_el) * np.cos(vec_az)  # 光源对x 轴的影响
    dy = np.cos(vec_el) * np.sin(vec_az)  # 光源对y 轴的影响
    dz = np.sin(vec_el)  # 光源对z 轴的影响

    b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)  # 光源归一化
    b = b.clip(0, 255)

    im = Image.fromarray(b.astype('uint8'))  # 重构图像
    im.save(f"./img1/{
      
      img_number}.jpg")
print("保存成功,请到D:/Python/目录下查看")

Extract audio from video

from moviepy.editor import *

"""
extensions_dict = { "mp4":  {'type':'video', 'codec':['libx264','libmpeg4', 'aac']},
                    'ogv':  {'type':'video', 'codec':['libtheora']},
                    'webm': {'type':'video', 'codec':['libvpx']},
                    'avi':  {'type':'video'},
                    'mov':  {'type':'video'},

                    'ogg':  {'type':'audio', 'codec':['libvorbis']},
                    'mp3':  {'type':'audio', 'codec':['libmp3lame']},
                    'wav':  {'type':'audio', 'codec':['pcm_s16le', 'pcm_s24le', 'pcm_s32le']},
                    'm4a':  {'type':'audio', 'codec':['libfdk_aac']}
                  }
"""
path = r'C:\Users\admin\Desktop\interface1\test_case\douying\video\下载.mp4'
path = eval(repr(path).replace('\\', '/'))
video = VideoFileClip(path)
audio = video.audio
path_img, path_sound = './%s/img' % path.split('/')[-1].split('.')[0], './%s/sound' % path.split('/')[-1].split('.')[0]
if os.path.exists(path_img) == False:
    os.makedirs(path_img)

if os.path.exists(path_sound) == False:
    os.makedirs(path_sound)

path_sound_mp3 = path_sound + "/" + path.split('/')[-1].split('.')[0] + '.mp3'
print(path_sound_mp3)

Video to picture

import cv2

vc = cv2.VideoCapture('./video/艾尔登法环.mp4')  # 读入视频文件
c = 0
rval = vc.isOpened()
# timeF = 1  #视频帧计数间隔频率
while rval:  # 循环读取视频帧
    c = c + 1
    rval, frame = vc.read()
    #    if(c%timeF == 0): #每隔timeF帧进行存储操作
    #        cv2.imwrite('smallVideo/smallVideo'+str(c) + '.jpg', frame) #存储为图像
    if rval:
        # img为当前目录下新建的文件夹
        cv2.imwrite('./image1/' + str(c) + '.jpg', frame)  # 存储为图像
        cv2.waitKey(1)
    else:
        break
vc.release()
print("完成")

Picture to video

import os
import re

from PIL import Image
import cv2

"""
'M', 'J', 'P', 'G' = avi
'M', 'P', '4', 'V' = mp4
"""
if __name__ == '__main__':
    ims_folder = './image1'
    video_path = './out_video_艾尔登法环.mp4'

    ims_path_list = os.listdir(ims_folder)
    ims_path_list.sort()
    fps = 30
    im_path = os.path.join(ims_folder, ims_path_list[0])

    def tryint(s):  # 将元素中的数字转换为int后再排序
        try:
            return int(s)

        except ValueError:
            return s


    def str2int(v_str):  # 将元素中的字符串和数字分割开
        return [tryint(sub_str) for sub_str in re.split('([0-9]+)', v_str)]


    def sort_humanly(v_list):  # 以分割后的list为单位进行排序
        return sorted(v_list, key=str2int)


    wk = sort_humanly(ims_path_list)

    im_size = Image.open(os.path.join(ims_folder, wk[0])).size
    # fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
    fourcc = cv2.VideoWriter_fourcc('M', 'P', '4', 'V')
    videoWriter = cv2.VideoWriter(video_path, fourcc, fps, im_size)

    for i, im_path in enumerate(wk):
        im_path = os.path.join(ims_folder, im_path)
        frame = cv2.imread(im_path)
        videoWriter.write(frame)
        print(im_path)
    videoWriter.release()
    print('finish')
import cv2
import glob

fps = 20  # 保存视频的FPS,可以适当调整

#可以用(*'DVIX')或(*'X264'),如果都不行先装ffmepg: sudo apt-get install ffmepg
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
#saveVideo.avi是要生成的视频名称,(384,288)是图片尺寸
videoWriter = cv2.VideoWriter('saveVideo111.avi', fourcc, fps, (384, 288))  # 括号可能是中文的,改一下,384,288需要改成你的图片尺寸,不然会报错
#imge存放图片
imgs = glob.glob('imge/*.jpg')
for imgname in imgs:
    frame = cv2.imread(imgname)
    videoWriter.write(frame)
    videoWriter.release()

Audio and video synthesis

import subprocess


def video_add_mp3(file_name, mp3_file):
    """

    视频添加音频

    :param file_name: 传入视频文件的路径

    :param mp3_file: 传入音频文件的路径

    :return:

    """

    outfile_name = file_name.split('/')[2].split('.')[0] + '.mp4'
    print(file_name.split('/'))
    print(file_name.split('/')[2])
    print(file_name.split('/')[2].split('.'))
    print(file_name.split('/')[2].split('.')[0])
    print(outfile_name)
    subprocess.call('D:\\FFmpeg\\bin\\ffmpeg.exe -i ' + file_name

                    + ' -i ' + mp3_file + ' -strict -2 -f mp4 '

                    + outfile_name, shell=True)


if __name__ == '__main__':
    # video2mp3(file_name='data-a.mp4')
    mp4_f = './video_processing/video/video_下载.mp4'  # 类似这样"F:/xxx/xxxxx.webm"  视频文件
    mp3_f = './video_processing/sound/下载.mp3'  # 类似这样"F:/xxx/xxxxx.webm"  音频文件
    video_add_mp3(file_name=mp4_f, mp3_file=mp3_f)

The above is the basic code content

Single py file implementation

After completing the above functions, I found that there were too many py files, which caused a conversion to be executed multiple times to successfully transfer the content I wanted. It was too cumbersome, so new code came out.

  1. New directory creation is added . During video conversion, a lot of pictures, audios, and sketches are generated for classification;
  2. A new loop operation is added to achieve single execution and multiple uses;

specific code

import re
import threading
import time

import numpy as np
from moviepy.editor import *
import cv2, os
from PIL import Image
import subprocess

print('请输入图片/视频的绝对路径, 并以英文","隔开进行输入文件夹名称(切记不可输入中文), 切记文件夹名称不可重复哦, 如有重复后果自理, 概不负责哦 !!!')
while True:
    path = input(r'请输入:')
    path_list_0, path_list_1 = '', ''

    if ',' in path:
        path = path.split(',')
        path_list_0 = path[0]
        path_list_1 = path[1]
    else:
        print('您输入的不合法哦 !!!')

    path = eval(repr(path_list_0).replace('\\', '/'))  # 将\\ 转换为 /
    if u'\u4e00' <= path.split('/')[-1].split('.')[0] <= u'\u9fff':
        path_img, path_Sketch, path_sound, path_video, path_SketchVideo = './%s/img' % path_list_1, './%s/Sketch' % path_list_1, './%s/sound' % path_list_1, './%s/video' % path_list_1, './%s/SketchVideo' % path_list_1
    else:
        path_img, path_Sketch, path_sound, path_video, path_SketchVideo = './%s/img' % path_list_1, './%s/Sketch' % path_list_1, './%s/sound' % path_list_1, './%s/video' % path_list_1, './%s/SketchVideo' % path_list_1

    if path.split('/')[-1].split('.')[1] != 'mp4':
        if os.path.exists(path_Sketch) == False:  # 处理后素描图片
            os.makedirs(path_Sketch)
    else:
        if os.path.exists(path_img) == False:  # 初始视频图片
            os.makedirs(path_img)
        if os.path.exists(path_Sketch) == False:  # 处理后素描图片
            os.makedirs(path_Sketch)
        if os.path.exists(path_sound) == False:  # 视频音频
            os.makedirs(path_sound)
        if os.path.exists(path_video) == False:  # 素描视频
            os.makedirs(path_video)
        if os.path.exists(path_SketchVideo) == False:  # 合成音视频
            os.makedirs(path_SketchVideo)


    # 处理视频mp3
    def Sound_mp3():
        print('<----------------------------- 开始提取音频并生成MP3 ----------------------------->')
        """
        extensions_dict = { "mp4":  {'type':'video', 'codec':['libx264','libmpeg4', 'aac']},
                            'ogv':  {'type':'video', 'codec':['libtheora']},
                            'webm': {'type':'video', 'codec':['libvpx']},
                            'avi':  {'type':'video'},
                            'mov':  {'type':'video'},

                            'ogg':  {'type':'audio', 'codec':['libvorbis']},
                            'mp3':  {'type':'audio', 'codec':['libmp3lame']},
                            'wav':  {'type':'audio', 'codec':['pcm_s16le', 'pcm_s24le', 'pcm_s32le']},
                            'm4a':  {'type':'audio', 'codec':['libfdk_aac']}
                          }
        """
        video = VideoFileClip(path)
        audio = video.audio
        path_sound_mp3 = path_sound + "/" + path.split('/')[-1].split('.')[0] + '.mp3'
        audio.write_audiofile(path_sound_mp3)
        print(f'<--------- 音频提取成功已生成MP3 存储位置: {
      
      path_list_1}\sound --------->' + '\n')


    # 处理视频拆解图片
    def Picture():
        print('<----------------------------- 开始拆解视频帧图片 ----------------------------->')
        vc = cv2.VideoCapture(path)  # 读入视频文件
        c = 0
        rval = vc.isOpened()
        while rval:  # 循环读取视频帧
            c = c + 1
            rval, frame = vc.read()
            if rval:
                # img为当前目录下新建的文件夹
                path_picture = path_img + "/" + str(c) + '.jpg'
                cv2.imwrite(path_picture, frame)  # 存储为图像
                cv2.imencode('.jpg', frame)[1].tofile(path_picture)  # 存储成功
                cv2.waitKey(1)
            else:
                break
        vc.release()
        print(f'<--------- 拆解视频帧图片完成 存储位置: {
      
      path_list_1}\img --------->' + '\n')


    # 原图转素描
    def Sketch():
        print('<----------------------------- 开始原图转素描 ----------------------------->')
        if path.split('.')[-1] == 'mp4':
            print(f'图片实在太多了,{
      
      len(os.listdir(path_img))}张, 转换的时间有点长哦,请稍等 !!!')
            for i in range(0, len(os.listdir(path_img))):
                img = os.listdir(path_img)[i]
                img_number = img.split('.')[0]
                a = np.asarray(Image.open(path_img + "/%s" % img).convert('L')).astype('float')
                time.sleep(0.5)
                depth = 10.  # (0-100)
                grad = np.gradient(a)  # 取图像灰度的梯度值
                grad_x, grad_y = grad  # 分别取横纵图像梯度值
                grad_x = grad_x * depth / 100.
                grad_y = grad_y * depth / 100.
                A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
                uni_x = grad_x / A
                uni_y = grad_y / A
                uni_z = 1. / A

                vec_el = np.pi / 2.2  # 光源的俯视角度, 弧度值
                vec_az = np.pi / 4.  # 光源的方位角度, 弧度值
                dx = np.cos(vec_el) * np.cos(vec_az)  # 光源对x 轴的影响
                dy = np.cos(vec_el) * np.sin(vec_az)  # 光源对y 轴的影响
                dz = np.sin(vec_el)  # 光源对z 轴的影响

                b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)  # 光源归一化
                b = b.clip(0, 255)

                im = Image.fromarray(b.astype('uint8'))  # 重构图像
                im.save(path_Sketch + f"/{
      
      img_number}.jpg")

                # src = cv2.imread(path_Sketch + f"/{img_number}.jpg", 100)
                # cv2.imwrite(path_Sketch + f"/{img_number}.jpg", src, [cv2.IMWRITE_JPEG_QUALITY, 100])
            print(f'<--------- 原图转素描成功 存储位置: {
      
      path_list_1}\Sketch --------->' + '\n')
        else:
            img_number = path.split('/')[-1].split('.')[0]
            a = np.asarray(Image.open(path).convert('L')).astype('float')
            time.sleep(0.5)
            depth = 10.  # (0-100)
            grad = np.gradient(a)  # 取图像灰度的梯度值
            grad_x, grad_y = grad  # 分别取横纵图像梯度值
            grad_x = grad_x * depth / 100.
            grad_y = grad_y * depth / 100.
            A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
            uni_x = grad_x / A
            uni_y = grad_y / A
            uni_z = 1. / A

            vec_el = np.pi / 2.2  # 光源的俯视角度, 弧度值
            vec_az = np.pi / 4.  # 光源的方位角度, 弧度值
            dx = np.cos(vec_el) * np.cos(vec_az)  # 光源对x 轴的影响
            dy = np.cos(vec_el) * np.sin(vec_az)  # 光源对y 轴的影响
            dz = np.sin(vec_el)  # 光源对z 轴的影响

            b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)  # 光源归一化
            b = b.clip(0, 255)

            im = Image.fromarray(b.astype('uint8'))  # 重构图像
            im.save(path_Sketch + f"/{
      
      img_number}.jpg")

            # src = cv2.imread(path_Sketch + f"/{img_number}.jpg", 100)
            # cv2.imwrite(path_Sketch + f"/{img_number}.jpg", src, [cv2.IMWRITE_JPEG_QUALITY, 100])
            print(f'<--------- 原图转素描成功 存储位置: {
      
      path_list_1}\Sketch --------->' + '\n')


    # 合成素描视频
    def PictureVideo():
        print('<----------------------------- 开始合成素描视频 ----------------------------->')

        """
        'M', 'J', 'P', 'G' = avi
        'M', 'P', '4', 'V' = mp4
        """
        ims_path_list = os.listdir(path_Sketch)
        ims_path_list.sort()
        fps = 30

        def tryint(s):  # 将元素中的数字转换为int后再排序
            try:
                return int(s)

            except ValueError:
                return s

        def str2int(v_str):  # 将元素中的字符串和数字分割开
            return [tryint(sub_str) for sub_str in re.split('([0-9]+)', v_str)]

        def sort_humanly(v_list):  # 以分割后的list为单位进行排序
            return sorted(v_list, key=str2int)

        wk = sort_humanly(ims_path_list)

        im_size = Image.open(os.path.join(path_Sketch, wk[0])).size
        # fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')
        fourcc = cv2.VideoWriter_fourcc('M', 'P', '4', 'V')
        videoWriter = cv2.VideoWriter(path_video + '/video_' + path.split('/')[-1].split('.')[0] + '.mp4', fourcc, fps,
                                      im_size)

        for i, im_path in enumerate(wk):
            im_path = os.path.join(path_Sketch, im_path)
            frame = cv2.imread(im_path)
            videoWriter.write(frame)
        videoWriter.release()
        print(f"<--------- 合成素描视频成功 存储位置: {
      
      path_list_1}\video --------->" + '\n')


    # 合成音视频
    def video_add_mp3(file_name, mp3_file):
        print('<----------------------------- 开始合成素描视频+背景音乐 ----------------------------->')

        """

        视频添加音频

        :param file_name: 传入视频文件的路径

        :param mp3_file: 传入音频文件的路径

        :return:

        """

        outfile_name = path_SketchVideo + "/new_video.mp4"

        subprocess.call('D:\\FFmpeg\\bin\\ffmpeg.exe -i ' + file_name

                        + ' -i ' + mp3_file + ' -strict -2 -f mp4 '

                        + outfile_name, shell=True)

        print(f"<--------- 合成素描视频+背景音乐完成 存储位置: {
      
      path_list_1}\SketchVideo --------->" + '\n')


    # 压缩视频
    def SaveVideo():
        print('<----------------------------- 开始压缩素描视频 ----------------------------->')
        fpsize = os.path.getsize(path_SketchVideo + "/new_video.mp4") / 1024
        if fpsize >= 100.0:  # 大于等于100KB的视频需要压缩
            if path_SketchVideo + "/new_video_ys.mp4":
                compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(
                    path_SketchVideo + "/new_video.mp4", path_SketchVideo + "/new_video_ys.mp4")
                isRun = os.system(compress)

                print('<----------------------------- 压缩素描视频完成 ----------------------------->' + '\n')
            else:
                compress = "ffmpeg -i {} -r 10 -pix_fmt yuv420p -vcodec libx264 -preset veryslow -profile:v baseline -crf 23 -acodec aac -b:a 32k -strict -5 {}".format(
                    path_SketchVideo + "/new_video.mp4", path_SketchVideo + "/new_video.mp4")
                isRun = os.system(compress)

                print('<----------------------------- 压缩素描视频完成 ----------------------------->' + '\n')
            if isRun != 0:
                return ('isRun', isRun, "没有安装ffmpeg")


    # 视频处理
    def StartProcessingVideo():
        print('<`---------- 您上传的是视频哦, 处理可能需要些时间, 尽情期待 ----------`>' + '\n')
        Sound_mp3()  # 音频MP3
        Picture()  # 视频切原图
        Sketch()  # 原图转素描
        PictureVideo()  # 合成素描视频
        mp3_f = path_sound + "/" + path.split('/')[-1].split('.')[0] + '.mp3'
        mp4_f = path_video + "/video_" + path.split('/')[-1].split('.')[0] + '.mp4'
        video_add_mp3(file_name=mp4_f, mp3_file=mp3_f)  # 合成素描音视频
        SaveVideo()


    # 图片处理
    def StartProcessingPictures():
        print('<`---------- 您上传的是图片哦, 处理起来很快的, 尽情期待 ----------`>' + '\n')
        Sketch()


    if path.split('/')[-1].split('.')[1] == 'mp4':
        StartProcessingVideo()
    else:
        StartProcessingPictures()

    operation = input('请问是否继续,继续请输入“是”: ')
    if operation != '是':
        exit()

Work information

Douyin: What is published in Douyin is sketch audio and video synthesis
https://www.douyin.com/user/MS4wLjABAAAANtLRNzfIQBaWgzev17EdTs0X_1JTszXdDCUc657AqvWv9GzGUVleCgwmmQ7OcCwV
Weibo: What is published in Chaohua 4Mango is a picture-to-sketch conversionInsert image description here

Guess you like

Origin blog.csdn.net/weixin_43603846/article/details/125180275