1. 程式人生 > >影象轉字元畫

影象轉字元畫

這是我第一個正經的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()

666999