12

Python生成字符视频

 4 years ago
source link: https://blog.csdn.net/ZackSock/article/details/116863387
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Python生成字符视频

在之前也写过生成字符视频的文章,但是使用的是命令行窗口输出,效果不是很好,而且存在卡顿的情况。于是我打算直接生成一个mp4的字符视频。大致思路和之前一样:Python20行代码实现视频字符化

下面来看一个效果图:

在这里插入图片描述

二、OpenCV的操作图像

我们先来看一些基本操作。首先我们需要安装OpenCV,执行下面语句:

pip install opencv-python

之后就可以使用了。

2.1、读取和显示

我们直接看代码:

import cv2
# 读取图片
img = cv2.imread("1.jpg")
# 显示图片
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

其中waitKey是等待输入的函数,因为imshow之后显示一瞬间,所以我们需要调用它。而destroyAllWindows是释放窗口。

2.2、灰度转换

灰度转换就是将图片转换成黑白图片(灰色),这样可以方便我们处理像素。代码如下:

import cv2
img = cv2.imread("1.jpg")
# 灰度转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

我们还可以直接以灰度形式读入:

import cv2
# 以灰度形式读入
img = cv2.imread("1.jpg", 0)

2.4、获取图片尺寸并修改尺寸

我们直接看代码:

import cv2
img = cv2.imread("1.jpg", 0)
# 获取图片的高宽
h, w = img.shape
# 缩放图片
res = cv2.resize(img, (w//2, h//2))

因为img的shape属性是一个元组,所以我们可以直接自动拆包。

然后调用cv2.resize函数,第一个参数传入图片,第二个参数传入修改后的尺寸。

2.5、绘制文字

绘制文字我们需要调用cv2.putText函数,代码如下:

import cv2
img = cv2.imread('1.jpg')
# 绘制文字
cv2.putText(
    # 背绘制的图片
    img, 
    # 要绘制的文字
    'Hello',
    # 文字左下角的坐标
    (100, 500),
    # 字体
    cv2.FONT_HERSHEY_SIMPLEX,
    # 字体大小缩放
    20, 
    # 文字颜色
    (0, 0, 0),
    # 文字粗细
    10
)

我们只需要注意这些参数就好了。

2.6、读取视频

读取视频的操作一般是通用的,代码如下:

import cv2
# 读取视频
cap = cv2.VideoCapture('1.mp4')
# 获取视频的帧率
fps = cap.get(cv2.CAP_PROP_FPS)
# 循环读取图片的每一帧
while True:
    # 读取下一帧
    ret, frame = cap.read()
    if not ret:
        break
    else:
        pass
cap.release()

上面我们获取的视频的帧,在写入视频的时候我们需要用到。

2.7、写入视频

写入视频的操作也是常规代码:

import cv2
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
writer = cv2.VideoWriter('11.mp4', fourcc, fps, (w, h))
# 写入视频
writer.write(frame)
***
write.release()

有了这些知识,我们就可以开始下一步工作了。

三、像素映射成字符

对于只有一个通道的图片,我们可以把它当成一个矩形,这个矩形最小单位就是一个像素。而字符化的过程就是用字符替代像素点的过程。所以我们要遍历图像的每个像素点,但是我们应该用什么字符取代呢?

我们颜色有一个参照表,而opencv将这个参数表切割成256份,代表不同的程度,我们也可以做一个参照表,不过表中的内容不是颜色,而是字符。

在这里插入图片描述

上图为颜色表,我们可以使颜色表和字符表建立映射关系。假如字符表如下:

mqpka89045321@#$%^&*()_=||||}

我们可以得到下列公式:

在这里插入图片描述

经过变换可以求得相应颜色对应字符表中的字符:

在这里插入图片描述

这个公式不理解也没关系,只需要会用即可。下面就是我们像素转字符的代码:

def pixel2char(pixel):
    char_list = "@#$%&erytuioplkszxcv=+---.     "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]

这个字符表是可以自己定义的。

四、生成字符图片

现在我们只需要将像素逐个转换成字符就好了,代码如下:

def get_char_img(img, scale=4, font_size=5):
    # 调整图片大小
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # 创建一张图片用来填充字符
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # 遍历图片像素
    for y in range(0, re_im.shape[0]):
        for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0, 0, 0))
    return char_img

这里我们使用了一个np.ones函数,它的作用我们理解为生成一个黑色图片。

生成的尺寸我们先除了scale,如何再乘font_size。scale是原图的缩小程度,因为像素有很多,所以我们需要先把图片缩小。而为了让我们的字体显示更清楚,我们需要把生成的字符图片放大。

因此需要注意,虽然我们生成的图片看起来单调,但是当font_size设置为5时,得到的图片已经比较大了。因此当你生成长时间的视频时,会花费比较多的时间,生成的视频也比较大。

我们来测试一下上面的函数:

import cv2
import numpy as np


def pixel2char(pixel):
    char_list = "@#$%&erytuioplkszxcv=+---.     "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]


def get_char_img(img, scale=4, font_size=5):
    # 调整图片大小
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # 创建一张图片用来填充字符
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # 遍历图片像素
    for y in range(0, re_im.shape[0]):
        for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0, 0, 0))
    return char_img


if __name__ == '__main__':
    img = cv2.imread('dl.jpg', 0)
    res = get_char_img(img)
    cv2.imwrite('d.jpg', res)

效果如下:

在这里插入图片描述

可以看到效果还是很不错的。

五、生成字符视频

有了上面的代码,我们就可以对整个视频进行转换了。将视频转换成字符视频的代码如下:

def generate(input_video, output_video):
    # 1、读取视频
    cap = cv2.VideoCapture(input_video)

    # 2、获取视频帧率
    fps = cap.get(cv2.CAP_PROP_FPS)

    # 读取第一帧,获取转换成字符后的图片的尺寸
    ret, frame = cap.read()
    char_img = get_char_img(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), 4)

    # 创建一个VideoWriter,用于保存视频
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_video, fourcc, fps, (char_img.shape[1], char_img.shape[0]))
    while ret:
        # 读取视频的当前帧,如果没有则跳出循环
        ret, frame = cap.read()
        if not ret:
            break
        # 将当前帧转换成字符图
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        char_img = get_char_img(gray, 4)

        # 转换成BGR模式,便于写入视频
        char_img = cv2.cvtColor(char_img, cv2.COLOR_GRAY2BGR)
        writer.write(char_img)
    writer.release()

下面是卡卡西经典战役的字符视频片段:

在这里插入图片描述

完整代码如下:

import cv2
import numpy as np


def pixel2char(pixel):
    char_list = "@#$%&erytuioplkszxcv=+---.     "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]


def get_char_img(img, scale=4, font_size=5):
    # 调整图片大小
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # 创建一张图片用来填充字符
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # 遍历图片像素
    for y in range(0, re_im.shape[0]):
        for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0, 0, 0))
    return char_img


def generate(input_video, output_video):
    # 1、读取视频
    cap = cv2.VideoCapture(input_video)

    # 2、获取视频帧率
    fps = cap.get(cv2.CAP_PROP_FPS)

    # 读取第一帧,获取转换成字符后的图片的尺寸
    ret, frame = cap.read()
    char_img = get_char_img(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), 4)

    # 创建一个VideoWriter,用于保存视频
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_video, fourcc, fps, (char_img.shape[1], char_img.shape[0]))
    while ret:
        # 读取视频的当前帧,如果没有则跳出循环
        ret, frame = cap.read()
        if not ret:
            break
        # 将当前帧转换成字符图
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        char_img = get_char_img(gray, 4)

        # 转换成BGR模式,便于写入视频
        char_img = cv2.cvtColor(char_img, cv2.COLOR_GRAY2BGR)
        writer.write(char_img)
    writer.release()


if __name__ == '__main__':
    generate('in.mp4', 'out.mp4')

我们只需要修改generate的参数就好了。完整效果视频如下:

Python生成字符视频-卡卡西VS带土


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK