当前位置: 首页 > news >正文

【Python实现代码视频/视频转字符画/代码风格视频】

该程序改良自GitHub开源项目VideoCharDraw
在源程序CharDraw_thread.py 带压缩和多线程版本字符画的基础上使用Tkinter库添加了图形化的操作,使用户操作体验更方便。
在这里插入图片描述
在这里插入图片描述

什么是视频字符画?

视频转字符画是一种将视频中的每一帧图像转换为由字符组成的图像表示的技术。通过将图像的像素信息映射到特定的字符集合中,可以用字符来近似地表示图像的内容。

在这个过程中,通常会对图像进行灰度化处理,然后根据像素的灰度值选择相应的字符来替代。较暗的像素可能会被映射为一些较密集的字符,而较亮的像素则可能会被映射为较稀疏的字符。

这样处理后的每帧图像看起来就像是由字符组成的画,将这些字符画按顺序组合起来,就可以形成一个视频的字符画版本。这种转换可以用于创造独特的视觉效果,或者在一些情况下,如低带宽环境或特殊的艺术表达中,用于减少视频的数据量或展示视频的基本内容。

视频字符画举例

比较典型的,耳熟能详的比如烂苹果
在这里插入图片描述
小黑子等
在这里插入图片描述

使用Python实现代码转字符画

import cv2
import os
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import threading
import tkinter as tk
from tkinter import filedialog
from tkinter import simpledialogdef select_file_path(): #选择视频路径root = tk.Tk()root.withdraw()  # 隐藏主窗口video_path = filedialog.askopenfilename()  # 选择文件if video_path:print(f"Selected file path: {video_path}")return video_pathelse:print("No file selected.")def get_user_input(): # 线程数,建议CPU线程数-1root = tk.Tk()root.withdraw()  # 隐藏主窗口thread_num = simpledialog.askinteger("输入线程", "请输入一个整数作为线程数:(建议设置为CPU线程数-1)")if thread_num is not None:print(f"User input: {thread_num}")return thread_numelse:print("No input provided.")
video_path = select_file_path()
thread_num = get_user_input()
out_path = "VideoTestOut/"  # 输出目录
huaZhi = 1  # 清晰度,最低1,无上限# -----以下为程序使用变量-----#
video_info = []num = 0info = []
'''
图片转换成字符里面的相关大小,
为元组,第一个是resize的宽高,第二个是图片输出的宽高
'''video = cv2.VideoCapture(video_path)# 定义一个线程安全的队列来存储待处理的图片
image_queue = []# 获取视频信息
def getVideoInfo() -> list:ret = [](major_ver, minor_ver, subminor_ver) = cv2.__version__.split('.')if int(major_ver) < 3:fps = video.get(cv2.cv.CV_CAP_PROP_FPS)else:fps = video.get(cv2.CAP_PROP_FPS)ret.append(fps)  # 视频帧数ret.append(video.read()[1].shape[0])  # 视频高度ret.append(video.read()[1].shape[1])  # 视频宽度return ret# 获取视频所有截图
def outVideoAllCapture():# 判断载入视频是否可以打开ret = video.isOpened()global num# 循环读取视频帧while ret:num = num + 1# 进行单张图片的读取,ret的值为True或者Flase,frame表示读入的图片ret, frame = video.read()if ret:cv2.imwrite(out_path + str(num) + '.jpg', frame)image_queue.append(out_path + str(num) + '.jpg')  # 将图片路径加入队列cv2.waitKey(1)else:break# 单张图片转换成字符画
def imageToChar(filename, number):# 字符列表ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~            <>i!lI;:,\"^`'. ")# 判断图片是否存在if os.path.exists(filename):# 将图片转化为灰度图像,并重设大小img_array = np.array(Image.open(filename).resize(info[0], Image.LANCZOS).convert('L'))  # resize里面 宽, 高 输出宽高/7# 创建新的图片对象img = Image.new('L', info[1], 255)  # 宽, 高draw_object = ImageDraw.Draw(img)# 设置字体font = ImageFont.truetype('consola.ttf', 10, encoding='unic')# 根据灰度值添加对应的字符for j in range(info[0][1]):  # 是resize的高for k in range(info[0][0]):  # 宽x, y = k * 8, j * 8index = int(img_array[j][k] / 4)draw_object.text((x, y), ascii_char[index], font=font, fill=0)# 保存字符图片img.save(out_path + str(number) + "g.jpg", 'JPEG')cv2.imwrite(out_path + str(number) + "g.jpg", cv2.imread(out_path + str(number) + "g.jpg"),[cv2.IMWRITE_JPEG_QUALITY, 2])os.remove(out_path + str(number) + '.jpg')  # 删除原始图片print("已成功把第" + str(number) + "帧转换成字符画")# 工作线程函数
def worker():while True:if image_queue:filename = image_queue.pop(0)number = int(os.path.splitext(os.path.basename(filename))[0])imageToChar(filename, number)else:breakdef mergeImage():print("开始将图片合并成MP4视频")# global numvideoWriter = cv2.VideoWriter(out_path + 'out.mp4', cv2.VideoWriter_fourcc('m', 'p', '4', 'v'), video_info[0],info[1])for i in range(1, num):filename = out_path + str(i) + 'g.jpg'if os.path.exists(filename):img = cv2.imread(filename=filename)cv2.waitKey(100)videoWriter.write(img)print("完成图片合并成MP4视频")def deleteImg():print("开始删除转换图片")global numfor i in range(1, num):os.remove(out_path + str(i) + 'g.jpg')print("删除转换图片完毕")if __name__ == "__main__":if not os.path.exists(out_path):  # 如果没有这个输出目录就创建os.makedirs(out_path)video_info = getVideoInfo()  # 获取视频信息info.append((int(video_info[2] * huaZhi / 8), int(video_info[1] * huaZhi / 8)))  # 添加计算设置数值info.append((int(video_info[2] * huaZhi / 8) * 8, int(video_info[1] * huaZhi / 8) * 8))  # 添加计算设置数值# print(info)outVideoAllCapture()  # 截取视频所有帧threads = []for _ in range(thread_num):  # 创建多个工作线程t = threading.Thread(target=worker)t.start()threads.append(t)for t in threads:  # 等待所有工作线程完成t.join()mergeImage()  # 合并图片成视频deleteImg()  # 删除每一帧的字符画video.release()

代码解析

该程序的主要功能是将视频转换为字符画视频,具体实现步骤如下:

  1. 选择视频路径和线程数
    • 通过select_file_path函数使用tkinterfiledialog模块弹出文件选择对话框,让用户选择视频文件,并返回视频路径。
    • 通过get_user_input函数使用tkintersimpledialog模块弹出输入对话框,让用户输入线程数,并返回线程数。
  2. 设置输出目录和清晰度
    • 定义输出目录out_path为"VideoTestOut/"。
    • 定义清晰度huaZhi为1。
  3. 获取视频信息
    • getVideoInfo函数中,根据cv2的版本获取视频的帧率、高度和宽度信息。
  4. 截取视频所有帧
    • outVideoAllCapture函数中,读取视频帧并保存为图片,同时将图片路径添加到image_queue队列中。
  5. 单张图片转换成字符画
    • imageToChar函数中,对每张图片进行灰度化处理,然后根据灰度值选择相应的字符来表示图像内容,并保存为字符图片。
  6. 工作线程处理
    • 创建多个工作线程,每个线程从image_queue中取出图片路径,调用imageToChar函数进行转换。
  7. 合并图片成视频
    • mergeImage函数中,将转换后的字符图片合并成MP4视频。
  8. 删除转换图片
    • deleteImg函数中,删除转换过程中生成的字符图片。

代码实现原理主要包括以下几个方面:

  1. 视频读取和处理
    • 使用cv2.VideoCapture读取视频,通过循环逐帧读取视频并保存为图片。
    • 对图片进行灰度化和重设大小处理,然后根据灰度值将像素映射为字符,生成字符图片。
  2. 多线程处理
    • 使用线程安全的队列image_queue存储待处理的图片路径。
    • 创建多个线程,每个线程从队列中取出图片路径进行处理,提高转换效率。
  3. 图片合并和视频生成
    • 使用cv2.VideoWriter将字符图片合并成MP4视频。
  4. 文件管理
    • 在输出目录中创建必要的文件夹和文件,保存图片和视频。
    • 删除转换过程中生成的中间文件,如原始图片和字符图片。

其他

输出文件压缩
在函数imageToChar里面的倒数第三行有一个

[cv2.IMWRITE_JPEG_QUALITY, 2]

这个是压缩的格式,后面那个2可以变动,范围是1-100以内
0的话就是死命压缩,不过画质不太好
如果想要看清楚字符的话可以考虑把这个调高一点,但相对应的
输出图片所占硬盘大小也会很高
如果你不想删除输出的图片的话,把倒数第四行那个daleteImg()给他注释掉就行

相关文章:

【Python实现代码视频/视频转字符画/代码风格视频】

该程序改良自GitHub开源项目VideoCharDraw 在源程序CharDraw_thread.py 带压缩和多线程版本字符画的基础上使用Tkinter库添加了图形化的操作&#xff0c;使用户操作体验更方便。 什么是视频字符画&#xff1f; 视频转字符画是一种将视频中的每一帧图像转换为由字符组成的图…...

基于级联深度学习算法的前列腺病灶检测在双参数MRI中的评估| 文献速递-基于深度学习的乳房、前列腺疾病诊断系统

Title 题目 Evaluation of a Cascaded Deep Learning–based Algorithm for Prostate Lesion Detection at Biparametric MRI 基于级联深度学习算法的前列腺病灶检测在双参数MRI中的评估 Background 背景 Multiparametric MRI (mpMRI) improves prostate cancer (PCa) de…...

基于STM32开发的智能门铃系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码控制代码应用场景 家庭门铃系统智能社区门禁管理常见问题及解决方案 常见问题解决方案结论 1. 引言 智能门铃系统结合了传统门铃功能与现代技术&#xff0c;通过摄像头、麦克风、…...

【WebRTC指南】远程视频流

远程视频流使用入门 RTCPeerConnection 连接到远程对等设备后,就可以在它们之间流式传输音频和视频。此时,我们会将从 getUserMedia() 收到的数据流连接到 RTCPeerConnection。媒体流包含至少一个媒体轨道,当我们想将媒体传输到远程对等设备时,它们会分别添加到 RTCPeerCo…...

前端构建URL的几种方法比对,以及函数实现

当我们在前端开发中处理 URL 时&#xff0c;可能会用到字符串拼接、ES6 模板语法 (template literals) 或者使用 new URL() 构造函数。这三者各有优劣&#xff0c;适用于不同的场景。 1. 字符串拼接与 ES6 模板语法 字符串拼接 和 ES6 模板语法 都是将不同的字符串片段组合在…...

场外个股期权如何发出行权指令?

场外期权行权指令也就是平仓指令的意思&#xff0c;一般场外个股期权交易有三种方式开仓和行权平仓指令&#xff0c;分别是市价&#xff0c;限价和半小时询价&#xff0c;跟普通股票的买卖和交易方式类似&#xff0c;唯一区别是手动发出场外个股期权的行权指令&#xff0c;下文…...

AH8681锂电升压3.7升5V升12V 2A可支持QC2.0 3.0

135.3806.7573在探讨AH8681这款专为3.7V升压5V至12V&#xff0c;并具备2A输出能力&#xff0c;同时兼容QC2.0与QC3.0快充协议的升压芯片时&#xff0c;我们不得不深入其技术细节、应用场景、设计优势以及市场定位等多个维度&#xff0c;以全面理解其在现代电子设备中的重要作用…...

那些年我们一起遇到过的奇技淫巧

EVAL长度限制突破技巧 PHP Eval函数参数限制在16个字符的情况下 &#xff0c;如何拿到Webshell&#xff1f; 写一段限制长度在小于17位的字符&#xff0c;拿下webshell <?php highlight_file(__FILE__); $param $_REQUEST[param]; if (strlen($param) < 17 &&am…...

机器学习笔记:编码器与解码器

目录 介绍 组成结构 代码实现 编码器 解码器 合并编码器-解码器 思考 介绍 在机器翻译中&#xff0c;输入的序列与输出的序列经常是长度不相等的序列&#xff0c;此时&#xff0c;像自然语言处理这种直接使用循环神经网络或是门控循环单元的方法就行不通了。因此&#x…...

加密狗创新解决方案助力工业自动化

面临的挑战 早在1991年&#xff0c;COPA-DATA就认识到需要一个既能提供长期保护又能灵活应对的解决方案&#xff0c;以防止软件盗版并确保客户在各种复杂的工业环境下能够顺利使用其产品。这一解决方案不仅要兼容Windows系统&#xff0c;还必须在网络连接受限的情况下&#xff…...

浅谈文件缓冲区和翻译环境

文章目录 1、文件缓冲区2、程序环境A、翻译过程概述B、详解编译和链接a、编译b、链接 1、文件缓冲区 ANSIC 标准采用”文件缓冲系统“处理数据文件&#xff0c;即在文件的读写过程中会使用到文件缓冲区&#xff0c;而文件缓冲区分为输入缓冲区和输出缓冲区。 读写文件 写文件…...

《腾讯NCNN框架的模型转换x86/mips交叉编译推理》详细教程

NCNN的编译运行交叉编译 1.在Ubuntu上编译运行ncnn1&#xff09;编译ncnn x86 linux2&#xff09;测试ncnn x86 linux 2. 模型转换1&#xff09;onnx2&#xff09;pnnx 3.在x86上加载推理模型1)准备工作2)编写C推理代码3)编写Cmakelist编译 4.在MIPS上进行交叉编译推理1&#x…...

关于近期安卓开发书籍阅读观后感

概述 由于笔者是Java转Android&#xff0c;对于安卓相关知识欠缺&#xff0c;故找一些入门和进阶书籍观看。笔者搜到的相关的安卓推荐博客&#xff1a;【Android – 学习】学习资料汇总_android书籍强烈推荐-CSDN博客相对来说比较全面。 阅读历程 笔者先阅读的是郭霖老师的…...

Servlet——个人笔记

Servlet——个人笔记 文章目录 [toc]Servlet简介Servlet命名Servlet由来实现过程 Servlet 相对 CGI 的优势简要说说什么是CGI Servlet 在IDEA中开发流程Servlet注解方式配置WebServlet注解源码WebServlet注解使用 Servlet常见容器Servlet 生命周期简介测试 Servlet 方法init()…...

富格林:戳穿虚假交易保证安全

富格林指出&#xff0c;虚假交易亏损骗局一直以来都是投资者的诟病。不少投资者来到这个赛道的目的铁定是为了安全盈利增值财富&#xff0c;因此如何去杜绝虚假交易便成了当务之急。实际上&#xff0c;有不少投资技巧可以为保障我们的交易安全带来一些庇护。下面富格林就给大家…...

Linux学习——文本处理工具与正则表达式

目录 一&#xff0c;grep 1&#xff0c;grep介绍 2&#xff0c;grep的常用选项 3&#xff0c;grep使用演示 1&#xff0c;基本使用 直接查找字符串&#xff1a; 使用选项 2&#xff0c;使用正则表达式进行匹配 1&#xff0c;正则表达式介绍 2&#xff0c;使用范例 二&…...

大厂进阶四:React源码Fiber架构解析

本文主要内容&#xff1a; 1、React Concurrent 2、React15架构 3、React16架构 4、Fiber架构 5、任务调度循环和fiber构造循环区别 一、React Concurrent React在解决CPU卡顿是会用到React Concurrent的概念&#xff0c;它是React中的一个重要特性和模块&#xff0c;主要的…...

MongoDB的WiredTiger存储引擎

作者&#xff1a;太阳 从MongoDB 3.2 开始&#xff0c;MongoDB实例默认的存储引擎为WiredTiger&#xff0c;WiredTiger存储引擎具体以下几大优点&#xff1a; 文档级并发 将数据持久化到磁盘 快照和checkpoint 数据压缩 本地数据加密 一、文档级别并发 1、WiredTiger使…...

windows 版本Jenkins的Jenkinsfile中共享变量

场景 jenkins部署在windows服务器上的&#xff0c;需要在Jenkinsfile中获取命令执行的结果存入一个变量&#xff0c;然后在后续的执行中使用此变量 一开始想的是定义一个环境变量&#xff0c;如下所示&#xff0c; pipeline {agent anystages {stage(test) {steps {bat for /…...

Android-->产物收集(含apk文件重命名, aab文件重命名)

以前写过修改apk生成路径和文件名的文章, 如下: AS–›Gradle 7.0.0/4.1.0/4.0/3.3/3.0 修改APK生成路径和文件名(附AAR修改方式以及分析过程)_com.android.build.gradle.internal.api.libraryvaria-CSDN博客 这种方法入侵了gradle,破坏了原有的gradle环境, 经常会导致如下问…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...