17 Jun 2021

Image 2 ASCII - ascii art generator

收藏到CSDN网摘

Converting images to ASCII, aka. ASCII art, has been explored by developers long time ago back to the time of DOS age. It is more about having fun but there are also some really good publications around this topic. Someone implemented online services to convert uploaded images to ASCII art like THIS one

The first answer under THIS QUESTION has a very detailed explanation and experiments of different approaches to this problem. A simple and straightforward approach is to do a pixel-2-text mapping from the image the the result ASCII text file. To avoid making the text file overcrowded, developers use to have some carefully selected character lists to reduce the intense level (number of chars used). So the process is more like a classification process: 

(1) find out which category the current pixel falls into; 
(2) pick up the character that represents the current category; 
(3) walking through the image pixel by pixel and repeat the process to generate the result text file.
Below is a very simple implementation of the algorithm described above. The best charset list is still under investigation. For instance, THIS website used a very simple character list "MNFV$I*:." while THIS website used a slightly longer list "B8&WM#YXQO{}[]()I1i!pao;:,. ". The QUESTION mentioned above has another simple list "@#%xo;:,. ", which achieves a rather good result. The longest list (maybe not) I found is a 70-character list "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " from HERE

 I am still experimenting with the various character list. The current version of my test code is shared below.
#!/usr/bin/env python

import PIL.Image
import sys
import tkinter as tk
from tkinter import filedialog

ASCII_CHARS = '$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`\'. '
ASCII_CHARS = "B8&WM#YXQO{}[]()I1i!pao;:,. "
ASCII_CHARS = 'MNFV$I*:.'
ASCII_CHARS = "@#%xo;:,. "
ASCII_CHARS = "MWKO0NXkdcxol;:,'.  "
ASCII_CHARS = "MWNXKO0kdcxol;:,'.  "
ASCII_CHARS = ASCII_CHARS[::-1]
ASCII_LEN = len(ASCII_CHARS)
CHAR_RATIO_ADJUST = 0.506


class Image2ASCII:
    def __init__(selffpathcharset=ASCII_CHARSnew_width=300):
        super().__init__()
        self.path_ = fpath.strip()
        if self.path_.startswith('"'):
            self.path_ = self.path_[1:]
        if self.path_.endswith('"'):
            self.path_ = self.path_[:-1]
        try:
            self.image_ = PIL.Image.open(self.path_)
            self.chars_ = charset
            self.char_len_ = len(self.chars_)
            self.width_ = new_width
            self.resize_greyscale()
        except:
            print(f'[ ERROR] unable to find image: {self.path_}')
            sys.exit(1)

    def resize_greyscale(self):
        try:
            widthheight = self.image_.size
            self.height_ = int(CHAR_RATIO_ADJUST * self.width_ * height / width)
            self.resized_ = self.image_.resize((self.width_self.height_))
            self.greyscale_ = self.resized_.convert('L')
        except:
            print(f'[ ERROR] unable to resize/convert image')
            sys.exit(1)

    def convert_2_ascii(self):
        try:
            ascii_str = ''.join([self.chars_[max(0min(round(p / 255 * self.char_len_),
                                                        self.char_len_ - 1))] for p in self.greyscale_.getdata()])
            self.ascii_str_ = '\n'.join([ascii_str[i:i + self.width_]
                                         for i in range(0len(ascii_str), self.width_)])
            out = self.path_[:self.path_.rindex('.')] + '.txt'
            with open(out'w'as f:
                f.write(self.ascii_str_)
            print(f'[OUTPUT] {out}')
        except:
            print(f'[ERROR ] unable to write txt file: {out}')
            sys.exit(1)


def main():
    root = tk.Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename()
    if len(file_path.strip()) > 0:
        print(f'[INPUT ] {file_path}')
        output_width = 300
        ascii_cls = Image2ASCII(file_pathnew_width=output_width)
        ascii_cls.convert_2_ascii()

if __name__ == '__main__':
    main()

No comments :

Post a Comment