以前就在抖音上看到过字符视频,直到昨天才突然想自己动手做一个,然后就利用各种博客,自己总结 兼 借鉴,终于完成了字符视频的制作

一、思路:
众所周知,视频是一帧一帧的图片组成的,所以我想的就是将抖音的视频先解析成好多帧图片,然后对图片进行操作,最后再把图片合成视频

二、遇到的问题:

  1. 其中我遇到的最大问题就是 pycharm 的 BUG,我从来没有想过 pycharm 会有 BUG,所以在我安装 opencv-python 库的时候,我一直以为是我的安装错误,可最后翻阅了超多博客后,才下定结论是 pycharm 的 BUG,并且代码验证确实可以运行,所以石锤了。

    错误显示:

    Cannot find reference 'waitKey' in '__init__.py' less... (Ctrl+F1)
    Inspection info: This inspection detects names that should resolve but don't. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Top-level and class-level items are supported better than instance items.
    

    这个错误可以忽略,因为这是 pycharm 本身的 BUG,不影响代码运行

  2. 视频格式错误
    从抖音上下载的视频格式显示是 .Mp4 ,可是并不能用,所以需要转换编码,网上有很多免费的在线转格式的网站。

三、具体操作步骤

  1. 转换视频格式
    在抖音上下载的视频是无法直接转换的,所以需要将视频转码:->免费转码网站<-,转成原来的格式,即还是 .Mp4 就足够了
  2. 首先是要将视频中的帧提取出来:
    部分代码如下:

    while ret:# 进行单张图片的读取,ret的值为True或者Flase,frame表示读入的图片ret, frame = vc.read()if ret:# 存储为图像cv2.imwrite(folder_path + str(c) + '.jpg', frame)# 输出图像名称#print(folder_path + str(c) + '.jpg')c = c + 1# 在一个给定的时间内(单位ms)等待用户按键触发,1mscv2.waitKey(1)else:break
    
  3. 其次就是单独处理每个图片(也是最复杂的)
    部分代码如下:

    for j in range(len(txts)):for i in range(len(txts[j])):if isgray:draw_handle.text((i*block_x, j*block_y), txts[j][i], (50, 50, 50))else:draw_handle.text((i*block_x, j*block_y), txts[j][i], colors[j][i])
    

    整体思路:读出旧图片,新建一个Image对象,基于旧图片,构造新图片
    具体思路:采用多线程来读出旧图片(因为单线程实在太慢了),自定义字体格式,获取此格式的一个字符的长宽,获取旧图片的长宽,新建一个图片对象,新图片的长宽为:(旧图片长宽 / 字体格式一个字符的长宽),相当于对图片进行了缩放,将每一个字体格式的字符,缩为新图片的一个像素,在扫描就图片的时候,记录下 RGB,并计算出字符,随后填入新图片。

  4. 最后合成视频
    部分代码如下:

    for i in range(1, 1000):filename = folder_path_char + str(i) + '.jpg'# 判断图片是否存在if os.path.exists(filename):img = cv2.imread(filename=filename)# 在一个给定的时间内(单位ms)等待用户按键触发,100mscv2.waitKey(100)# 将图片写入视频中videoWriter.write(img)# print(str(i) + '.jpg' + ' done!')
    
  5. 提取原视频 Mp3
    这里有一个网站:->Mp3提取网站<-,可以提取出视频的 Mp3
  6. 合成
    我用的是一个视频编辑软件,加入了音频 Mp3,并且压缩了视频(因为合成的视频太大了,抖音 2 M 的视频,合成后变成了 200 M)

四、详细代码

from PIL import Image, ImageDraw, ImageFont
import cv2
import os
import threading
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")#在当前目录下新建文件夹
folder_path = r"D:\Python_workspace\char_video_sources\pictures\\"#每帧
folder_path_char =r"D:\Python_workspace\char_video_sources\char_pitcures\\"#彩色字符帧width=None
height=None
fps=None
count=None
def getVideo(url):# 进行视频的载入vc = cv2.VideoCapture(url)c = 0# 判断载入的视频是否可以打开ret = vc.isOpened()"""获取视频参数"""global fpsfps=vc.get(cv2.CAP_PROP_FPS)#获取视频帧速global countcount=vc.get(cv2.CAP_PROP_FRAME_COUNT)#获取视频帧数global widthglobal heightwidth =int(vc.get(cv2.CAP_PROP_FRAME_WIDTH))  # 获取长宽height =int(vc.get(cv2.CAP_PROP_FRAME_HEIGHT))"""end"""# 循环读取视频帧while ret:# 进行单张图片的读取,ret的值为True或者Flase,frame表示读入的图片ret, frame = vc.read()if ret:# 存储为图像cv2.imwrite(folder_path + str(c) + '.jpg', frame)# 输出图像名称#print(folder_path + str(c) + '.jpg')c = c + 1# 在一个给定的时间内(单位ms)等待用户按键触发,1mscv2.waitKey(1)else:breakvc.release()def get_char(r,g,b,alpha = 256):#获取对应的字符if alpha == 0:return ' 'length = len(ascii_char)gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)unit = (256.0 + 1)/lengthreturn ascii_char[int(gray/unit)]def severalThreadings(isgray=False):#多线程处理灰度图像lines=5eachPice=int(count/lines)#每个线程所需处理帧数threads=[]for line in range(lines):#对于一片进行处理,然后计算扩展到begin=line*eachPiceend=(line+1)*eachPiceif line==lines-1:#如果是最后一个线程,则其工作为收尾工作,将图片进行到最后end=int(count)thread = threading.Thread(target=getCharPitcure, args=(begin,end,isgray))threads.append(thread)thread.setDaemon(True)thread.start()for item in threads:item.join()def getCharPitcure(begin=0,end=count,isgray=False):#传入是否生成灰色,默认为否for op in range(begin, end):#print("这是第{}个".format(op))img = folder_path + str(op) + '.jpg'# print(img)if os.path.exists(img):im = Image.open(img).convert('RGB') # 注意,此处需要先将图片转换为RGB模式# 设定处理后的字符画大小,需要为整型raw_width = int(im.width)raw_height = int(im.height)# 获取设定的字体的尺寸,ImageFont默认的尺寸大小为6x11,其他字体会有所不同# 此处使用的字体为truetype字体,大小为10pxfont = ImageFont.truetype('consola.ttf', 10, encoding='unic')font_x, font_y = font.getsize(' ')# 确定单元的大小block_x = int(font_x)block_y = int(font_y)# 确定长宽各有几个单元w = int(raw_width/block_x)h = int(raw_height/block_y)# 将每个单元缩小为一个像素im = im.resize((w, h), Image.NEAREST)# txts和colors分别存储对应块的ASCII字符和RGB值txts = []colors = []for i in range(h):#遍历行line = ''lineColor = []for j in range(w):#遍历列pixel = im.getpixel((j, i))lineColor.append((pixel[0], pixel[1], pixel[2]))line += get_char(pixel[0], pixel[1], pixel[2])txts.append(line)colors.append(lineColor)# 创建新画布im_txt = Image.new("RGB", (raw_width, raw_height), (255, 255, 255))# 创建ImageDraw对象以写入ASCIIdraw_handle = ImageDraw.Draw(im_txt)for j in range(len(txts)):for i in range(len(txts[j])):if isgray:draw_handle.text((i*block_x, j*block_y), txts[j][i], (50, 50, 50))else:draw_handle.text((i*block_x, j*block_y), txts[j][i], colors[j][i])name = folder_path_char + str(op) + '.jpg'# print(name)im_txt.save(name, 'JPEG')def createVideo(url):# 设置视频编码器,这里使用使用MJPG编码器fourcc = cv2.VideoWriter_fourcc(*'MJPG')# 输出视频参数设置,包含视频文件名、编码器、帧率、视频宽高(此处参数需和字符图片大小一致)videoWriter = cv2.VideoWriter(url, fourcc, fps, (width,height))for i in range(1, 1000):filename = folder_path_char + str(i) + '.jpg'# 判断图片是否存在if os.path.exists(filename):img = cv2.imread(filename=filename)# 在一个给定的时间内(单位ms)等待用户按键触发,100mscv2.waitKey(100)# 将图片写入视频中videoWriter.write(img)# print(str(i) + '.jpg' + ' done!')# 视频释放videoWriter.release()if __name__ == '__main__':"""使用教程:将抖音视频转换编码,抖音的编码不能直接使用,转成 mp4 格式 -》https://app.xunjiepdf.com/video传入视频地址解析出无声音版的视频提取视频里的 mp3 -》http://audio-extractor.net/cn/用视频编辑器将视频压缩并配乐完成"""print("BEGIN")"""检查文件夹路径在不在"""if not os.path.exists(folder_path):os.mkdir(folder_path)if not os.path.exists(folder_path_char):os.mkdir(folder_path_char)"""end"""url=r'D:\Python_workspace\char_video_sources\dance.mp4'getVideo(url)severalThreadings()#多线程处理图片# getCharPitcure()#单线程处理,已设置默认值为(0,count,False)createVideo(url.replace(".mp4",".avi"))"""删除对应文件夹"""os.system("rd /s /q "+folder_path)os.system("rd /s /q "+folder_path_char)"""END"""print("END")

五、参考博客

  1. https://blog.csdn.net/XZQ121963/article/details/90045996

  2. https://blog.csdn.net/qq_41841569/article/details/84940294

  3. https://blog.csdn.net/weixin_41010198/article/details/88535234

    综上:三篇博客中,综合了第一二篇的优点,我自己又加入了多线程,并且视频长宽完全是基于原视频的,所以在性能和功能上都优于前者,第三篇主要是参考了 cv2 的 get() 函数的属性表

六、运行结果(直接上视频截图,哈,因为需要看出效果,所以抖音上找的一个跳舞的小姐姐,人长得挺漂亮,大家感兴趣可以关注一下,还有用人家图片来写博客也挺不好意思的。)

【Python 字符视频】Python 实现将抖音视频转换成字符视频相关推荐

  1. python多线程下载编程软件_python抖音多线程下载无水印视频

    [Python] 纯文本查看 复制代码import re import requests from concurrent import futures import time headers = {' ...

  2. PR2018模板|手机竖屏图文视频制作剪辑素材/抖音,快手等短视频创作模板

    这是一个很棒的手机竖屏图文视频制作剪辑素材PR模板.可以使用此模板制作一个简约的视频作品. PR2018 | 1080×1920 (Vertical) | 306.08KB | 无需插件

  3. 将字符转换成数字(atoi),将数字转换成字符(itoa)

    目录 一.将字符转换为数字. 二.将数字转换成字符. 一.将字符转换为数字. (首先字符必须是"0" -"9",然后转换成十进制的数字) 比如将"12 ...

  4. 怎么把avi文件转换成mp4视频格式,4个高能方法

    怎么把avi文件转换成mp4视频格式? 当您下载到avi格式的视频文件时,您可能会选择将其转换为MP4格式的文件. avi是一种由微软开发的多媒体容器格式,尽管现在已经被认为是老旧的技术,但由于其简单 ...

  5. python爬app视频_python爬取抖音APP视频教程

    本文讲述爬取抖音APP视频数据(本文未完,后面还有很多地方优化总结) 公众号回复:抖音 即可获取源码 1.APP抓包教程,需要用到fiddler fiddler配置和使用查看>>王者荣耀盒 ...

  6. python批量删缩进_鬼畜小姐姐+野狼disco,十分钟教你如何用Python剪辑一个牛逼的抖音小视频?...

    鬼畜小姐姐+野狼disco,十分钟教你如何用Python剪辑一个牛逼的抖音小视频? 前言 半个月前,后台有个小伙伴问我,如何将视频中的音频提取出来,并且将声音转成文字写入到 word 中,正好接下来的 ...

  7. python音视频开发_Python音视频开发:消除抖音短视频Logo的图形化工具实现

    一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现消除视频Logo的四种方法,并提供了详细的 ...

  8. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  9. Python音视频开发:消除抖音短视频Logo的图形化工具实现

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...

最新文章

  1. Redis缓存失效策略思考
  2. JavaEE基础(十四) /正则
  3. SpringOne 2017:与Pivotal聊大会、Spring、Reactor、WebFlux及其他
  4. yield return关键字怎么使用?
  5. 邮箱不可用 550 User has no permission
  6. android面试经典,Android经典面试题集锦(一)
  7. python机器学习系列教程——深度学习框架比较TensorFlow、Theano、Caffe、SciKit-learn、Keras
  8. 线索二叉树(Binary Thread Tree)
  9. asp获取用户坐标,通过微信公众号的js-sdk功能实现获取用户地址坐标
  10. Excel技巧之插入图表
  11. 三星海外远程真机调试使用教程
  12. 流浪地球2真实成本多少?怎么参与?找谁参与?安全可靠吗?
  13. PHP 的__call()
  14. word中段落里面的选项“如果定义了文档网格,则对齐到网格”起什么作用?
  15. hdu 2276【Kiki Little Kiki 2】
  16. 计算机网络的五层模型和七层模型
  17. Apache Flink介绍、架构、原理以及实现
  18. 【PS2019CC】工具栏找不到某工具怎么办/自定义工具栏的步骤
  19. 最高效的2FA 工具 Authy
  20. 融易宝项目管理平台前台搭建

热门文章

  1. 阿里云oss对象存储的使用
  2. 【Java】绘图入门和机制,绘图方法演示(绘制坦克)
  3. 没有大招的火山引擎,拿下70%大模型玩家
  4. Python中如何计算时间差
  5. 【JavaScript】预解析
  6. Oracle RAC集群安装,从零开始
  7. win7如何去除计算机左边的,win7系统删除资源管理器左侧的家庭组图标方法图解...
  8. Xiuno 开发手册正式发布。
  9. R 和 Rstudio 在线更新
  10. Mac设置命令行代理