Python使用PIL將圖片或GIF轉(zhuǎn)為字符畫的方法詳解
圖片或GIF轉(zhuǎn)字符畫
紅及一時(shí)的編程小玩具,將圖片轉(zhuǎn)為字符畫
接下來通過
Python實(shí)現(xiàn),比較好玩
圖片轉(zhuǎn)換為黑白字符畫
- 安裝
pillow庫
pip3 install pillow
灰度值:黑白圖像中點(diǎn)的顏色深度,范圍一般從
0~255,白色為255,黑色為0,所以黑白圖片也被成為灰度圖像
RBG映射灰度公式
我們要將一張圖片的灰度處理,將其中的色彩處理為黑白灰亮度圖像
越亮的地方用占位百分比越小的字符來替換處理,比如
|而越暗的地方用占位百分比越大的字符來替換處理,比如
#
創(chuàng)建一個(gè)不重復(fù)字符序列數(shù)據(jù),灰度值越?。ㄔ桨担樾蛄袛?shù)據(jù)開頭,越大(越亮)到序列結(jié)尾,長度為
90,用來映射256個(gè)灰度值,便捷的方法可以直接使用ascii碼進(jìn)行構(gòu)建定義函數(shù),用來處理
RGB并得出灰度值,根據(jù)灰度值,得出一個(gè)字符
char_=list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?_+~<>i!lI;:,\"^`'. ")
def get_char(r,g,b, alpha=256):
'''
r(紅),g(綠),b(藍(lán))
total: 灰度值總大小
return -> str
'''
if alpha == 0:
return ' '
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b #得出灰度值
char_length = len(char_) #字符序列長度
index = (alpha+1) / char_length #總灰度值對應(yīng)列表索引范圍
return char_[int(gray/index)] #返回當(dāng)前灰度值所對應(yīng)字符
pillow模塊可以打卡圖像,并重設(shè)圖像大小,分析圖像像素,定義如下函數(shù),取出圖像對應(yīng)坐標(biāo)像素
from PIL import Image
def convert_image_to_ascii(origin_path, output_path, width=150, height=80):
"""
將圖像轉(zhuǎn)換為ASCII文字并保存到文本文件
:param origin_path: 輸入圖像路徑
:param output_path: 輸出文本文件路徑
:param width: 輸出寬度
:param height: 輸出高度
:return: None
"""
# 打開圖像,并將其轉(zhuǎn)換為RGBA格式以確保包含alpha通道信息
img = Image.open(origin_path).convert('RGBA')
#Image.NEAREST 代表設(shè)置縮放圖片的質(zhì)量
img = img.resize((width,height),Image.NEAREST)
#遍歷像素,獲得灰度值對應(yīng)字符
content = ''
for h in range(height):
for w in range(width):
char = get_char(*img.getpixel((w,h)))
content += char
content += '\n' #每一行像素?fù)Q行追加\n
with open(output_path,'w') as fp:
fp.write(content)
return content
- 運(yùn)行這段代碼,調(diào)用
analy_image函數(shù),傳入待處理圖像路徑path及保存之后的文件路徑file
比如這樣一張圖片

- 經(jīng)過代碼處理之后將會(huì)變?yōu)?/li>

- 如果想把文本存儲(chǔ)為圖片也可以
from PIL import Image
from PIL import Image, ImageDraw, ImageFont
char_ = list(
"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?_+~<>i!lI;:,\"^`'. ")
def get_char(r, g, b, alpha=256):
'''
r(紅),g(綠),b(藍(lán))
total: 灰度值總大小
return -> str
'''
if alpha == 0:
return ' '
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b # 得出灰度值
char_length = len(char_) # 字符序列長度
index = (alpha+1) / char_length # 總灰度值對應(yīng)列表索引范圍
return char_[int(gray/index)] # 返回當(dāng)前灰度值所對應(yīng)字符
def convert_image_to_ascii(origin_path, output_path, width=150, height=80):
"""
將圖像轉(zhuǎn)換為ASCII文字并保存到文本文件
:param origin_path: 輸入圖像路徑
:param output_path: 輸出文本文件路徑
:param width: 輸出寬度
:param height: 輸出高度
:return: None
"""
# 打開圖像,并將其轉(zhuǎn)換為RGBA格式以確保包含alpha通道信息
img = Image.open(origin_path).convert('RGBA')
#Image.NEAREST 代表設(shè)置縮放圖片的質(zhì)量
img = img.resize((width,height),Image.NEAREST)
#遍歷像素,獲得灰度值對應(yīng)字符
content = ''
for h in range(height):
for w in range(width):
char = get_char(*img.getpixel((w,h)))
content += char
content += '\n' #每一行像素?fù)Q行追加\n
with open(output_path,'w') as fp:
fp.write(content)
return content
def ascii_art_to_image(ascii_art, output_path, font_path=None, font_size=20):
"""
將ASCII字符藝術(shù)轉(zhuǎn)換為圖片并保存
:param ascii_art: ASCII字符藝術(shù)字符串
:param output_path: 輸出圖片路徑
:param font_path: 字體文件路徑,默認(rèn)為None,表示使用默認(rèn)字體
:param font_size: 字體大小
:return: None
"""
# 分割A(yù)SCII藝術(shù)字符串為行列表
lines = ascii_art.split('\n')
# 獲取最長行的長度和總行數(shù),用于確定圖片尺寸
max_line_length = max(len(line) for line in lines)
num_lines = len(lines)
# 設(shè)置圖片的基本參數(shù)
char_width, char_height = font_size, font_size # 假設(shè)每個(gè)字符寬度和高度相等
margin = 10 # 圖片邊緣留白
# 創(chuàng)建白色背景的新圖像
image = Image.new('RGB',
(max_line_length * char_width + 2 * margin,
num_lines * char_height + 2 * margin),
color='white')
draw = ImageDraw.Draw(image)
try:
# 加載字體
if font_path:
font = ImageFont.truetype(font_path, font_size)
else:
font = ImageFont.load_default()
except IOError:
print("加載字體失敗,使用默認(rèn)字體")
font = ImageFont.load_default()
# 在圖像上繪制ASCII藝術(shù)文字
for i, line in enumerate(lines):
draw.text((margin, margin + i * char_height),
line, fill='black', font=font)
# 保存圖像
image.save(output_path)
print(f"已保存圖片至 {output_path}")
path = '1.jpg'
file = '1.txt'
content_str = convert_image_to_ascii(path, '1.txt')
ascii_art_to_image(content_str, '1_ASCII.jpg')
- 完整代碼
from PIL import Image
char_ = list(
"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?_+~<>i!lI;:,\"^`'. ")
def get_char(r, g, b, alpha=256):
'''
r(紅),g(綠),b(藍(lán))
total: 灰度值總大小
return -> str
'''
if alpha == 0:
return ' '
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b # 得出灰度值
char_length = len(char_) # 字符序列長度
index = (alpha+1) / char_length # 總灰度值對應(yīng)列表索引范圍
return char_[int(gray/index)] # 返回當(dāng)前灰度值所對應(yīng)字符
def analy_image(path, file):
"""
path: 處理圖像路徑
file: 處理后的保存文件
return -> None
"""
img = Image.open(path)
width = 80
height = 80
img = img.resize((width, height), Image.NEAREST)
# Image.NEAREST 代表設(shè)置縮放圖片的質(zhì)量
# 遍歷像素,獲得灰度值對應(yīng)字符
content = ''
for h in range(height):
for w in range(width):
char = get_char(*img.getpixel((w, h)))
# img.getpixel(w,h) 獲取對應(yīng)坐標(biāo)像素
content += char
content += '\n' # 每一行像素?fù)Q行追加\n
print(content)
with open(file, 'w') as fp:
fp.write(content)
將GIF轉(zhuǎn)換為動(dòng)態(tài)彩色字符畫
思路很簡單,將
GIF圖片處理為一幀一幀的單獨(dú)圖片,再將單獨(dú)圖片灰度處理搞成字符圖片,像上面這樣,最終再上色并且把一陣一陣的字符圖片組合成一個(gè)字符GIF
from PIL import Image,ImageDraw,ImageFont
import os
from time import sleep
import imageio
char_ = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
#"MNHQ$OC67+>!:-. "
def get_char(r,g,b,alpha=256):
'''
r(紅),g(綠),b(藍(lán))
total: 灰度值總大小
return -> str
'''
if alpha == 0:
return ''
gray = 0.2126 * r + 0.7152 * g + 0.0722 * b #得出灰度值
char_length = len(char_) #字符序列長度
index = (alpha+1) / char_length #總灰度值對應(yīng)列表索引范圍
return char_[int(gray/index)] #返回當(dāng)前灰度值所對應(yīng)字符
def gif2png(path='test.gif'):
'''
path: GIF 圖像路徑
該函數(shù)拆分GIF為單獨(dú)的每一張PNG圖片
'''
img = Image.open(path)
work_path = os.getcwd() #當(dāng)前工作路徑
cache_dir = os.path.join(work_path,'cache')
if not os.path.exists(cache_dir):
#如果不存在保存單獨(dú)每一幀圖片的目錄,則創(chuàng)建該目錄
os.mkdir(cache_dir)
while True:
try:
current = img.tell() #獲取當(dāng)前幀位置
file_name = os.path.join(cache_dir,str(current)+'.png')
img.save(file_name)
img.seek(current+1) #向下一幀讀取
except EOFError:
#GIF讀取完畢
break
return current
def analy_image(pic_id):
"""
path: 處理圖像路徑
file: 處理后的保存文件
return -> None
"""
cache_dir = os.path.join(os.getcwd(),'cache')
path = os.path.join(cache_dir,'%d.png' % (pic_id))
img = Image.open(path).convert('RGB')
#GIF處理后的單幀圖片需要轉(zhuǎn)換為RGB格式,否則會(huì)報(bào)錯(cuò)
pic_width,pic_height = img.width,img.height
width = int(pic_width / 6)
height = int(pic_height / 12)
img = img.resize((width,height),Image.NEAREST)
#Image.NEAREST 代表設(shè)置縮放圖片的質(zhì)量
#遍歷像素,獲得灰度值對應(yīng)字符
content = ''
colors = []
for h in range(height):
for w in range(width):
px = img.getpixel((w,h))
char = get_char(px[0],px[1],px[2], px[3] if len(px) > 3 else 256)
colors.append( (px[0],px[1],px[2]) )
#img.getpixel(w,h) 獲取對應(yīng)坐標(biāo)像素
content += char
content += '\n' #每一行像素?fù)Q行追加\n
colors.append( (255,255,255) )
print(content)
return content,colors,pic_width,pic_height
def text2png(content,colors,pic_width,pic_height,pic_id):
'''
將輸出的圖片字符文本轉(zhuǎn)換為png
'''
work_path = os.getcwd() #當(dāng)前工作路徑
content_dir = os.path.join(work_path,'content')
if not os.path.exists(content_dir):
#如果不存在保存單獨(dú)每一幀圖片的目錄,則創(chuàng)建該目錄
os.mkdir(content_dir)
txt_img = Image.new("RGB", (pic_width,pic_height), (255,255,255))
canvas = ImageDraw.Draw(txt_img) #創(chuàng)建一個(gè)可以在給定圖像上繪圖的對象
font = ImageFont.load_default().font
x = 0
y = 0
font_w,font_h = font.getsize(content[1]) #字體的寬高
for i in range(len(content)):
if content[i] == '\n':
x = -font_w #每次初始化橫縱坐標(biāo)
y += font_h
canvas.text( (x,y), content[i], colors[i])
x += font_w # 追加一個(gè)字體的像素
txt_img.save(os.path.join(content_dir,'%d.png' % (pic_id)))
def png2gif(_id,dir_name='content',duration=5 / 130):
'''
將之前處理好的字符png圖片組合成GIF圖像
通過imageio模塊處理合并
'''
path = os.path.join(os.getcwd(),dir_name)
images = []
for pic_id in range(_id):
#遍歷取出每一張?zhí)幚砗蟮淖址麍D片id值
images.append(imageio.imread(os.path.join(path,'%d.png' % pic_id) ) )
#從文件中讀入數(shù)據(jù)
imageio.mimsave(os.path.join(os.getcwd(),'fin.gif'), images, duration=duration)
#保存路徑、png圖片數(shù)據(jù)列表、合并幀頻率
def main():
path = input(':')
_id = gif2png(path)
for pic_id in range(_id+1):
content,colors,pic_width,pic_height = analy_image(pic_id)
text2png(content,colors,pic_width,pic_height,pic_id)
sleep(5 / 130)
os.system('cls')
png2gif(_id)
if __name__ == '__main__':
main()
- 來看這樣一張
GIF圖片

- 他會(huì)變成這樣

以上就是Python使用PIL將圖片或GIF轉(zhuǎn)為字符畫的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Python PIL圖片或GIF轉(zhuǎn)字符畫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python利用xlrd和xlwt模塊進(jìn)行自動(dòng)化操作讀寫Excel的完整指南
在日常工作中,Excel表格是不可或缺的數(shù)據(jù)處理工具,本文將介紹xlrd和xlwt模塊的參數(shù)說明,并通過代碼實(shí)戰(zhàn)演示如何進(jìn)行Excel的讀寫操作,有需要的可以了解下2025-11-11
python中的生成器實(shí)現(xiàn)周期性報(bào)文發(fā)送功能
本文主要介紹了python中的生成器實(shí)現(xiàn)周期性報(bào)文發(fā)送功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Python機(jī)器學(xué)習(xí)利用隨機(jī)森林對特征重要性計(jì)算評估
本文是對隨機(jī)森林如何用在特征選擇上做一個(gè)簡單的介紹。隨機(jī)森林非常簡單,易于實(shí)現(xiàn),計(jì)算開銷也很小,更令人驚奇的是它在分類和回歸上表現(xiàn)出了十分驚人的性能2021-10-10
Python實(shí)現(xiàn)農(nóng)歷轉(zhuǎn)換教程詳解
農(nóng)歷,是我國現(xiàn)行的傳統(tǒng)歷法。它是根據(jù)月相的變化周期,每一次月相朔望變化為一個(gè)月,參考太陽回歸年為一年的長度,并加入二十四節(jié)氣與設(shè)置閏月以使平均歷年與回歸年相適應(yīng)。本文將用Python實(shí)現(xiàn)農(nóng)歷轉(zhuǎn)換,需要的可以參考一下2022-03-03
pandas讀取csv文件,分隔符參數(shù)sep的實(shí)例
今天小編就為大家分享一篇pandas讀取csv文件,分隔符參數(shù)sep的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12

