Python使用PIL將圖片或GIF轉(zhuǎn)為字符畫的方法詳解
圖片或GIF轉(zhuǎn)字符畫
紅及一時(shí)的編程小玩具,將圖片轉(zhuǎn)為字符畫
接下來通過
Python
實(shí)現(xiàn),比較好玩
圖片轉(zhuǎn)換為黑白字符畫
- 安裝
pillow
庫(kù)
pip3 install pillow
灰度值:黑白圖像中點(diǎn)的顏色深度,范圍一般從
0~255
,白色為255
,黑色為0
,所以黑白圖片也被成為灰度圖像
RBG
映射灰度公式
我們要將一張圖片的灰度處理,將其中的色彩處理為黑白灰亮度圖像
越亮的地方用占位百分比越小的字符來替換處理,比如
|
而越暗的地方用占位百分比越大的字符來替換處理,比如
#
創(chuàng)建一個(gè)不重復(fù)字符序列數(shù)據(jù),灰度值越?。ㄔ桨担樾蛄袛?shù)據(jù)開頭,越大(越亮)到序列結(jié)尾,長(zhǎng)度為
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_) #字符序列長(zhǎng)度 index = (alpha+1) / char_length #總灰度值對(duì)應(yīng)列表索引范圍 return char_[int(gray/index)] #返回當(dāng)前灰度值所對(duì)應(yīng)字符
pillow
模塊可以打卡圖像,并重設(shè)圖像大小,分析圖像像素,定義如下函數(shù),取出圖像對(duì)應(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) #遍歷像素,獲得灰度值對(duì)應(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_) # 字符序列長(zhǎng)度 index = (alpha+1) / char_length # 總灰度值對(duì)應(yīng)列表索引范圍 return char_[int(gray/index)] # 返回當(dāng)前灰度值所對(duì)應(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) #遍歷像素,獲得灰度值對(duì)應(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') # 獲取最長(zhǎng)行的長(zhǎng)度和總行數(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_) # 字符序列長(zhǎng)度 index = (alpha+1) / char_length # 總灰度值對(duì)應(yīng)列表索引范圍 return char_[int(gray/index)] # 返回當(dāng)前灰度值所對(duì)應(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ì)量 # 遍歷像素,獲得灰度值對(duì)應(yīng)字符 content = '' for h in range(height): for w in range(width): char = get_char(*img.getpixel((w, h))) # img.getpixel(w,h) 獲取對(duì)應(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)彩色字符畫
思路很簡(jiǎn)單,將
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_) #字符序列長(zhǎng)度 index = (alpha+1) / char_length #總灰度值對(duì)應(yīng)列表索引范圍 return char_[int(gray/index)] #返回當(dāng)前灰度值所對(duì)應(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ì)量 #遍歷像素,獲得灰度值對(duì)應(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) 獲取對(duì)應(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è)可以在給定圖像上繪圖的對(duì)象 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)字符畫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python 實(shí)現(xiàn)體質(zhì)指數(shù)BMI計(jì)算
這篇文章主要介紹了python 實(shí)現(xiàn)體質(zhì)指數(shù)BMI計(jì)算操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05python如何在一個(gè)py文件中獲取另一個(gè)py文件中的值(一個(gè)或多個(gè))
這篇文章主要介紹了python如何在一個(gè)py文件中獲取另一個(gè)py文件中的值(一個(gè)或多個(gè)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08python時(shí)間序列數(shù)據(jù)相減的實(shí)現(xiàn)
本文主要介紹了python時(shí)間序列數(shù)據(jù)相減的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04解決每次打開pycharm直接進(jìn)入項(xiàng)目的問題
今天小編就為大家分享一篇解決每次打開pycharm直接進(jìn)入項(xiàng)目的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10Python實(shí)現(xiàn)制作透明背景的電子印章
這篇文章主要為大家詳細(xì)介紹了如何利用Python語(yǔ)言實(shí)現(xiàn)制作透明背景的電子印章,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-09-09用python做一個(gè)搜索引擎(Pylucene)的實(shí)例代碼
下面小編就為大家?guī)硪黄胮ython做一個(gè)搜索引擎(Pylucene)的實(shí)例代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07基于python分享一款地理數(shù)據(jù)可視化神器keplergl
這篇文章主要介紹了分享一款地理數(shù)據(jù)可視化神器keplergl,keplergl是由Uber開源的一款地理數(shù)據(jù)可視化工具,通過keplergl我們可以在Jupyter?notebook中使用,下文分享需要的小伙伴可以參考一下2022-02-02Python利用os模塊實(shí)現(xiàn)自動(dòng)刪除磁盤文件
你們一定想不到os模塊還可以這樣玩,本文就將利用Python中的os模塊實(shí)現(xiàn)自動(dòng)刪除磁盤文件功能,文中的示例代碼講解詳細(xì),感興趣的可以嘗試一下2022-11-11