在Python中将PPM图像转换为ASCII艺术

gorkyyrv  于 2023-10-21  发布在  Python
关注(0)|答案(3)|浏览(150)

我必须做一个程序,从命令行读入一个文件,并将其转换为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'对象是不可迭代的,是有一个简单的方法来解决这个问题,以及如何有人建议打印出来,同时保留图像。
最后一件我不确定的事情是如何保持图片的宽度和高度。
任何帮助将不胜感激。

u0njafvf

u0njafvf1#

您可以使用image-to-ansi.py进行转换。
首先,下载image-to-ansi.py

wget https://gist.githubusercontent.com/klange/1687427/raw/image-to-ansi.py

将其转换为Python 3语法:

2to3 -w image-to-ansi.py

安装Pillow,一个镜像库:

pip3 install pillow

保存此脚本为ppmimage.py

# Parses a PPM file and loads it into image-to-ansi.py
import re, itertools, sys
from PIL import Image

image_to_ansi = __import__("image-to-ansi") # __import__ because of minuses in filename. From https://gist.github.com/1687427

if __name__ == '__main__':
    im = Image.open('/dev/stdin')
    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")

您可以像这样测试脚本(假设您安装了netpbmimagemagick):
convert -resize $(($COLUMNS*2))x$(($LINES*2)) logo: pnm:- | pnmtoplainpnm | python3 ppmimage.py
在我的机器上,它看起来像这样:

yshpjwxd

yshpjwxd2#

在这里,您已经修改了代码并开始工作。
它不是最佳的,它没有考虑到头中存在或多或少的注解,也没有异常处理,但这是一个开始。

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 Art结果

下面是我在示例中使用的micro 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
i2loujxw

i2loujxw3#

不久前我用C#写了一个这样的程序,我用这个公式计算了要使用的字符:

index_into_array = (int)(r_g_b_value * (chars_array_length / (255.0)));

至于宽度和高度,您可以平均每两行垂直像素,以将高度减半。
编辑1:回应评论:基本思想是,它将RGB值从0到255再到0缩放到数组的长度,并将其用作索引。
编辑2:更新以纠正我忽略了你的灰度归一化。

相关问题