在Python中将图像转换为ASCII图像

ASCII艺术导论

null

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

工作原理:

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

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

要求

你将用python编写这个程序,我们将使用 枕头 这是Python图像库,用于读取图像、访问其底层数据、创建和修改图像以及科学模块 努比 计算平均值。

密码 首先定义用于生成ASCII艺术的灰度级别。然后,您将看到如何将图像分割为瓷砖,以及如何计算这些瓷砖的平均亮度。接下来,您将使用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)

计算平均亮度 接下来,计算灰度图像中平铺的平均亮度。函数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图像对象传入。在第二步中,将图像转换为一个numpy数组,此时“im”将成为每个像素的二维亮度数组。在第三步中,存储图像的尺寸(宽度和高度)。第四步,numpy。average()使用numpy计算图像中亮度值的平均值。重塑()首先将二维数组的宽度和高度(w,h)转换为?在一维数组中,其长度是宽度乘以高度(w*h)的乘积。努比。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图像首先存储为字符串列表,并在第一步初始化。接下来,迭代计算出的行图像分片数,在第二步和下一行,计算每个图像分片的开始和结束y坐标。虽然这些是?在进行点计算时,先将其截断为整数,然后再将其传递给图像裁剪方法。接下来,因为只有当图像宽度是列数的整数倍时,将图像分割为平铺才会创建相同大小的边缘平铺,所以通过将y坐标设置为图像的实际高度来校正最后一行中平铺的y坐标。这样做可以确保图像的上边缘不会被截断。在第三步,将空字符串添加到ASCII中,作为表示当前图像行的紧凑方式。下一步你要填写这个字符串。(将字符串视为字符列表。)在第四步和下一行中,计算每个磁贴的左右x坐标,在第五步中,按照校正y坐标的相同原因校正最后一个磁贴的x坐标。使用图像。裁剪()在第六步中,要提取图像平铺,然后将该平铺传递给上面定义的getAverageL()函数,请将平均亮度值从[0,255]缩小到[0,9](默认10级灰度渐变的值范围)。然后使用gscale2(存储的斜坡字符串)作为相关ASCII值的ASCII Art 95查找表。“八步”中的行与此类似,只是它仅在命令行?ag设置为使用70级坡道。最后,在最后一步将查找到的ASCII值gsval附加到文本行,代码循环直到所有行都被处理。 添加命令行界面并将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 + '')# clean up>>> f.close()

然后添加这些部分来创建程序。下面给出了完整的代码。

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:
# 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 + '' )
# 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

资源 1. 维基百科:ASCII_艺术 2.Python游乐场:Mahesh Venkitachalam为好奇的程序员设计的极客项目。 3. 灰度值 4. 本文的Github代码 本文由 Subhajit Saha .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 写极客。组织 或者把你的文章寄去评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。 如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享