App下載

程序員如何使用Python Turtle+PIL 畫圖紀念黃家駒?【附源碼】

猿友 2021-06-30 16:21:26 瀏覽數 (5568)
反饋

6 月 30 日是 Beyond黃家駒逝世周年紀念日,對于編程獅W3Cschool小編和廣大70、80甚至90年代的人來說“Beyond”可以是一種情結可以是一種回憶也可以是一種精神上的能量,《再見理想》《Amani》《海闊天空》《光輝歲月》一首首膾炙人口的歌曲,鼓舞著一代人在逆境中成長。許多樂迷曾經說過,喜歡 Beyond 就是在紀念自己。紀念黃家駒,也像是在紀念自己的青春,家駒不僅是一代人的記憶,沒有什么能夠比 Beyond 的名字更能概括 Be-yond ———超越。今天我們來看看會 Python 編程的樂迷是如何致敬黃家駒的吧~

最終效果圖:

Python畫黃家駒最終效果

思路:

運用 PIL 的 Image 模塊與 turtle 模塊讀取并重新畫出圖像

就是讀取一張有人像的圖片,然后通過循環(huán)對比,記錄下人各行人像的像素坐標,然后再通過 turtle 畫出大概的人像輪廓。

Image 模塊有直接顯示輪廓的函數,而且對于從圖象中識別出人像,這個對于小白太難了,所以就選取黑白或者是色彩單一、含人像的圖像來識別。

步驟:

步驟 操作 用到的庫
1 讀取圖像,通過遍歷每一行像素記錄并對比,得到畫圖所需的人像‘坐標’ PIL
2 根據所得到的坐標,調用 turtle 庫畫圖 turtle

第一步,讀取圖片,獲得畫圖坐標

Python畫黃家駒第一步

讀取圖片如上,獲取坐標是逐行遍歷像素的過程,便利時記錄每一行像素中非白色(白色為背景色)的像素條的始末坐標(X1X2)。 對比時,當前像素與同行的下一個像素進行比較,如果兩個像素值不同,且有一像素為背景色,那么記錄非背景色的橫坐標。 記錄時,整張圖的數據暫時保存在一個列表中,該列表由 n 個列表組成(n 為圖像像素行數),這 n 個列表存著對應行的所有非背景色像素條的始末坐標。

源碼:

from PIL import Image
import turtle as t


def get_lst(img_path):
    imgf = Image.open(img_path)  # 讀取圖像
    global size
    print(size:= imgf.size) # 獲取圖像尺寸/大小
    pix = imgf.load()
    lst = [[] for i in range(size[1])] # 構造空列表
    for y in range(0, size[1]): # 從第一行開始循環(huán)
        index = 0
        for x in range(0, size[0]-1): # 循環(huán)第y行的每一個像素
            # 如果當前像素與下一個像素值不同且兩者有一為背景色,則記錄坐標
            if pix[x, y] != pix[x+1, y] and (255, 255, 255, 255) in [pix[x, y], pix[x+1, y]]:
                if index == 0: # index值為0說明是像素條起始坐標
                    lst[y].append([x+1, ])
                    index += 1
                else: # index值為1說明記錄的是像素條結束坐標
                    lst[y][-1].append(x)
                    index = 0
    return lst

第二步,畫圖

得到了每一個像素條的始末坐標后,就可以逐行畫圖了

源碼

def paint(lst):
    fontc = 'whitesmoke' # 右邊字的顏色
    manc = 'black' #'dimgrey' 人像的顏色
    t.setup(width=size[0]+40, height=size[1]) # 繪圖窗口大小
    t.screensize(bg='oldlace') # 畫布背景色
    t.bgpic(r'c:\\users\\pxo\\desktop\\bg.png') # 畫布背景圖
    t.speed(333) #畫畫速度 據說范圍[1,10]
    for y in range(0, size[1]):
        # 遍歷每一行
        t.pencolor(manc)
        for line in lst[y]:
            # 遍歷每一個像素條
            if line[0] > 364 and 144 < y < 495: # 這個是判斷是否是右邊的字
                t.pencolor(fontc)
            # 下面是畫像素條
            t.penup()
            t.goto(line[0]-size[0]//2, (size[1]-y)-size[1]//2)
            t.pendown()
            t.goto(line[1]-size[0]//2, (size[1]-y)-size[1]//2)
    t.mainloop()

開始:

if __name__ == '__main__':
    img_path = r'c:\\users\\pxo\\desktop\\jh.png' # 圖像地址
    lst = get_lst(img_path)
    paint(lst)

附上一張帶背景圖的效果

Python畫黃家駒第二步

這樣就實現了使用 Python Turtle+PIL 繪制黃家駒效果。如果還不過癮以下提供了另一種思路,具體查看源碼注釋↓

隨機線條實現方式:

源碼:

from PIL import Image
import turtle as t
from random import choice




def get_lst(img_path):
    imgf = Image.open(img_path)
    global size
    print(size:= imgf.size)
    pix = imgf.load()
    lst = [[] for i in range(size[1])]
    for y in range(0, size[1]):
        index = 0
        for x in range(0, size[0]-1):
            if pix[x, y] != pix[x+1, y] and (255, 255, 255, 255) in [pix[x, y], pix[x+1, y]]:
                if index == 0:
                    lst[y].append([y, x+1, ]) # 這里在每一個像素條的數據中加入了其縱坐標y
                    index += 1
                else:
                    lst[y][-1].append(x)
                    index = 0
    # 這里也改了,返回的數據列表的子元素是所有單獨的像素條,而不是某一行像素條的總和
    lt = []
    for i in lst:
        for j in i:
            if j:
                lt.append(j)
    return lt




def paint(lst):
    fontc = 'darkorange'
    manc = 'black' #'dimgrey'
    t.setup(width=size[0]+40, height=size[1]+40)
    t.screensize(bg='oldlace')
    #t.bgpic(r'c:\\users\\pxo\\desktop\\bg.png')
    t.speed(330)
    cnt = len(lst)
    lt = [i for i in range(cnt)] # 弄一個種子列表,理解為存取位置
    flst = []
    for i in range(cnt):
        del lt[lt.index(index:=choice(lt))] #獲取并刪除一個隨機位置
        line = lst[index]  # 從所有線條中得到一條隨機線條(像素條)
        y = line[0]
        x1, x2 = line[1], line[2]
        t.pencolor(manc)
        if x1 > 364 and 144 < y < 495:
            flst.append(line)
            continue
        t.penup()
        t.goto(x1-size[0]//2, (size[1]-y)-size[1]//2)
        t.pendown()
        t.goto(x2-size[0]//2, (size[1]-y)-size[1]//2)
    new_flst = sorted(flst[:-80], reverse=True)
    for line in new_flst:
        y = line[0]
        x1, x2 = line[1], line[2]
        t.pencolor(fontc)
        t.penup()
        t.goto(x1-size[0]//2, (size[1]-y)-size[1]//2)
        t.pendown()
        t.goto(x2-size[0]//2, (size[1]-y)-size[1]//2)
    t.hideturtle()
    t.mainloop()




if __name__ == '__main__':
    img_path = r'c:\\users\\pxo\\desktop\\jh.png'
    lst = get_lst(img_path)
    paint(lst)

附幾張畫到一半的圖

img

img

以上就是編程獅(w3cschool.cn)小編為你整理的《程序員如何使用 Python Turtle+PIL 畫圖繪制黃家駒?【附源碼】》全部內容,更多 IT 編程技術文章請關注W3C技術頭條。

如果你也想擁有這種能力,你也許需要先掌握以下技能:

1 人點贊