python图片转字符画:如何将图像转换为ASCII图像?

2021年11月7日15:26:19 发表评论 985 次浏览

ASCII 艺术简介 

python如何将图片转为字符画?ASCII 艺术是一种图形设计技术,它使用计算机进行演示,由 1963 年 ASCII 标准定义的 95 个可打印字符(总共 128 个)和具有专有扩展字符(超过 128 个字符)的 ASCII 兼容字符集拼凑而成的图片组成。标准 7 位 ASCII 字符)。该术语也广泛用于泛指基于文本的视觉艺术。python图片转字符画可以使用任何文本编辑器创建,并且通常与自由格式语言一起使用。大多数 ASCII 艺术示例都需要固定宽度的字体(非比例字体,如传统打字机上的字体),例如 Courier 进行演示。已知最古老的 ASCII 艺术示例是计算机艺术先驱肯尼斯·诺尔顿 (Kenneth Knowlton) 于 1966 年左右创作的作品,当时他在贝尔实验室工作。1966 年 Ken Knowlton 和 Leon Harmon 的“Studies in Perception I”展示了他们早期 ASCII 艺术的一些例子。ASCII 艺术的发明在很大程度上是因为早期的打印机通常缺乏图形能力,因此使用字符代替图形标记。此外,为了标记来自不同用户的不同打印作业之间的分区,批量打印机通常使用 ASCII 艺术来打印大型横幅,使分区更容易被发现,以便计算机操作员或文员更容易区分结果。当无法嵌入图像时,早期的电子邮件中也使用了 ASCII 艺术。你可以找到有关它们的更多信息。[来源 :为了标记来自不同用户的不同打印作业之间的分区,批量打印机通常使用 ASCII 艺术来打印大横幅,使分区更容易被发现,以便计算机操作员或文员更容易区分结果。当无法嵌入图像时,早期的电子邮件中也使用了 ASCII 艺术。你可以找到有关它们的更多信息。[来源 :为了标记来自不同用户的不同打印作业之间的分区,批量打印机通常使用 ASCII 艺术来打印大横幅,使分区更容易被发现,以便计算机操作员或文员更容易区分结果。当无法嵌入图像时,早期的电子邮件中也使用了 ASCII 艺术。你可以找到有关它们的更多信息。[来源 :维基

如何将图像转换为ASCII图像 

以下是程序生成 ASCII
图像的步骤 : 

  • 将输入图像转换为灰度。
  • 将图像拆分为 M×N 块。
  • 更正 M(行数)以匹配图像和字体纵横比。
  • 计算每个图像块的平均亮度,然后为每个块查找合适的 ASCII 字符。
  • 组合成行的 ASCII 字符串并将它们打印到文件中以形成最终图像。

要求  

你将在 python 中执行此程序,我们将使用Pillow,它是 Python 成像库,用于读取图像、访问其底层数据、创建和修改它们以及科学模块Numpy来计算平均值。

python如何将图片转为字符画代码 
你将首先定义用于生成 ASCII 艺术的灰度级别。然后,你将了解如何将图像拆分为图块以及如何计算这些图块的平均亮度。接下来,你将使用 ASCII 字符替换图块以生成最终输出。最后,你将为程序设置命令行解析,以允许用户指定输出大小、输出文件名等。
 

python图像转换ASCII图像定义灰度级别和网格  

作为创建程序的第一步,定义用于将亮度值转换为 ASCII 字符的两个灰度级别作为全局值。 

>>>gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^`". "    #70 levels of gray
>>>gscale2 = "@%#*+=-:. "         #10 levels of gray

u 处的值 gscale1 是 70 级灰度斜坡,v 处的 gscale2 是更简单的 10 级灰度斜坡。这两个值都存储为字符串,字符范围从最暗到最亮。
现在你有了灰度渐变,你可以设置图像。以下代码打开图像并将其拆分为网格:

    # open image and convert to grayscale
>>>    image = Image.open(fileName).convert('L')
    # store dimensions
>>>    W, H = image.size[0], image.size[1]
    # compute width of tile
>>>    w = W/cols
    # compute tile height based on aspect ratio and scale
>>>    h = w/scale
    # compute number of rows
>>>    rows = int(H/h)

python图片转字符画:计算平均亮度 
接下来,你计算灰度图像中平铺的平均亮度。函数 getAverageL() 完成这项工作。

#Given PIL Image, return average value of grayscale value
>>>def getAverageL(image):
    # get image as numpy array
...    im = np.array(image)
    # get shape
...    w,h = im.shape
    # get average
...    return np.average(im.reshape(w*h))

首先,图像块作为 PIL Image 对象传入。在第二步将图像转换为 numpy 数组,此时 'im' 成为每个像素的二维亮度数组。在第三步,你存储图像的尺寸(宽度和高度)。第四步, numpy.average() 通过使用 numpy.reshape() 计算图像中亮度值的平均值,首先将维度宽和高 (w,h) 的二维数组转换为平坦的维数组,其长度是宽度乘以高度 (w*h) 的乘积。numpy.average() 调用然后对这些数组值求和并计算平均值。
 

从图像生成 ASCII 内容 

  # ascii image is a list of character strings
>>>    aimg = []
    # generate list of dimensions
>>>    for j in range(rows):
...        y1 = int(j*h)
...        y2 = int((j+1)*h)
        # correct last tile
...        if j == rows-1:
...            y2 = H
        # append an empty string
...        aimg.append("")
...        for i in range(cols):
            # crop image to tile
...            x1 = int(i*w)
...            x2 = int((i+1)*w)
            # correct last tile
...            if i == cols-1:
...                x2 = W
            # crop image to extract tile
...            img = image.crop((x1, y1, x2, y2))
            # get average luminance
...            avg = int(getAverageL(img))
            # look up ascii char
...            if moreLevels:
...                gsval = gscale1[int((avg*69)/255)]
...            else:
...                gsval = gscale2[int((avg*9)/255)]
            # append ascii char to string
...            aimg[j] += gsval

如何将图像转换为ASCII图像?在程序的这一部分中,首先将 ASCII 图像存储为字符串列表,并在第一步进行初始化。接下来,你遍历计算出的行图像块数,并在第二个 steo 和下一行,计算每个图像块的起始和结束 y 坐标。尽管这些是浮点计算,但在将它们传递给图像裁剪方法之前将它们截断为整数。接下来,因为将图像划分为瓦片只会在图像宽度为列数的整数倍时创建相同大小的边缘瓦片,因此通过将 y 坐标设置为对最后一行瓦片的 y 坐标进行校正图片的实际高度。通过这样做,你可以确保图像的顶部边缘不会被截断。第三步,你可以在 ASCII 中添加一个空字符串作为表示当前图像行的紧凑方式。接下来你将填写此字符串。(你将字符串视为字符列表。)在第四步和下一行,你计算每个图块的左右 x 坐标,在第五步,你更正最后一个图块的 x 坐标。与你更正 y 坐标的原因相同。在第六步使用 image.crop() 提取图像块,然后将该块传递给上面定义的 getAverageL() 函数,将平均亮度值从 [0, 255] 缩小到 [0, 9](范围默认 10 级灰度渐变的值)。然后使用 gscale2(存储的斜坡字符串)作为 ASCII Art 95 相关 ASCII 值的查找表。八步线是类似的,除了它仅在命令行标记设置为使用 70 级斜坡时才使用。最后,将查找到的 ASCII 值 gsval 附加到最后一步的文本行,代码循环直到处理完所有行。
python如何将图片转为字符画?添加命令行界面并将 ASCII 艺术字符串写入文本文件
要添加命令行界面,请使用 python 内置模块argparse。 
现在最后,获取生成的 ASCII 字符串列表并将这些字符串写入文本文件。

# open a new text file
>>> f = open(outFile, 'w')
# write each string in the list to the new file
>>> for row in aimg:
...    f.write(row + '\n')
# clean up
>>> f.close()

然后添加这些部分以创建你的程序。python图片转字符画完整代码如下。

  • Python
# Python code to convert an image to ASCII image.
import sys, random, argparse
import numpy as np
import math
 
from PIL import Image
 
# gray scale level values from:
# http://paulbourke.net/dataformats/asciiart/
 
# 70 levels of gray
gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
 
# 10 levels of gray
gscale2 = '@%#*+=-:. '
 
def getAverageL(image):
 
    """
    Given PIL Image, return average value of grayscale value
    """
    # get image as numpy array
    im = np.array(image)
 
    # get shape
    w,h = im.shape
 
    # get average
    return np.average(im.reshape(w*h))
 
def covertImageToAscii(fileName, cols, scale, moreLevels):
    """
    Given Image and dims (rows, cols) returns an m*n list of Images
    """
    # declare globals
    global gscale1, gscale2
 
    # open image and convert to grayscale
    image = Image.open(fileName).convert('L')
 
    # store dimensions
    W, H = image.size[0], image.size[1]
    print("input image dims: %d x %d" % (W, H))
 
    # compute width of tile
    w = W/cols
 
    # compute tile height based on aspect ratio and scale
    h = w/scale
 
    # compute number of rows
    rows = int(H/h)
     
    print("cols: %d, rows: %d" % (cols, rows))
    print("tile dims: %d x %d" % (w, h))
 
    # check if image size is too small
    if cols > W or rows > H:
        print("Image too small for specified cols!")
        exit(0)
 
    # ascii image is a list of character strings
    aimg = []
    # generate list of dimensions
    for j in range(rows):
        y1 = int(j*h)
        y2 = int((j+1)*h)
 
        # correct last tile
        if j == rows-1:
            y2 = H
 
        # append an empty string
        aimg.append("")
 
        for i in range(cols):
 
            # crop image to tile
            x1 = int(i*w)
            x2 = int((i+1)*w)
 
            # correct last tile
            if i == cols-1:
                x2 = W
 
            # crop image to extract tile
            img = image.crop((x1, y1, x2, y2))
 
            # get average luminance
            avg = int(getAverageL(img))
 
            # look up ascii char
            if moreLevels:
                gsval = gscale1[int((avg*69)/255)]
            else:
                gsval = gscale2[int((avg*9)/255)]
 
            # append ascii char to string
            aimg[j] += gsval
     
    # return txt image
    return aimg
 
# main() function
def main():
    # create parser
    descStr = "This program converts an image into ASCII art."
    parser = argparse.ArgumentParser(description=descStr)
    # add expected arguments
    parser.add_argument('--file', dest='imgFile', required=True)
    parser.add_argument('--scale', dest='scale', required=False)
    parser.add_argument('--out', dest='outFile', required=False)
    parser.add_argument('--cols', dest='cols', required=False)
    parser.add_argument('--morelevels',dest='moreLevels',action='store_true')
 
    # parse args
    args = parser.parse_args()
   
    imgFile = args.imgFile
 
    # set output file
    outFile = 'out.txt'
    if args.outFile:
        outFile = args.outFile
 
    # set scale default as 0.43 which suits
    # a Courier font
    scale = 0.43
    if args.scale:
        scale = float(args.scale)
 
    # set cols
    cols = 80
    if args.cols:
        cols = int(args.cols)
 
    print('generating ASCII art...')
    # convert image to ascii txt
    aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)
 
    # open file
    f = open(outFile, 'w')
 
    # write to file
    for row in aimg:
        f.write(row + '\n')
 
    # cleanup
    f.close()
    print("ASCII art written to %s" % outFile)
 
# call main
if __name__ == '__main__':
    main()

输入: 

$python "ASCII_IMAGE_GENERATOR.py" --file data/11.jpg --cols 120

python图像转换ASCII图像相关资源

  1. 维基百科:ASCII_ART 
  2. Python Playground:Mahesh Venkitachalam 为好奇程序员设计的极客项目。 
  3. 灰度等级值 
  4. 本文的 Github 代码 
木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: