一、解析iTunes播放列表
該項目在iTunes播放列表文件中查找重復的樂曲音軌,並繪制各種統計數據,如音軌長度和評分。你可以從查看iTunes播放列表格式開始,然后學習如何用Python提取這些文件的信息。為了繪制這些數據,要用到matplotlib庫。
在這個項目中,我們將學習以下主題:
- XML和屬性列表(p-list)文件;
- Python列表和字典;
- 使用Python的set對象;
- 使用numpy數組;
- 直方圖和散點圖;
- 用matplotlib庫繪制簡單的圖;
- 創建和保存數據文件。
所需模塊:
import re, argparse
import sys
from matplotlib import pyplot
import plistlib
import numpy as np
二、萬花斥資
我們可以用萬花尺玩具(如圖2-1所示)來繪制數學曲線。這種玩具由兩個不同尺寸的塑料齒輪組成,一大一小。小的齒輪有幾個孔。把鋼筆或鉛筆放入一個孔,然后在較大齒輪(內部有齒)內旋轉里面的小齒輪,保持筆與外輪接觸,可以畫出無數復雜而奇妙的對稱圖案。
在這個項目中,我們將用Python來創建動畫,像萬花尺一樣繪制曲線。我們的spiro.py程序將用Python和參數方程來描述程序的萬花尺齒輪的運動,並繪制曲線(我稱之為螺線)。我們可以將完成的畫圖保存為PNG圖像文件,並用命令行選項來指定參數或生成隨機螺線。
在這個項目中,我們將學習如何在計算機上繪制螺線。還將學習以下幾點:
- 用turtle模塊創建圖形;
- 使用參數方程;
- 利用數學方程來生成曲線;
- 用線段來畫曲線;
- 用定時器來生成圖形動畫;
- 將圖形保存為圖像文件。
import sys, random, argparse
import numpy as np
import math
import turtle
import random
from PIL import Image
from datetime import datetime
from fractions import gcd
三、Conway生命游戲
這個項目將創建一個N×N的細胞網格,通過應用Conway生命游戲的規則,模擬系統隨時間的演進。你將顯示每個時間段的游戲狀態,並提供一些方式將輸出保存到文件。你會設置系統的初始狀態,要么是隨機分布,要么是預先設計的圖案。
該模擬由以下幾部分組成:
在一維或兩維空間中定義的屬性;
在模擬中的每一步,改變這種屬性的數學規則;
隨着系統的演進,顯示或記錄系統狀態的方式。
在Conway生命游戲中的細胞可以處於ON或OFF狀態。游戲從一個初始狀態開始,其中每個細胞分配一個狀態,數學規則決定其狀態如何隨時間而改變。Conway生命游戲中令人驚奇的是,只有4個簡單的規則,系統演進會產生行為極其復雜的圖案,仿佛它們是活的。圖案包括“滑翔機”,即在網格上滑動,“眨眼”,即閃爍ON和OFF,甚至還有復制圖案。
當然,這個游戲的哲學意義也很重要,因為它們表明,復雜的結構可以根據簡單的規則演進,不必遵循任何一種預設的模式。
下面是該項目包含的一些主要概念:
- 利用matplotlib imshow來展示數據的二維網格;
- 利用matplotlib生成動畫;
- 使用numpy數組;
- 將%運算符用於邊界條件;
- 設置值的隨機分布。
因為生命游戲建立在9個方格的網格中,每個細胞有8個相鄰細胞,如圖3-1所示。模擬中的給定細胞(i, j)用二維數組[i][j]來存取,其中i和j分別是行和列的下標。在給定時間段,給定細胞的值取決於前一時間段它的鄰居的狀態。Conway生命游戲有4個規則。
1.如果一個細胞為ON,鄰居中少於兩個為ON,它變為OFF。
2.如果一個細胞為ON,鄰居中有兩個或3個為ON,它保持為ON。
3.如果一個細胞為ON,鄰居中超過3個為ON,它變為OFF。
4.如果一個細胞為OFF,鄰居中恰好有3個為ON,它變為ON。
所需模塊:
import sys, argparse
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
四、用Karplus-Strong算法產生音樂泛音
任何樂音的主要特點是它的音調,即頻率。這是每秒的振動數,單位是赫茲(Hz)。例如,從原聲吉他的第三根弦產生音符D,頻率是146.83赫茲。可以在計算機上創建頻率為146.83 Hz的正弦波,來模擬這種聲音,如圖4-1所示。
遺憾的是,如果在計算機上播放這個正弦波,聽起來不會像吉他或鋼琴。播放相同的音符時,是什么讓計算機的聲音與樂器如此不同呢?
在吉他上撥弦時,樂器產生了不同強度的混合頻率,如圖4-2的頻譜圖所示。剛撥弦時聲音最強,強度隨着時間推移而逐漸消失。撥動吉他D弦聽到的主要頻率稱為基本頻率,是146.83赫茲,但也會聽到該頻率的一些倍數,稱為泛音。任何樂器的聲音都由這種基本頻率和泛音組成,正是這種組合,讓吉他聽起來像吉他。
如你所見,在計算機上模擬撥弦樂器的聲音,要能同時生成基本頻率和泛音。訣竅是利用Karplus-Strong算法。
這個項目使用Karplus-Strong算法,產生5個類似吉他的音符,它們屬於一個音階(一系列相關的音符)。我們會讓產生這些音符的算法可視化,並將聲音保存為WAV文件。我們還會創建一種方式,隨機演奏它們,並學習如何做到以下幾點:
- 用Python的deque類實現環形緩沖區;
- 使用numpy數組和ufuncs;
- 用pygame播放WAV文件;
- 用matplotlib繪圖;
- 演奏五聲音階。
所需模塊:
import sys, os
import time, random
import wave, argparse, pygame
import numpy as np
from collections import deque
from matplotlib import pyplot as plt
五、類鳥群:仿真鳥群
仔細觀察一群鳥或一群魚,你會發現,雖然群體由個體生物組成,但該群體作為一個整體似乎有它自己的生命。鳥群中的鳥在移動、飛越和繞過障礙物時,彼此之間相互定位。受到打擾或驚嚇時會破壞編隊,但隨后重新集結,仿佛被某種更大的力量控制。
1986年,Craig Reynolds創造鳥類群體行為的一種逼真模擬,稱為“類鳥群(Boids)”模型。關於類鳥群模型,值得注意的是,只有3個簡單的規則控制着群體中個體間的相互作用,但該模型產生的行為類似於真正的鳥群。類鳥群模型被廣泛研究,甚至被用來制作群體的計算機動畫,如電影“蝙蝠俠歸來(1992)”中的行軍企鵝。
本項目將利用Reynolds的3個規則,創建一個類鳥群,模擬N只鳥的群體行為,並畫出隨着時間的推移,它們的位置和運動方向。我們還會提供一個方法,向鳥群中添加一只鳥,以及一種驅散效果,可以用於研究群體的局部干擾效果。類鳥群被稱為“N體模擬”,因為它模擬了N個粒子的動態系統,彼此之間施加作用力。
所需模塊:
import sys, argparse
import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.spatial.distance import squareform, pdist, cdist
from numpy.linalg import norm
六、ASCII文本圖形
在20世紀90年代,電子郵件占據着統治地位,圖形處理能力很有限,常見的做法是在電子郵件中包含一個簽名,它是由文本制作的圖形,一般稱為ASCII文本圖形(ASCII是一個簡單的字符編碼方案)。圖6-1展示了兩個例子。盡管因特網已經讓共享圖像容易很多,但出身卑微的文本圖形還沒有消失。
ASCII文本圖形的源頭是19世紀后期出現的打字機文本圖形。在20世紀60年代,計算機有了較弱的圖形處理硬件,ASCII被用於表示圖形。今天,ASCII文本圖形繼續作為因特網上的一種表現形式,你可以在網上找到各種創意的例子。
這個項目用Python創建一個程序,從圖像生成ASCII文本圖形。該程序讓你指定輸出(文本列數)的寬度,並設置垂直比例因子。它也支持兩種灰度值到ASCII字符的映射:稀疏的10級映射和更精細校正的70級映射。
要從圖像生成ASCII文本圖形,需要學習如何做到以下幾點:
- 用Pillow將彩色圖像轉換成灰度圖像,它是Python的圖像庫(PIL)的一個分支;
- 使用numpy計算灰度圖像的平均亮度;
- 用一個字符串作為灰度值的快速查找表。
所需模塊
import sys, random, argparse
import numpy as np
import math
from PIL import Image
七、照片馬賽克
照片馬賽克是一張圖像,它被分割成長方形的網格,每個長方形由另一張匹配“目標”的圖像(最終希望出現在照片馬賽克中的圖像)替代。換言之,如果從遠處看照片馬賽克,會看到目標圖像;但如果走近,會看到該圖像實際上包含許多較小的圖像。
這個迷題有解是因為人眼的工作方式。圖7-1中的低分辨率塊狀圖像,靠近了很難識別,但如果從遠處看,就知道它代表什么,因為看到的細節較少,就使得邊緣越光滑。照片馬賽克的原理是相似的。從遠處看,圖像看起來正常,但走近時,秘密揭開了:每“塊”都是一個獨特的圖像!
本項目中,我們將學習如何用Python創建照片馬賽克。我們將目標圖像划分成較小圖像的網格,並用適當的圖像替換網格中的每一小塊,創建原始圖像的照片馬賽克。你可以指定網格的尺寸,並選擇輸入圖像是否可以在馬賽克中重復使用。
在這個項目中,你將學習如何做到以下幾點:
用Python圖像庫(PIL)創建圖像;
計算圖像的平均RGB值;
剪切圖像;
通過粘貼另一張圖像來替代原圖像的一部分;
利用平均距離測量來比較RGB值。
所需模塊:
import sys, os, random, argparse
from PIL import Image
import imghdr
import numpy as np
八、三維立體畫
盯着圖8-1看一分鍾。除了隨機的點,你還看到別的什么嗎?圖8-1是一張三維立體畫,是制造三維假象的二維圖像。 三維立體畫通常包含一些重復的圖案,仔細觀察會被大腦解釋為三維。如果你看不到任何圖像效果,別擔心。我也花了一段時間,做了一些嘗試,才能看到(如果你在本書的印刷版本上看不到,請在這里嘗試彩色的版本:https://github.com/electronut/pp/images/。標題的腳注提示了你應該看到的圖像)。
本項目將用Python創建一張三維立體畫。下面是本項目涉及的一些概念:
線性間距和深度知覺;
深度圖;
用Pillow創建和編輯圖像;
用Pillow繪制圖像。
本項目生成的三維立體畫設計為用“牆眼”方式觀看。看到它們的最好方法,就是讓眼睛聚焦在圖像后面的點(如牆上)。有點神奇,一旦在這些圖案中感知到某樣東西,眼睛就會自動將它作為關注的焦點,如果三維圖像已“鎖定”,你很難對它視而不見的(如果你仍然無法看到圖像,請看Gene Levin的文章“How to View Stereograms and Viewing Practice” [1] ,或許有幫助)。
所需模塊
import sys, random, argparse
from PIL import Image, ImageDraw
九、理解OpenGL
本項目將創建一個簡單的程序,利用OpenGL和GLFW來顯示紋理貼圖的正方形。OpenGL為圖形處理單元(GPU)增加了一個軟件接口,而GLFW是一個窗口工具包。我們還將學習如何使用類似C語言的OpenGL着色語言(GLSL)來編寫着色器,即在GPU上執行的代碼。着色器為OpenGL中的計算帶來巨大的靈活性。我會展示如何用GLSL着色器來變換幾何圖形並上色,創建一個旋轉的、帶紋理的多邊形(如圖9-1所示)。
GPU經過優化,以並行的方式對大量數據反復地執行相同的操作,這讓它們在做這樣的工作時,比中央處理單元(CPU)快得多。除了渲染計算機圖形,它們也用於通用計算,現在有一些專門的語言讓你用GPU硬件完成這樣的工作。本項目將利用GPU、OpenGL和着色器。
Python是一種極好的“膠水”語言。對於其他語言(如C語言)編寫的庫,有大量的Python綁定,讓你在Python中使用它們。本章和第10章、第11章,將使用PyOpenGL,即OpenGL的Python綁定,來創建計算機圖形。
OpenGL是一個“狀態機”,有點像一個電器開關,有兩種狀態:開和關。如果從一種狀態切換到另一種,開關就保持在這種新狀態。然而,OpenGL比簡單的電器開關更復雜,它更像一個交換機,有許多開關和表盤。一旦更改特定設置的狀態,它就保持為關,直到你打開。如果一個 OpenGL調用綁定到某個對象上了,那隨后的相關調用都會發送給這個對象,直到解除綁定。
import OpenGL
from OpenGL.GL import *
import numpy, math, sys, os
import glutils
import glfw
十、粒子系統
在計算機圖形世界中,粒子系統是用許多小圖元(如點、線、三角形和多邊形)來表示的物體,如煙霧、火焰,甚至頭發,沒有明確的幾何形狀,因此很難用標准技術來建模。
例如,如何在計算機上制造一次爆炸效果?設想爆炸從空間中的一個點開始,然后向外擴張,作為一個快速擴大的、復雜的三維實體,隨時間而改變形狀和顏色。不誇張地說,嘗試建立數學模型就令人望而生畏。
但現在設想一下,爆炸包含一群細小的粒子,每個粒子有關聯的位置和顏色。爆炸開始時,粒子在空間中的一個點上聚成一圖。隨着時間的推移,它們根據一定的數學規則向外移動,並改變顏色,讓你定期繪制所有粒子,從而生成爆炸的動畫。利用好的數學模型、大量粒子,以及透明度和公告板(billboarding)這樣的渲染技術,可以創建逼真的效果,如圖10-1所示。
本項目會制定粒子運動的數學模型,將它表示為時間的函數,並利用圖形處理單元(GPU)的着色器進行計算。然后,會設計一種渲染方案,利用一種名為公告板的技術,它讓二維圖像一直面向觀眾,從而使二維圖像看起來像是三維的,用一種令人信服的方式來繪制這些粒子。還會用OpenGL着色器讓粒子旋轉,並生成動畫場景。你可以通過按鍵來打開或關閉各種效果,進行比較。
數學模型將設置每個粒子的初始位置和速度,並決定粒子如何隨時間運動。你可以讓每個紋理的黑色區域透明,利用正方形圖像創建火花,保持每個火花面向觀眾,使它們看起來有立體感。你會生成粒子的動畫,定期更新它們的位置,其亮度隨着時間的推移逐漸減弱。
下面是將要探索的一些概念:
- 制定噴泉粒子系統的數學模型;
- 利用GPU着色器計算;
- 利用紋理和公告板模擬復雜的三維對象;
- 利用OpenGL渲染功能,如混合、深度遮掩和Alpha通道,繪制半透明物體;
- 利用相機模型繪制三維透視圖。
十一、體渲染
MRI和CT掃描這樣的診斷過程會創建體數據,它由一組二維圖像來表示通過三維物體的截面。體繪制是一種計算機圖形技術,利用這種類型的體數據來構造三維圖像。雖然體繪制通常用於分析醫學掃描,但也可以用於地質、考古和分子生物學等學科,生成三維科學可視化效果。
由MRI和CT掃描記錄的數據通常采取N x ×N y ×N z 的三維網格形式,或N z 個二維“切片”,其中每個切片是大小為N x ×N y 的圖像。體繪制算法采用某種類型的透明度,來展示采集切片數據,並采用各種技術來強調被渲染物體中關注的部分。
本項目將探討名為“體光線投射(volume ray casting)”的體繪制算法,它充分利用圖形處理單元(GPU),用OpenGL着色語言(GLSL)的着色器來進行計算。代碼針對屏幕上的每個像素執行,並利用了GPU,其目的是有效地進行並行計算。利用二維圖像文件夾中包含的三維數據集切片,用體光線投射算法,構建體渲染圖像。我們還會實現一種方法,顯示在x、y、z方向上的二維切片數據,以便用戶可以通過箭頭鍵來滾動切片。鍵盤命令讓用戶在三維渲染和二維切片之間切換。
下面是本項目涉及的一些主題:
- 用GLSL進行GPU計算;
- 創建頂點和片段着色器;
- 表示三維立體數據,並使用體光線投射算法;
- 用numpy數組表示三維變換矩陣。