「ASCII Art」字符画黑人抬棺

文章写于2020.6,迁移博客导致了日期的错误

马上,我就将迎来小学的最后一个六一节日,不管怎么说,我也得整个节目。再加上这次节目是录制形式的,这使得我可以以编程作为节目主体。

稍加思考,我就想到了可以做字符画黑人抬棺。

有关这一项目的信息,可以参考README

README

Dancing_Pallbearers_ASCII

以上为GitHub Repo名称

Play video "Dancing Pallbearers" in ASCII Art.

How To Use

  1. Download original video (.mp4) from Bilibili or other websites.

  2. Put it in the same directory as the source code.

  3. Run Extract_Frames.py. It will generate frame0.jpg, frame1.jpg, etc.

  4. Run Main.py. Windows Terminal is recommended.

Using this source code, can I play other videos?

Of Course, You Can.

It is worth noting that maybe you should change some value in line 23 in Main.py.

Other

This source code is for my Children's day program.

If you're interested in this program, There's a link.

代码分析

接下来,对代码进行简要的介绍。

# Extract_Frames.py
import cv2

vidcap = cv2.VideoCapture('黑人抬棺.mp4')
success, image = vidcap.read()
count = 0
success = True
while success:
    success, image = vidcap.read()
    cv2.imwrite("frame%d.jpg" % count, image)
    if cv2.waitKey(10) == 27:
        break
    count += 1

以上代码,用于输出黑人抬棺视频的每一帧画面,代码技术含量并不高,只要求对cv2库有一定了解。

每帧画面

# Main.py
from PIL import Image
import os

os.system("color 70")
ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "


def transform(image_file):
    image_file = image_file.convert("L")
    char = ""
    for h in range(0, image_file.size[1]):
        for w in range(0, image_file.size[0]):
            gray = image_file.getpixel((w, h))
            char += ascii_char[int((len(ascii_char) * gray) / 256)]
        char += "\n"
    return char


for i in range(0, 1323):
    os.system("cls")
    pic = open(u"frame" + str(i) + ".jpg", "rb")
    pic = Image.open(pic)
    pic = pic.resize((int(pic.size[0] * 0.08), int(pic.size[1] * 0.04)))
    print(transform(pic))

这里是主程序,首先用os.system("color 70")更改终端背景颜色为白色,保证用户看到的字符画视频不是颜色相反的效果。

接下来,定义transform类,用于把图片转为字符画。

image_file = image_file.convert("L")将照片文件转化为了黑白照片,以方便获取灰度值。

    for h in range(0, image_file.size[1]):
        for w in range(0, image_file.size[0]):

嵌套for循环,遍历图片的每一个像素点。

gray = image_file.getpixel((w, h))获取像素点的灰度值。

char += ascii_char[int((len(ascii_char) * gray) / 256)]将灰度值转化为了字符。

这里有必要提一下,在此之前,我以为是要将字符转化为图片,获取灰度值,然后与像素点的灰度值相匹配,其实并没有这么麻烦。我们往前看,在定义ascii_char的时候,ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^'. "这些字符,其实是按照灰度值高到灰度值低的顺序排列的,那么根据像素灰度值就可以直接计算字符在字符串中的位置。

接下来,遍历每一帧画面,进行显示。

os.system("cls")为清屏指令,为显示下一帧画面做准备。

pic = pic.resize((int(pic.size[0] * 0.08), int(pic.size[1] * 0.04)))这里对图片进行了缩放操作,原因有两个:

  1. 肉眼无法分辨的像素点被放大到了字符大小,为了适应屏幕,需要缩小

  2. 正方形的像素点变为了长方形,所以会将宽度缩小到长的一般,大致能使图像显示正常

那么,全部程序就完工了,如果需要将图片转化为字符画,可以直接调用transform方法,当然,要按照程序for循环中的方式打开图片,并不是传递给函数图片的名称。

此程序还有一些缺陷,最主要的是,将图片转化为字符画的过程需要一定时间,这使得在播放过程中会有空白画面的存在,我目前想到的解决方式,就是把os.system("cls")放到方法的return前面,但是为了保证程序的模块化和方便调用,并没有使用这一方法。

最终效果可以前往README中的链接查看。

posted @ 2020-10-03 19:44  Liuxizai  阅读(403)  评论(0编辑  收藏  举报