影象轉字元畫
這是我第一個正經的python程式,之前的無非是照抄廖大佬的教程胡亂試探的小程式。在敲這個程式之前,用了一個週末熟悉python的語法,廖雪峰老師的教程真的很棒!
在敲這個程式之前,我遇到許多煩心的小問題,在這裡寫下來也許對您有些幫助
0.設定模組路徑
因為我用的是mac,自帶了python,在敲這個程式之前用的都是python2.x,然而,當我想用python3.7編寫程式時,卻出了問題
首先是PIL庫,我當時一句pip install pillow以為就能解決問題,在編譯的時候pycharm卻總是告訴我找不到pillow模組(我當時寫的是from pillow import Image, ImageFont, ImageDraw )
後來發現,應該是
from PIL import Image, ImageFont, ImageDraw
然而,還是不行,它繼續報錯,PIL模組也找不到,接下來我就開始了漫長的瀏覽各種部落格,發現我犯的錯誤真是不止一個
首先,pillow用不了是因為我是後裝的python3.7,通過pip下載的pillow不在它預設的模組資料夾裡
於是我先是這樣:
>>>import sys
>>>sys.path
然後它告訴我
['', '/anaconda3/lib/python37.zip', '/anaconda3/lib/python3.7', '/anaconda3/lib/python3.7/lib-dynload', '/anaconda3/lib/python3.7/site-packages', '/anaconda3/lib/python3.7/site-packages/aeosa']
退出python3,我又
$ pip install pillow
(因為這樣可以讓pip告訴你pillow裝在哪裡了)
然後它說
Requirement already satisfied: pillow in /usr/local/lib/python2.7/site-packages (5.3.0)
進去一看,還真有(在這之前我還查了一下為什麼我的mac看不到usr資料夾,我是有多菜……,其實查之前我還查了一下mac咋進入根目錄……)
點進去一看,PIL很大的樣子,pillow只有幾個檔案,我猜是用來給python3.x適配的,看來這個PIL必須要和pillow在一起python3.x才能用
現在pillow和PIL不在python3預設的模組路徑裡,我就把它複製過去唄
然後它又報錯了
ImportError: dlopen(/Users/blind/Desktop/python/newbie/PIL/_imaging.so, 2): Symbol not found: _PyInt_AsLong
Referenced from: /Users/blind/Desktop/python/newbie/PIL/_imaging.so
Expected in: flat namespace
幹啊,這又是為啥啊!
在stackoverflow上查了一下這個錯誤,突然明白我為什麼是智障了……
下載pillow時的命令應該是
pip3 install pillow
應該用pip3,而不是pip!!!
我再pip3一遍,發現針對python3的模組資料夾就在python2的右邊
把裡面的PIL和pillow複製到專案的資料夾下,我再
from PIL import Image, ImageFont, ImageDraw
好感動,終於正常運行了
1.查查pillow模組咋用
發現我們要用到Image, ImageFont, ImageDraw這三個模組以及裡面的各種函式
先把用到的函式貼出來,具體咋用後面再講
- Image模組
函式名 | 解釋 |
---|---|
Image.open(“x.x”) | 開啟一個影象檔案 |
im.size | 它的返回值為寬度和高度的二元組(width, height) |
Image.new(mode, size, color) | 新建一個影象檔案 |
im.resize | 縮放 |
- ImageFont模組
函式名 | 解釋 |
---|---|
ImageFont.load_default() | 載入一個預設的字型 |
- ImageDraw模組
函式名 | 解釋 |
---|---|
Draw(image) | 建立一個可以在給定影象上繪圖的物件 |
draw.text(position,string, options) | 在給定的位置繪製一個字元 |
2.開始敲
第一次獨立敲python還有點小緊張,之前簡單的看了一眼做字元畫的教程,因為想滿足自己的某種成就感,決定具體的程式碼還要自己敲!
發現pillow離不開Image類,用Image類的open函式
from PIL import Image
im = Image.open('666.jpg','r')
就能開啟專案資料夾下的hhh.jpg檔案了
同時我們要獲取這個影象的長和寬,用im.size就ok
w,h=im.size
然後順手再新建一個大小一樣的影象,用來儲存我們之後畫出來的字元畫
newIm= Image.new("RGB",im.size, (150, 150, 150))
其中(150,150,150)表示新建影象的背景顏色,因為我有強迫症就選了整數
然後就要我們識別圖片裡的每一個畫素,這裡要用到getpixel函式,只要這樣
im.getpixel((x, y))
就可以得到某個畫素點的顏色,一般返回(r, g, b),然後我們建一個列表color先把每個畫素點的RGB引數存下來
再新建一個字串,每對應一個畫素存一個字元,這裡我就比較騷了,可以這樣玩
char = "ILOVEYOU"
def GetChar(number):
return char[number%8]
然後只要在迴圈裡每次對number加1,就可以連續輸出ILOVEYOU了
把每個畫素都對應一個字元輸出到字串裡,我們就得到了一個文字檔案(別忘了敲回車,不然所有畫素對應的字元就都在一列了)
然後我們用ImageDraw類的Draw函式,像這樣
draw =ImageDraw.Draw(newIm)
就建立了一個可以在上面繪圖的物件,以後對圖片的處理都在draw這個物件上進行,但newIm也會跟著改變
接下來要獲取系統預設的字元資訊,分別是字元的寬和高
fontW,fontH=ImageFont.load_default().getsize(char[0])
接下來我們只要把txt中對應的字串和和colors中每個畫素的顏色結合繪製在draw上就完工了
然後執行,幹啊,為什麼只有原圖的一小部分?!
原來是一個畫素對應一個字元導致影象太大了
那我們只需要做一些小小的改動
newW = int(w/fontW)
newH = int(h/fontH)
im = im.resize((newW,newH), Image.NEAREST)
把im根據系統預設的字元大小縮放,然後在新的im中獲取畫素的顏色資訊
這次終於成功了!!!
附上程式碼和圖片
# -*- coding:utf-8 -*-
from PIL import Image, ImageFont, ImageDraw
char = "ILOVEYOU"
def GetChar(number):
return char[number%8]
im = Image.open('666.jpg', 'r')
w,h=im.size
newIm = Image.new("RGB", (w,h), (150, 150, 150))
fontW, fontH = ImageFont.load_default().getsize(char[0])
newW = int(w/fontW)
newH = int(h/fontH)
im = im.resize((newW,newH), Image.NEAREST)
txt = ""
colors = []
number = 0
for i in range(newH):
for j in range(newW):
pixel = im.getpixel((j, i))
colors.append((pixel[0], pixel[1], pixel[2]))
txt += GetChar(number)
number += 1
txt += '\n'
colors.append((0, 0, 0))
draw = ImageDraw.Draw(newIm)
x = y = 0
for i in range(len(txt)):
if (txt[i] == '\n'):
x += fontH
y = -fontW
draw.text([y, x], txt[i], colors[i])
y += fontW
newIm.save('999.jpg')
newIm.show()