首先導(dǎo)入必要的庫限匣,argparse 庫是用來管理命令行參數(shù)輸入的
from PIL import Image
import argparse
首先導(dǎo)入必要的庫,argparse 庫是用來管理命令行參數(shù)輸入的
# 首先偿曙,構(gòu)建命令行輸入?yún)?shù)處理 ArgumentParser 實(shí)例
parser = argparse.ArgumentParser()
# 定義輸入文件围小、輸出文件、輸出字符畫的寬和高
parser.add_argument('file') #輸入文件
parser.add_argument('-o', '--output') #輸出文件
parser.add_argument('--width', type = int, default = 80) #輸出字符畫寬
parser.add_argument('--height', type = int, default = 80) #輸出字符畫高
# 解析并獲取參數(shù)
args = parser.parse_args()
# 輸入的圖片文件路徑
IMG = args.file
# 輸出字符畫的寬度
WIDTH = args.width
# 輸出字符畫的高度
HEIGHT = args.height
# 輸出字符畫的路徑
OUTPUT = args.output
首先將 RGB 值轉(zhuǎn)為灰度值宵睦,然后使用灰度值映射到字符列表中的某個(gè)字符。
下面是我們的字符畫所使用的字符集群井,一共有 70 個(gè)字符状飞,為了方便寫入到實(shí)驗(yàn)環(huán)境中,可以使用實(shí)驗(yàn)環(huán)境右邊工具欄上的剪切板將以下代碼內(nèi)容拷貝到實(shí)驗(yàn)環(huán)境中书斜,注意需要使用右鍵復(fù)制和拷貝诬辈,不要使用 Ctrl-C/Ctrl-V
快捷鍵。字符的種類與數(shù)量可以自己根據(jù)字符畫的效果反復(fù)調(diào)試:
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
下面是 RGB 值轉(zhuǎn)字符的函數(shù)荐吉,注意 alpha 值為 0 的時(shí)候表示圖片中該位置為空白:
def get_char(r,g,b,alpha = 256):
# 判斷 alpha 值
if alpha == 0:
return ' '
# 獲取字符集的長度焙糟,這里為 70
length = len(ascii_char)
# 將 RGB 值轉(zhuǎn)為灰度值 gray,灰度值范圍為 0-255
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
# 灰度值范圍為 0-255样屠,而字符集只有 70
# 需要進(jìn)行如下處理才能將灰度值映射到指定的字符上
unit = (256.0 + 1)/length
# 返回灰度值對應(yīng)的字符
return ascii_char[int(gray/unit)]
完成上面的代碼之后穿撮,我們進(jìn)入到最后一個(gè)步驟昆咽,對圖片進(jìn)行處理矢洲。
這一個(gè)步驟我們放入到 if name == 'main': 代碼塊中(表示如果 ascii.py 被當(dāng)作 python 模塊 import 的時(shí)候缆巧,這部分代碼不會(huì)被執(zhí)行)宗弯。圖片的處理步驟如下:
首先使用 PIL 的 Image.open 打開圖片文件,獲得對象 im
使用 PIL 庫的 im.resize() 調(diào)整圖片大小對應(yīng)到輸出的字符畫的寬度和高度届慈,注意這個(gè)函數(shù)第二個(gè)參數(shù)使用 Image.NEAREST陵像,表示輸出低質(zhì)量的圖片呀伙。
遍歷提取圖片中每行的像素的 RGB 值知举,調(diào)用 getchar 轉(zhuǎn)成對應(yīng)的字符
將所有的像素對應(yīng)的字符拼接在一起成為一個(gè)字符串 txt
打印輸出字符串 txt
如果執(zhí)行時(shí)配置了輸出文件瞬沦,將打開文件將 txt 輸出到文件,如果沒有雇锡,則默認(rèn)輸出到 output.txt 文件
這個(gè)過程中需要注意的是調(diào)用 getchar 時(shí)候的參數(shù)是通過 PIL 庫的 getpixel 獲取的逛钻,見如下代碼:
char = get_char(*im.getpixel((j,i)))
其中 im.getpixel((j,i)) 獲取得到坐標(biāo) (j,i) 位置的 RGB 像素值(有的時(shí)候會(huì)包含 alpha 值),返回的結(jié)果是一個(gè)元組锰提,例如 (1,2,3) 或者 (1,2,3,0)曙痘。我們使用 * 可以將元組作為參數(shù)傳遞給 get_char芳悲,同時(shí)元組中的每個(gè)元素都對應(yīng)到 get_char 函數(shù)的每個(gè)參數(shù)。
該部分的代碼實(shí)現(xiàn)如下(注意 name 和 main 前后都是兩個(gè)下劃線):
if __name__ == '__main__':
# 打開并調(diào)整圖片的寬和高
im = Image.open(IMG)
im = im.resize((WIDTH,HEIGHT), Image.NEAREST)
# 初始化輸出的字符串
txt = ""
# 遍歷圖片中的每一行
for i in range(HEIGHT):
# 遍歷該行中的每一列
for j in range(WIDTH):
# 將 (j,i) 坐標(biāo)的 RGB 像素轉(zhuǎn)為字符后添加到 txt 字符串
txt += get_char(*im.getpixel((j,i)))
# 遍歷完一行后需要增加換行符
txt += '\n'
# 輸出到屏幕
print(txt)
# 字符畫輸出到文件
if OUTPUT:
with open(OUTPUT,'w') as f:
f.write(txt)
else:
with open("output.txt",'w') as f:
f.write(txt)
完整代碼參考
# -*- coding=utf-8 -*-
from PIL import Image
import argparse
#命令行輸入?yún)?shù)處理
parser = argparse.ArgumentParser()
parser.add_argument('file') #輸入文件
parser.add_argument('-o', '--output') #輸出文件
parser.add_argument('--width', type = int, default = 80) #輸出字符畫寬
parser.add_argument('--height', type = int, default = 80) #輸出字符畫高
#獲取參數(shù)
args = parser.parse_args()
IMG = args.file
WIDTH = args.width
HEIGHT = args.height
OUTPUT = args.output
ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
# 將256灰度映射到70個(gè)字符上
def get_char(r,g,b,alpha = 256):
if alpha == 0:
return ' '
length = len(ascii_char)
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
unit = (256.0 + 1)/length
return ascii_char[int(gray/unit)]
if __name__ == '__main__':
im = Image.open(IMG)
im = im.resize((WIDTH,HEIGHT), Image.NEAREST)
txt = ""
for i in range(HEIGHT):
for j in range(WIDTH):
txt += get_char(*im.getpixel((j,i)))
txt += '\n'
print(txt)
#字符畫輸出到文件
if OUTPUT:
with open(OUTPUT,'w') as f:
f.write(txt)
else:
with open("output.txt",'w') as f:
f.write(txt)