我必须创建一个程序,从命令行读取文件并将其转换为ASCII艺术。我使用的是PPM格式,这里是the project的链接。
这是我到目前为止所做的:
import sys
def main(filename):
image = open(filename)
#reads through the first three lines
color = image.readline().splitlines()
size_width, size_height = image.readline().split()
max_color = image.readline().splitlines()
#reads the body of the file
pixels = image.read().split()
red = 0
green = 0
blue = 0
r_g_b_value = []
#pulls out the values of each tuple and coverts it to its grayscale value
for i in pixels:
if i != "\n" or " ":
if len(i) == 3:
red = int(i[0]) * .3
green = int(i[1]) * .59
blue = int(i[2]) * .11
elif len(i) == 2:
red == int(i[0]) * .3
green == int(i[1]) *.59
blue == 0
elif len(i) == 1:
red == int(i[0]) * .3
green == 0
blue == 0
r_g_b_value = [red + green + blue]
character = []
for j in len(r_g_b_value):
if int(j) <= 16:
character = " "
elif int(j) > 16 and int(j) <= 32:
character = "."
elif int(j) > 32 and int(j) <= 48:
character = ","
elif int(j) > 48 and int(j) <= 64:
charcter = ":"
elif int(j) > 64 and int(j) <= 80:
character = ";"
elif int(j) > 80 and int(j) <= 96:
character = "+"
elif int(j) > 96 and int(j) <= 112:
character = "="
elif int(j) > 112 and int(j) <= 128:
character = "o"
elif int(j) > 128 and int(j) <= 144:
character = "a"
elif int(j) > 144 and int(j) <= 160:
character = "e"
elif int(j) > 160 and int(j) <= 176:
character = "0"
elif int(j) > 176 and int(j) <= 192:
character = "$"
elif int(j) > 192 and int(j) <= 208:
character = "@"
elif int(j) > 208 and int(j) <= 224:
character = "A"
elif int(j) > 224 and int(j) <= 240:
character = "#"
else:
character = "M"
grayscale = character
print(grayscale)
main(sys.argv[1])
我得到一个错误,说“int”对象不可迭代,是否有一种简单的方法可以解决这个问题,有人会建议在保留图像时将其打印出来。
我不确定的最后一件事是如何保持图片的宽度和高度。
非常感谢任何帮助。
答案 0 :(得分:8)
您可以使用image-to-ansi.py
进行转化。
首先,下载image-to-ansi.py
:
wget https://gist.githubusercontent.com/klange/1687427/raw/image-to-ansi.py
将此脚本另存为ppmimage.py
:
# Parses a PPM file and loads it into image-to-ansi.py
import re, itertools
sep = re.compile("[ \t\r\n]+")
def chunks(iterable,size):
""" http://stackoverflow.com/a/434314/309483 """
it = iter(iterable)
chunk = tuple(itertools.islice(it,size))
while chunk:
yield chunk
chunk = tuple(itertools.islice(it,size))
""" Emulates the Image class from PIL and some member functions (`getpixel`, `size`). """
class Image:
""" This class emulates the PIL Image class, and it can parse "plain" PPM's.
You can use PIL instead. """
@staticmethod
def fromstdin():
return Image()
def __init__(self): # http://netpbm.sourceforge.net/doc/ppm.html
self.entities = sep.split("\n".join(list(filter(lambda x: not x.startswith("#"), sys.stdin.read().strip().split("\n")))))
self.size = tuple(list(map(int,self.entities[1:3])))
self.high = int(self.entities[3]) # z.b. 255
self.pixels = list(map(lambda x: tuple(map(lambda y: int(int(y) / self.high * 255), x)), list(chunks(self.entities[4:], 3))))
def getpixel(self, tupl):
x = tupl[0]
y = tupl[1]
pix = self.pixels[y*self.size[0]+x]
return pix
image_to_ansi = __import__("image-to-ansi") # __import__ because of minuses in filename. From https://gist.github.com/1687427
if __name__ == '__main__':
import sys
#import Image
im = Image.fromstdin() # use Image.open from PIL if using PIL
for y in range(im.size[1]):
for x in range(im.size[0]):
p = im.getpixel((x,y))
h = "%2x%2x%2x" % (p[0],p[1],p[2])
short, rgb = image_to_ansi.rgb2short(h)
sys.stdout.write("\033[48;5;%sm " % short)
sys.stdout.write("\033[0m\n")
sys.stdout.write("\n")
您可以像这样测试脚本(假设您已安装netpbm
和imagemagick
):
convert -resize $(($COLUMNS*2))x$(($LINES*2)) logo: pnm:- | pnmtoplainpnm | python3 ppmimage.py
在我的机器上,它看起来像这样:
答案 1 :(得分:4)
您可以在此处修改和修改代码 它不是最优的,它没有考虑标题中是否存在更多或更少的注释,并且没有异常处理,但它是一个开始。
import sys
import numpy as np
RGBS = range(16, 255, 16)
CHARS = [' ', '.', ',', ':', ';', '+', '=', 'o',
'a', 'e', '0', '$', '@', 'A', '#']
FACTORS = [.3, .59, .11]
def main(filename):
image = open(filename)
#reads header lines
color = image.readline()
_ = image.readline()
size_width, size_height = image.readline().split()
max_color = image.readline()
size_width = int(size_width)
max_color = int(max_color)
#reads the body of the file
data = [int(p) for p in image.read().split()]
#converts to array and reshape
data = np.array(data)
pixels = data.reshape((len(data)/3, 3))
#calculate rgb value per pixel
rgbs = pixels * FACTORS
sum_rgbs = rgbs.sum(axis=1)
rgb_values = [item * 255 / max_color for item in sum_rgbs]
grayscales = []
#pulls out the value of each pixel and coverts it to its grayscale value
for indx, rgb_val in enumerate(rgb_values):
#if max width, new line
if (indx % size_width) == 0 : grayscales.append('\n')
for achar, rgb in zip(CHARS, RGBS):
if rgb_val <= rgb:
character = achar
break
else:
character = 'M'
grayscales.append(character)
print ''.join(grayscales)
main('test.ppm')
这些是ppm数字和ASCII艺术结果
我用于示例的微ppm文件:
P3
# test.ppm
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
答案 2 :(得分:0)
我在C#中写了其中一个,我计算了这个公式使用的字符:
index_into_array = (int)(r_g_b_value * (chars_array_length / (255.0)));
对于宽度和高度,您可以平均每两行垂直像素将高度减半。
编辑1:回应评论: 基本思想是它将RGB值从0到255缩放到0到数组的长度,并将其用作索引。
编辑2:更新以更正我忽略了您的灰度标准化。