一短好玩的代码,视频图片转素描图片视频
使用的工具
1、Pycharm python3.8
2、图片类 PIL numpy ffmepg
3、视频提取音频 moviepy
4、视频转图片 cv2
5、音视频合成 subprocess
图片转素描
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/目录下查看")
视频提取音频
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)
视频转图片
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("完成")
图片转视频
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()
音视频合成
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)
以上就是基础的代码内容
单py文件实现
当时完成以上的功能后,发现py文件太多了,导致一次转换需要执行多次才能成功的转出我想要的内容,太过于累赘,于是新的代码就出来了
- 新增目录创建 ,视频转换的时候回有很多的图片、音频、素描图的产生,为了归类;
- 新增循环操作, 用来实现单次执行多次使用;
具体代码
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()
作品信息
抖音:抖音中发布的是素描音视频合成
https://www.douyin.com/user/MS4wLjABAAAANtLRNzfIQBaWgzev17EdTs0X_1JTszXdDCUc657AqvWv9GzGUVleCgwmmQ7OcCwV
微博:超话4Mango中发布的是图片转素描