首页 > 其他分享 >字符视频转换器--不保留中间的转换过程

字符视频转换器--不保留中间的转换过程

时间:2023-07-22 16:24:45浏览次数:25  
标签:字符 -- frame height width video path 转换器 dir

# -*- coding: utf-8 -*-
import os
import threading
import time
import tkinter
from tkinter import TOP, LEFT, RIGHT, messagebox, filedialog, DISABLED, NORMAL
from tkinter.ttk import Progressbar

import cv2
import filetype
import numpy
from PIL import Image, ImageDraw, ImageFont

ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")  # 所用字符列表


# 将256灰度映射到70个字符上
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) / length
    return ascii_char[int(gray / unit)]


def frame2char(frame):
    im = Image.fromarray(frame)
    origin_img_width = im.width
    origin_img_height = im.height
    new_img_width = int(im.width / 6)
    new_img_height = int(im.height / 15)
    im_txt = Image.new("RGB", (origin_img_width, origin_img_height), (255, 255, 255))
    im = im.resize((new_img_width, new_img_height), Image.NEAREST)
    txt = ""
    colors = []
    for i in range(new_img_height):
        for j in range(new_img_width):
            pixel = im.getpixel((j, i))
            colors.append((pixel[0], pixel[1], pixel[2]))
            if len(pixel) == 4:
                txt += get_char(pixel[0], pixel[1], pixel[2], pixel[3])
            else:
                txt += get_char(pixel[0], pixel[1], pixel[2])
        txt += '\n'
        colors.append((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
    for i in range(len(txt)):
        if txt[i] == '\n':
            x += font_h
            y = -font_w
        dr.text((y, x), txt[i], colors[i])
        y += font_w
    return im_txt


def get_image_size(video_path):
    frame_count, frame_width, frame_height = 0, 0, 0
    vc = cv2.VideoCapture(video_path)
    ret = vc.isOpened()
    while ret:
        ret, frame = vc.read()
        if ret:
            frame_count = int(vc.get(cv2.CAP_PROP_FRAME_COUNT))
            frame_height = vc.get(cv2.CAP_PROP_FRAME_HEIGHT)
            frame_width = vc.get(cv2.CAP_PROP_FRAME_WIDTH)
            break
    vc.release()
    time.sleep(1)
    return frame_count, frame_width, frame_height


def video2char_video(video_path, char_video_dir):
    frame_count, frame_width, frame_height = get_image_size(video_path)
    fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
    video_writer = cv2.VideoWriter(f"{char_video_dir}/output.mp4", fourcc, 30.0,
                                   (int(frame_width), int(frame_height)))
    vc = cv2.VideoCapture(video_path)
    c = 0
    ret = vc.isOpened()
    while ret:
        c = c + 1
        ret, frame = vc.read()
        if ret:
            im_txt = frame2char(frame)
            img = cv2.cvtColor(numpy.array(im_txt), cv2.COLOR_RGB2BGR)
            video_writer.write(img)
            schedule = c / float(frame_count) if frame_count != 0 else 1.00
            progress_label["text"] = f"转换进度:{schedule:.2%}"
            progressbar['value'] = schedule * 100
            root.update()
        else:
            break
    # 视频释放
    vc.release()
    video_writer.release()
    label["text"] = "转换完成"
    choose_file_button['state'] = NORMAL
    convert_button['state'] = NORMAL
    progress_label.pack_forget()
    progressbar.pack_forget()


def check_or_create_dir(dir_path):
    if os.path.exists(dir_path):
        files = os.listdir(dir_path)
        if files:
            return False
        else:
            return True
    else:
        os.makedirs(dir_path, exist_ok=True)
        return True


def choose_video_file_path():
    global video_path
    video_path = filedialog.askopenfilename()


def convert_video():
    if not video_path:
        messagebox.showerror('错误', '没有选择有效的路径,请重新选择')
    else:
        if os.path.isfile(video_path):
            kind = filetype.guess(video_path)
            if kind:
                mime = kind.mime
                if mime:
                    if mime.startswith("video"):
                        video_dir = os.path.dirname(os.path.abspath(video_path))
                        output_dir = f"{video_dir}/output"
                        flag = check_or_create_dir(output_dir)
                        if not flag:
                            messagebox.showerror('错误', f'{output_dir} 不是空的,请删除或者清空此目录')
                        else:
                            choose_file_button['state'] = DISABLED
                            convert_button['state'] = DISABLED
                            label["text"] = "视频正在转换,请稍等!!!"
                            progress_label.pack(side=LEFT)
                            progressbar.pack(side=RIGHT)
                            t = threading.Thread(target=video2char_video, args=(video_path, output_dir,))
                            t.setDaemon(True)
                            t.start()
                    else:
                        messagebox.showerror('错误', f'{video_path} 不是视频,请重新选择')
                else:
                    messagebox.showerror('错误', f'{video_path} 不是视频,请重新选择')
            else:
                messagebox.showerror('错误', f'{video_path} 不是视频,请重新选择')
        else:
            messagebox.showerror('错误', '没有选择有效的路径,请重新选择')


if __name__ == "__main__":
    root = tkinter.Tk()
    video_path = None
    label = tkinter.Label(root, text="欢迎使用海军专属的字符视频转换器")
    label.pack(side=TOP)
    progress_label = tkinter.Label(root, text="转换进度:0.0%")
    progress_label.pack_forget()
    progressbar = Progressbar(root)
    progressbar["value"] = 0
    progressbar["maximum"] = 100
    progressbar.pack_forget()
    choose_file_button = tkinter.Button(root, text="选择文件", command=choose_video_file_path)
    choose_file_button.pack(side=LEFT)
    convert_button = tkinter.Button(root, text="开始转换", command=convert_video)
    convert_button.pack(side=RIGHT)
    screen_width, screen_height = root.maxsize()  # 获取屏幕最大长宽
    w = int((screen_width - 240) / 2)
    h = int((screen_height - 480) / 2)
    root.geometry(f'+{w}+{h}')
    root.resizable(width=False, height=False)
    root.title('字符视频转换器')
    root.mainloop()

  

标签:字符,--,frame,height,width,video,path,转换器,dir
From: https://www.cnblogs.com/navysummer/p/17573567.html

相关文章

  • 字体属性
    字体font-family   font-weight100-300无反应细的 常规 400-500normal600-900加粗bold font-styleitalicoblique文字倾斜 text-decoration none添加修饰 text-indent首航缩进  letter-spacing字间距  text-transformuppercase 继......
  • 浮动的问题
    浮动是有方向性的后面一个浮动跟着前面一个浮动浮动是脱离文档流半层的 清除浮动:清除浮动带来的影响(解决高度塌陷的问题)父元素加宽度父元素加上overflow:hidden; 在浮动元素后面加一个空的divstyle="clear:both;"clear有这些属性leftrightbothnone   浮动......
  • 常见bug
    1.块级标签支持所有的css属性2.行内块有一些属性不支持----写了也没用不支持宽高 marginpadding等属性显示有问题3.margin-top的传递问题4.行内标签什么时候用----文字左右排列的时候使用3.浮动导致父元素高度塌陷(直接给父元素高度,也可以写overflow:hidden;)......
  • 背景属性
    background-image:url()通常情况下会平铺 background-repeat:no-reqeat 平铺分为x和ybackground-position:-20px-50px;background-position:50% 50%;background-position:centercenter;background-position:10px;第二个值缺损表示上下居中background-position:left;backgrou......
  • MySQL的执行计划详解(Explain)
    MySQL的执行计划详解(Explain)1、MySQL执行计划的定义在MySQL中可以通过explain关键字模拟优化器执行SQL语句,从而知道MySQL是如何处理SQL语句的。2、MySQL整个查询的过程•客户端向MySQL服务器发送一条查询请求•服务器首先检查查询缓存,如果命中缓存,则立刻返回存储......
  • 元素之间的相互转换
    1.dispaly:inline-block;不确定宽度 在父元素加上text-align:center;分页但是中间有间距解决方法 中间不换行加上注释字间距设置为0然后在li里面加上(解决代码换行产生的间距)   2.图片中空隙可以设置两张图片的文字大小取消换行间隙font-size:0......
  • 利用微搭低代码平台快速搭建问卷系统
    可爱鲸官网:https://keaijing.com.cn/项目简介利用微搭低代码平台搭建一个问卷小程序,主要实现微信支付和消息推送功能。微信支付利用微搭自带的接口可以快速实现。消息推送分为两种,利用小程序自带的服务通知和自己利用微搭的云函数来实现公众号推送。微信支付首先可以新建......
  • MQTT学习笔记
    客户端:mqttxforwindows,并提供基于互联网的mqtt服务,不用再搭建 MQTT的C语言编程:下载paho的包,在github上,有基于Linux的release版本,下载后,将其解压到任意目录,比如:/opt/mqtt目录结构如下: 安装完毕后,进行配置(如果不配置,动态链接库无法找到)设置动态链接库的搜索路径export......
  • 元素类型
    1.块级元素 独占一行 可以做容器----盒子 2.内联元素 左右排列  不是盒子----子哦为辅助标签来使用 有很多属性显示不完整  3.行内块级元素  imginput  可以支持宽高 左右排列 也叫行内块级元素都有相应的bug 行内块和行内元素换行都会与有空......
  • 今日任务
    1.STL标准模板库https://zzk.cnblogs.com/s/blogpost?w=STL%E6%A0%87%E5%87%86%E6%A8%A1%E6%9D%BF%E5%BA%932.BFS宽度优先搜索https://zzk.cnblogs.com/s/blogpost?w=BFS%E5%AE%BD%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2http://ybt.ssoier.cn:8088/index.php3.结构体......