Introducción al arte ASCII
El arte ASCII es una técnica de diseño gráfico que utiliza computadoras para la presentación y consiste en imágenes ensambladas a partir de los 95 caracteres imprimibles (de un total de 128) definidos por el estándar ASCII de 1963 y conjuntos de caracteres compatibles con ASCII con caracteres extendidos patentados (más allá de los 128 caracteres de ASCII estándar de 7 bits). El término también se usa libremente para referirse al arte visual basado en texto en general. El arte ASCII se puede crear con cualquier editor de texto y, a menudo, se usa con lenguajes de forma libre. La mayoría de los ejemplos de arte ASCII requieren una fuente de ancho fijo (fuentes no proporcionales, como en una máquina de escribir tradicional) como Courier para la presentación. Entre los ejemplos más antiguos conocidos de arte ASCII se encuentran las creaciones del pionero del arte por computadora Kenneth Knowlton de alrededor de 1966, que trabajaba para Bell Labs en ese momento. “Studies in Perception I” de Ken Knowlton y Leon Harmon de 1966 muestra algunos ejemplos de su arte ASCII temprano. El arte ASCII se inventó, en gran parte, porque los primeros impresores a menudo carecían de capacidad gráfica y, por lo tanto, se usaban caracteres en lugar de marcas gráficas. Además, para marcar divisiones entre diferentes trabajos de impresión de diferentes usuarios, las impresoras a granel a menudo usaban arte ASCII para imprimir pancartas grandes, lo que hacía que la división fuera más fácil de detectar para que un operador de computadora o un empleado pudiera separar más fácilmente los resultados. El arte ASCII también se usó en los primeros correos electrónicos cuando las imágenes no se podían incrustar. Puedes encontrar más sobre ellos. [Fuente : Para marcar divisiones entre diferentes trabajos de impresión de diferentes usuarios, las impresoras a granel a menudo usaban arte ASCII para imprimir pancartas grandes, lo que hacía que la división fuera más fácil de detectar para que un operador de computadora o un empleado pudiera separar más fácilmente los resultados. El arte ASCII también se usó en los primeros correos electrónicos cuando las imágenes no se podían incrustar. Puedes encontrar más sobre ellos. [Fuente : Para marcar divisiones entre diferentes trabajos de impresión de diferentes usuarios, las impresoras a granel a menudo usaban arte ASCII para imprimir pancartas grandes, lo que hacía que la división fuera más fácil de detectar para que un operador de computadora o un empleado pudiera separar más fácilmente los resultados. El arte ASCII también se usó en los primeros correos electrónicos cuando las imágenes no se podían incrustar. Puedes encontrar más sobre ellos. [Fuente :wiki .
Cómo funciona:
Estos son los pasos que toma el programa para generar la
imagen ASCII:
- Convierta la imagen de entrada a escala de grises.
- Divide la imagen en mosaicos M×N.
- Corrija M (el número de filas) para que coincida con la relación de aspecto de la imagen y la fuente.
- Calcule el brillo promedio para cada mosaico de imagen y luego busque un carácter ASCII adecuado para cada uno.
- Reúna filas de strings de caracteres ASCII e imprímalas en un archivo para formar la imagen final.
Requisitos
Hará este programa en python y usaremos Pillow , que es la biblioteca de imágenes de Python para leer las imágenes, acceder a sus datos subyacentes y crearlos y modificarlos, y también el módulo científico Numpy para calcular los promedios.
El código
Comenzará definiendo los niveles de escala de grises utilizados para generar el arte ASCII. Luego verá cómo se divide la imagen en mosaicos y cómo se calcula el brillo promedio para esos mosaicos. A continuación, trabajará para reemplazar los mosaicos con caracteres ASCII para generar el resultado final. Finalmente, configurará el análisis de línea de comando para el programa para permitir que un usuario especifique el tamaño de salida, el nombre de archivo de salida, etc.
Definición de los niveles de escala de grises y la cuadrícula
Como primer paso para crear su programa, defina los dos niveles de escala de grises utilizados para convertir valores de brillo a caracteres ASCII como valores globales.
>>>gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^`". " #70 levels of gray >>>gscale2 = "@%#*+=-:. " #10 levels of gray
El valor gscale1 en u es la rampa de escala de grises de 70 niveles, y gscale2 en v es la rampa de escala de grises de 10 niveles más simple. Ambos valores se almacenan como strings, con un rango de caracteres que progresan desde el más oscuro hasta el más claro.
Ahora que tiene sus rampas en escala de grises, puede configurar la imagen. El siguiente código abre la imagen y la divide en una cuadrícula:
# 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)
Cálculo del brillo promedio
A continuación, calcula el brillo promedio de un mosaico en la imagen en escala de grises. La función getAverageL() hace el trabajo.
#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))
Primero, el mosaico de imagen se pasa como un objeto de imagen PIL. Convierta la imagen en una array numpy en el segundo paso, en cuyo punto ‘im’ se convierte en una array bidimensional de brillo para cada píxel. En el tercer paso, almacena las dimensiones (ancho y alto) de la imagen. En el cuarto paso, numpy.average() calcula el promedio de los valores de brillo en la imagen usando numpy.reshape() para convertir primero la array bidimensional de las dimensiones ancho y alto (ancho, alto) en una plana Array dimensional cuya longitud es el producto del ancho por la altura (ancho*alto). La llamada numpy.average() luego suma estos valores de array y calcula el promedio.
Generación del contenido ASCII a partir de la imagen
# 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
En esta sección del programa, la imagen ASCII se almacena primero como una lista de strings, que se inicializa en el primer paso. A continuación, itera a través del número calculado de mosaicos de imagen de fila y, en el segundo paso y en la línea siguiente, calcula las coordenadas y iniciales y finales de cada mosaico de imagen. Aunque estos son cálculos de punto flotante, trunquelos a números enteros antes de pasarlos a un método de recorte de imágenes. A continuación, debido a que dividir la imagen en mosaicos crea mosaicos de borde del mismo tamaño solo cuando el ancho de la imagen es un múltiplo entero del número de columnas, corrija la coordenada y de los mosaicos en la última fila configurando la coordenada y en la altura real de la imagen. Al hacerlo, se asegura de que el borde superior de la imagen no se trunque. En el tercer paso, agrega una string vacía en el ASCII como una forma compacta de representar la fila de la imagen actual. A continuación, rellenará esta string. (Usted trata la string como una lista de caracteres). En el cuarto paso y en la línea siguiente, calcula las coordenadas x izquierda y derecha de cada mosaico, y en el quinto paso, corrige la coordenada x para el último mosaico para el mismas razones por las que corrigió la coordenada y. Use image.crop() en el sexto paso para extraer el mosaico de la imagen y luego pase ese mosaico a la función getAverageL() definida anteriormente, reduzca el valor de brillo promedio de [0, 255] a [0, 9] (el rango de valores para la rampa de escala de grises de 10 niveles predeterminada). Luego usa gscale2 (la string de rampa almacenada) como una tabla de búsqueda para ASCII Art 95 el valor ASCII relevante. La línea en el paso ocho es similar, excepto que se usa solo cuando la bandera de la línea de comando está configurada para usar la rampa con 70 niveles. Finalmente, agrega el valor ASCII buscado, gsval, a la fila de texto en el último paso, y el código se repite hasta que se procesan todas las filas.
Adición de la interfaz de línea de comandos y escritura de strings de arte ASCII en un archivo de texto
Para agregar una interfaz de línea de comandos, use el módulo integrado de Python argparse .
Y ahora, finalmente, tome la lista generada de strings de caracteres ASCII y escríbalas en un archivo de texto.
# 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()
Luego agregue estas partes para crear su programa. El código completo se da a continuación.
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()
Aporte:
$python "ASCII_IMAGE_GENERATOR.py" --file data/11.jpg --cols 120
Recursos
1. Wikipedia: ASCII_ART
2. Python Playground: Geeky Projects for the Curious Programmer por Mahesh Venkitachalam.
3. Valores de nivel de escala de grises
4. Código de Github para este artículo Subhajit Saha
contribuye con este artículo . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA