1. 程式人生 > >【Python AsciiArt】利用命令列打印出字元圖案

【Python AsciiArt】利用命令列打印出字元圖案

利用字串生成工具可以方便的打印出自己想要字元圖案,以及如何將圖片轉換為ASCII ART輸出。
最終可以用命令列輸出各種彩色影象---->>
利用背景顯示,引數48,佔位符grays[-2]


一般字元圖案

我們在使用一些開源軟體的時候,啟動開啟的字元圖形很好看。於是搜尋到了一些工具來實現:

"""
 _              _   _                        
| |            | | ( )                       
| |       ___  | |_|/   ___    __ _    ___   
| |      / _ \ | __|   / __|  / _` |  / _ \  
| |____ |  __/ | |_    \__ \ | (_| | | (_) | 
\_____/  \___|  \__|   |___/  \__, |  \___/  
                               __/ |         
                              |___/                                                                                                                                                                                         
"""

1.網站taag

在這裡插入圖片描述
可以隨意輸入內容,調節字型、寬、高。

同時作者還有另外一個ascii圖形生成器:http://patorjk.com/arial-ascii-art

#一條小鱷魚
#                    __  __
#       _ _        /[email protected])[email protected]) \          /^^\ /^\ /^^\_ 
#    _/oo \____/~''. . .  '~\       /'\''  ~ ''~~' -'\_ 
#   / '.'. ~.~.~.       .'    ~ |     /'\~~..''''.'' ''  ~\_ 
# ('_'_'_'_'_'_'_'_ ' : ' \_/' '.'' . '. .'' '. ~\_ # ~V~V~V~V \ ~\ '' '~ ' '' ~ ` ~ '' ~\_ # /\~/\~/\~/\~/|/ ' '' _ ' ~ '' ' ~ '' __ ' .. \_ # <-- --- ---.---.--/' '' /' '\_ '' ': ~ ;;'' ' /''; \ ;'''''' '' ~\ _ # \~ '. . : .:: ~. :. /_'''_'' \_' :'''_ : _ ''/''_' '_ \:_ '''' #''..\/\/\/~/\~ ''~~~~~O
# ~~ \-~ `---~~~---- \(_)(_)(_)/ ~ ~~' ~\(_)(_)(_)\_~_~_~_~_~/˜¤¹

如果想要在python中輸出,只需要把上面的字串賦值然後使用print函式列印即可,需要用多行註釋來包含這些字元:
在這裡插入圖片描述

2.命令列工具figlet

figlet [ -cklnoprstvxDELNRSWX ] [ -d fontdirectory ]
      [ -f fontfile ] [ -m layoutmode ]
      [ -w outputwidth ] [ -C controlfile ]
      [ -I infocode ] [ message ]

安轉後直接在命令列中使用即可。更多高階用法參考doc


圖片字串圖案

3.在python中顯示字串圖片

這種方法的主要原理是利用一組視覺密度不同的字元,按照灰度去替換每一個畫素:

  • 可以將影象的灰度定義為不同的級別來顯示:
    gscale1 = "[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^.
    gscale2 = "@%#*+=-:. " 這種灰度級別少一些
  • 然後讀入影象,將影象對映為長寬等比的矩陣;
  • 然後將顏色灰度值對映到定義的灰度級別上來。
import sys
import cv2

grays = "@%#*+=-:. "   #由於控制檯是白色背景,所以先密後疏/黑色背景要轉置一下
gs = 10                #10級灰度
#grays2 = "[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^.` "
#gs2 = 67

img = cv2.imread('where/your/img.jpg',0)  #讀入灰度圖

#寬(列)和高(行數)
w = img.shape[1]
h = img.shape[0]
ratio = float(w)/h  #調整長寬比 (**注:此比例為win cmd,ratio需要根據不同終端的字元長寬調整)   

scale = w // 50    #縮放尺度,向下取整,每50個畫素取一個 值越小圖越小(scale 越大)

for y in range(0, h, int(scale*ratio)):  #根據縮放長度 遍歷高度 y對於h,x對應w
    for x in range(0, w, scale):  #根據縮放長度 遍歷寬度
        idx=img[y][x] * gs // 255  #獲取每個點的灰度  根據不同的灰度填寫相應的 替換字元
        if idx==gs:
            idx=gs-1
        sys.stdout.write(grays[idx])  #寫入控制檯
    sys.stdout.write('\n')
    sys.stdout.flush()

在這裡插入圖片描述在這裡插入圖片描述


4.輸出影象

首先我們將上面的灰度圖轉字元的程式碼封裝成一個函式img_ascii

def img_ascii(img,r=3):
    #img: input img
    #r:  raito params #由於不同控制檯的字元長寬比不同,所以比例需要適當調整。
    #window cmd:r=3/linux console r=
    
    grays = "@%#*+=-:. "   #由於控制檯是白色背景,所以先密後疏/黑色背景要轉置一下
    gs = 10                #10級灰度
    #grays2 = "[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^.` "
    #gs2 = 67              #67級灰度

    #寬(列)和高(行數)
    w = img.shape[1]
    h = img.shape[0]
    ratio = r*float(w)/h  #調整長寬比-根據終端改變r

    scale = w // 100    #縮放尺度/取值步長,向下取整,每100/50個畫素取一個 值越小圖越小(scale 越大)

    for y in range(0, h, int(scale*ratio)):  #根據縮放長度 遍歷高度 y對於h,x對應w
        strline=''
        for x in range(0, w, scale):  #根據縮放長度 遍歷寬度
            idx=img[y][x] * gs // 255  #獲取每個點的灰度  根據不同的灰度填寫相應的 替換字元
            if idx==gs:
                idx=gs-1
            strline+=grays[idx]  #寫入控制檯
        print(strline)
        #sys.stdout.flush()

然後利用控制檯輸出彩色的功能

#控制帶自帶的256色輸出功能,demo如下
#from:#https://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal

print("Color indexes should be drawn in bold text of the same color.")

colored = [0] + [0x5f + 40 * n for n in range(0, 5)]    #array combined [0, 95, 135, 175, 215, 255]
colored_palette = [
    "%02x/%02x/%02x" % (r, g, b)    #轉為16進位制
    for r in colored
    for g in colored
    for b in colored
]

grayscale = [0x08 + 10 * n for n in range(0, 24)]
grayscale_palette = [
    "%02x/%02x/%02x" % (a, a, a)
    for a in grayscale 
]

normal = "\033[38;5;%sm" 
bold = "\033[1;38;5;%sm"
reset = "\033[0m"

for (i, color) in enumerate(colored_palette + grayscale_palette, 16):
    index = (bold + "%4s" + reset) % (i, str(i) + ':')
    hex   = (normal + "%s" + reset) % (i, color)
    newline = '\n' if i % 6 == 3 else ''
    print(index, hex, newline,)
##ref
#https://en.wikipedia.org/wiki/ANSI_escape_code
#https://github.com/grawity/code/blob/master/term/xterm-color-chooser
#https://unix.stackexchange.com/questions/404414/print-true-color-24-bit-test-pattern/404415#404415

可見核心是利用格式化輸出ASCII轉義碼(ANSI escape code)來實現的:
print("\033[38;5;%sm #\n"%'1') #其中%s對應的就是256位顏色的一種
在這裡插入圖片描述

我們需要根據rgb值和對應的顏色構建查表或轉換函式來將圖形中的顏色(r,g,b)轉為n[0,255]:

based = range(0,16)
based_palette = [
    "%02x" %l    #轉為16進位制
    for l in based
]

colored = [0] + [0x5f + 40 * n for n in range(0, 5)]    #array combined [0, 95, 135, 175, 215, 255]
colored_palette = [
    "%02x/%02x/%02x" % (r, g, b)    #轉為16進位制
    for r in colored
    for g in colored
    for b in colored
]

grayscale = [0x08 + 10 * n for n in range(0, 24)]
grayscale_palette = [
    "%02x/%02x/%02x" % (a, a, a)
    for a in grayscale 
]

color_256 = based_palette + colored_palette + grayscale_palette 
#生成一個字典
color_dict={color:i for (i,color) in enumerate(color_256)}
#通過rgb值近似到00/5f/87/af/d7/ff來得到彩色值

#輸出顯示各種顏色
index =''
for (i,color) in enumerate(color_256):
    index +=  "\033[38;5;%sm#"%i   #其中#為各個顏色的輸出顯示
print(index)

在這裡插入圖片描述
或者可以選擇公式來直接轉換216種彩色:
16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)(待驗證)


A.首先我們需要定義一本RGB**到真彩的顏色字典,利用前面生成的color_256來定義:

#先定義顏色和對應的16進位制值
based = range(0,16)
based_palette = [
    "%02x" %l    #轉為16進位制
    for l in based
]

colored = [0] + [0x5f + 40 * n for n in range(0, 5)]    #array combined [0, 95, 135, 175, 215, 255]
colored_palette = [
    "%02x%02x%02x" % (r, g, b)    #轉為16進位制
    for r in colored
    for g in colored
    for b in colored
]

grayscale = [0x08 + 10 * n for n in range(0, 24)]
grayscale_palette = [
    "%02x%02x%02x" % (a, a, a)
    for a in grayscale 
]

color_256 = based_palette + colored_palette + grayscale_palette 
#生成一個字典
color_dict={color:i for (i,color) in enumerate(color_256)}
#color_dict={}
#for index,name in enumerate(color_256):
#    color_dict[name]=index

B.隨後我們需要定義函式將影象的RGB轉換為對應的真彩畫素:

#首先定義函式,利用顏色字典將RGB顏色轉換為真彩對應數值
def cvtrgb(rgb,color_dict):
    xx=''
    #根據上面生成的顏色字典來,對於不同取值區間賦予不同的值
    for i in range(3):
        if rgb[i]<95:
            xx+= '00'
        elif rgb[i]<135:
            xx+= '5f'
        elif rgb[i]<175:
            xx+= '87'
        elif rgb[i]<215:
            xx+= 'af'
        elif rgb[i]<225:
            xx+= 'd7'
        else:
            xx+= 'ff'
        name =  ''.join(xx)
    
    value = color_dict[name]
    return value 

#隨後對輸入圖進行遍歷,將所有的RGB值轉換為相應的真彩值
def cvtimg(img,color_dict):
    ascii_img = np.array(img[:,:,0],dtype=np.string_)
    for h in range(img.shape[0]):
        for w in range(img.shape[1]):
            ascii_img[h,w] = cvtrgb(img[h,w,:],color_dict)   #呼叫換色函式
    return ascii_img  #返回值中每一個畫素已經是真彩值

C.最後重新定義一個真彩ASCII彩色繪圖函式來繪製,將原來的繪圖函式略微修改即可:

def img_color_ascii(img,r=3):
    #img: input img
    #r:  raito params #由於不同控制檯的字元長寬比不同,所以比例需要適當調整。
    #window cmd:r=3/linux console r=
    
    grays = "@%#*+=-:. "   #由於控制檯是白色背景,所以先密後疏/黑色背景要轉置一下
    gs = 10                #10級灰度
    #grays2 = "[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^.` "
    #gs2 = 67              #67級灰度

    #寬(列)和高(行數)
    w = img.shape[1]
    h = img.shape[0]
    ratio = r*float(w)/h  #調整長寬比-根據終端改變r

    scale = w // 100    #縮放尺度/取值步長,向下取整,每100/50個畫素取一個 值越小圖越小(scale 越大)

    for y in range(0, h, int(scale*ratio)):  #根據縮放長度 遍歷高度 y對於h,x對應w
        strline=''
        for x in range(0, w, scale):  #根據縮放長度 遍歷寬度
            idx=img[y][x] * gs // 255  #獲取每個點的灰度  根據不同的灰度填寫相應的 替換字元
            if idx==gs:
                idx=gs-1  #防止溢位
			######改變這裡,將真彩值利用命令列格式化輸出賦予
            color_id = "\033[38;5;%sm%s"%(img[y][x],grays[2])      #輸出!
            strline+= color_id #按行寫入控制檯
        print(strline)

D.下面就可以使用了:

#匯入圖片
import cv2
import matplotlib.pyplot as plt
import numpy as np
img0 = cv2.imread('img2.png')
img =cv2.cvtColor(img0,cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.axis('off')
plt.show()

在這裡插入圖片描述
隨後利用前面定義的顏色轉換函式得到ascii編碼的顏色值:

#使用前面定義的顏色字典,顏色轉換函式cvtrgb和影象對映哈數cvtimg
ass = cvtimg(img,color_dict)
ass = np.array(ass,dtype=np.int)  #將array轉化為int型別
img_color_ascii(ass,2.5)          #彩色繪圖函式,r=2.5調整比例,由於命令列行距存在需要微調r因子

在這裡插入圖片描述

下面就是一些轉換的影象,一起來感受一下自己的ASCII ART。(由於截圖,尺度可能有些許扭曲)
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述

5. 彩蛋

在這裡插入圖片描述
在做完了上面所有的程式碼之後,發現了控制檯的輸出還可以直接使用RGB來表示:
"\033[38;2;r;g;bm "
所以無需進行顏色空間轉換,直接利用RGB即可!
將上面的繪圖函式稍加改變:

def img_RGBcolor_ascii(img,r=3):
    #img: input img img here is 3channel!
    #r:  raito params #由於不同控制檯的字元長寬比不同,所以比例需要適當調整。
    #window cmd:r=3/linux console r=
    
    grays = "@%#*+=-:. "   #由於控制檯是白色背景,所以先密後疏/黑色背景要轉置一下
    gs = 10                #10級灰度
    #grays2 = "[email protected]%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~i!lI;:,\"^.` "
    #gs2 = 67              #67級灰度

    #寬(列)和高(行數)
    w = img.shape[1]
    h = img.shape[0]
    ratio = r*float(w)/h  #調整長寬比-根據終端改變r

    scale = w // 100    #縮放尺度/取值步長,向下取整,每100/50個畫素取一個 值越小圖越小(scale 越大)

    for y in range(0, h, int(scale*ratio)):  #根據縮放長度 遍歷高度 y對於h,x對應w
        strline=''
        for x in range(0, w, scale):  #根據縮放長度 遍歷寬度
            idx=int(img[100][100].mean()) * gs // 255  #獲取每個點的灰度  根據不同的灰度填寫相應的 替換字元
            if idx==gs:
                idx=gs-1  #防止溢位
			######改變這裡,將RGB值,利用2控制引數直接輸入
            color_id = "\033[38;2;%d;%d;%dm%s"%(img[y][x][0],img[y][x][1],img[y][x][2],grays[2])      #輸出!  
            #38為前景  ->> 48為背景 ,使用grays[-1/-2]輸出
            strline+= color_id #按行寫入控制檯
        print(strline)

img_RGBcolor_ascii(img)
就可以愉快繪圖了!
利用背景顯示,引數48,佔位符grays[-2]


在這裡插入圖片描述
pic from pexels.com

TODO

#https://en.wikipedia.org/wiki/ANSI_escape_code
#opencv:https://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html
def cvtRGB2ITU([r,g,b]):
    [r,g,b] = [r,g,b]/255*5
    color_v = 16 + 36 × r + 6 × g + b
    return color_v
def cvtRGB2ITU(color):
    #array combined [0, 95, 135, 175, 215, 255]  find the region
    color = np.array(color)/40
    color_v = color
    return color_v

ref:
https://en.wikipedia.org/wiki/ASCII_art
https://blog.csdn.net/qq_19655383/article/details/70176349
https://blog.csdn.net/su_bao/article/details/80355001
color:
https://www.text-image.com/index.html
https://www.maketecheasier.com/convert-pictures-ascii-art/
https://fossbytes.com/linux-distribution-logo-ascii-art-terminal/
https://gallery.technet.microsoft.com/scriptcenter/bc15444a-9490-4115-aa40-76d898041724
https://stackoverflow.com/questions/40754673/python-fails-to-output-ansi-color-codes-for-the-terminal
https://en.wikipedia.org/wiki/8-bit_color
changechar:https://www.geeksforgeeks.org/converting-image-ascii-image-python/
++||| https://stackoverflow.com/questions/287871/print-in-terminal-with-colors
modules:
https://pypi.org/project/colorama/
https://pypi.org/project/termcolor/
ternima:
https://unix.stackexchange.com/questions/404414/print-true-color-24-bit-test-pattern/404415#404415
++YY$$ python:https://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal
https://segmentfault.com/q/1010000016688755