python中噪音是什么意思_Perlin噪声和Python的ctypes
最近在知乎上看了一篇關(guān)于用C++加速Python的短文,受益匪淺。同時也受到啟發(fā),撰寫此文作為以后的參考。
作為Python的用戶經(jīng)常碰到的一個問題就是速度太慢,一般來說速度下降的一個主要原因是來自多重的for循環(huán)。如何給現(xiàn)有的Python代碼加速其實(shí)是Python用戶的一門必修課。比較熟悉numpy的用戶,可以熟練地寫成矩陣化操作,這樣可以大大加速運(yùn)行的效率。這和MATLAB里多用矩陣操作而少用for循環(huán)是一個道理。但往往我們中的大多數(shù)并沒有高超的numpy技巧。即便是有,Python代碼的閱讀性可能反而會下降。就算退一步講,寫成了比較好的numpy的代碼也未必會比C/C++的代碼快。在不放棄Python語言的前提下,怎么用C語言來提速呢?方法有很多,前面的所指的短文已經(jīng)給出了一個答案。這里我再用一個例子做一個簡單的說明,希望對大家有所幫助。首先代碼都可以取到,https://github.com/yanfeit/PerlinNoise?github.com
關(guān)于Perlin噪聲,我就不詳細(xì)介紹。簡單地說來,Perlin噪聲具有光滑性,自然性和隨機(jī)性的特點(diǎn)。感興趣的讀者可以找到很多相關(guān)資料,在這里我推薦兩個,pvigier的GitHub site和Adrian's 的博客。Pvigier的Perlin噪聲是用numpy來實(shí)現(xiàn)的,讀者如果對自己numpy的技巧深感自信,可以去閱讀一下他寫的代碼。閱讀他的代碼之后,我們可以給自己兩個問題:我是否可以寫出這樣高度矩陣化操作的numpy代碼?
是否我們遇到的所用問題都可以用numpy矩陣化的操作來解決?
我想讀者心中可能也會犯嘀咕,確實(shí),高度矩陣化的操作需要程序員有高超的numpy技巧。反正我自愧不如,認(rèn)為我很難寫出那樣漂亮的代碼。我們再來看看Adrian的博客,這是篇博客文中的上乘之作, 是關(guān)于Perlin噪聲的一個詳細(xì)介紹,配合C#來實(shí)現(xiàn)。我想大多數(shù)讀者可能和我一樣,對寫成for循環(huán)的形式感到極度舒適。而閱讀這樣的代碼我想讀者們也是駕輕就熟吧。所以我首先制作了一個Perlin噪聲的C++代碼(其實(shí)只用到了C的成分),之后我們會使用ctypes來調(diào)用動態(tài)鏈接庫的代碼。
創(chuàng)建動態(tài)鏈接庫
$ mkdir build
$ cd build
$ cmake ..
$ make
$ mv ./lib/libperlinNoise.dylib ../python # Move library to the python folder.
$ cd ../python
$ python caltime.py # compare the time usage of numpy and C code.
為了快速測試一下效果,讀者可以嘗試執(zhí)行以上的代碼。
用了make之后我們會在/build/lib目錄下得到一個libperlinNoise.dylib的動態(tài)鏈接庫文件,在這個庫里面我們可以調(diào)用兩個函數(shù)。它們的接口如下所示,
// 你可以在./lib/PerlinNoise.h的文件中找到相應(yīng)代碼。// 純粹為了解釋一下Float#ifndef PRECISION#define PRECISION 1#endif#if PRECISION==1typedef float Float;
#elsetypedef double Float;
#endif// .....省略很多代碼......// lattice 是指生成梯度所在的格子的大小,x,y,z當(dāng)然指的是方向// res 是指resolution,解析度(像素)。這里我與Pvigier的定義是不同的。Float* perlinNoise3D(int lattice_x, int lattice_y, int lattice_z,
int res_x, int res_y, int res_z);
Float* perlinNoise2D(int lattice_x, int lattice_y, int res_x, int res_y);
兩個函數(shù)返回的是指向Float的指針,我選用了單精度的浮點(diǎn)數(shù)也就是float。這里面有個需要注意的地方,函數(shù)切記不要返回指向一個超過二維數(shù)組的指針,其實(shí)根本就沒有這樣的定義,具體請看這個帖子。有了libperlinNoise.dylib這個動態(tài)鏈接庫之后,剩下的任務(wù)就交給Python了。以下是我的代碼的一部分(借鑒了Pvigier的代碼,在./python/cppnoise.py中可以找到相應(yīng)的代碼),
# 我們所采用加速的方法,ctypes是build-in package
import ctypes
# 因?yàn)槲覀円祷刂羔?#xff0c;我覺得調(diào)用numpy下的這個包是我找到的比較簡單可行的方法
from numpy.ctypeslib import ndpointer
# ...省略...其余的包的調(diào)用....
def octavePerlin2d(lattice, res, octaves = 1, persistence=0.5):
# pass the dynamic library
lib = ctypes.CDLL('./libperlinNoise.dylib')
# get the 2d Perlin noise function
perlinNoise2D = lib.perlinNoise2D
# Need specify the types of the argument for function perlinNoise2D
perlinNoise2D.argtypes = (ctypes.c_int, ctypes.c_int,
ctypes.c_int, ctypes.c_int)
# This note is extremely useful to understand how to return a 2d array!
# https://stackoverflow.com/questions/43013870/
# how-to-make-c-return-2d-array-to-python?noredirect=1&lq=1
# We can never pass a 2d array, therefore return 1d array in a C function
perlinNoise2D.restype = ndpointer(dtype=ctypes.c_float,
shape = (res[0], res[1]))
noise = np.zeros(res)
frequency = 1
amplitude = 1
for _ in range(octaves):
temp = perlinNoise2D(ctypes.c_int(frequency*lattice[1]),
ctypes.c_int(frequency*lattice[0]),
ctypes.c_int(res[1]),
ctypes.c_int(res[0]) )
noise += amplitude * temp
frequency *= 2
amplitude *= persistence
return noise
相比于木盞的函數(shù),我這里相對來說復(fù)雜一點(diǎn)點(diǎn)。我們需要注意的是,我們得告訴函數(shù)傳入的參數(shù)的類型和返回的類型和大小,這點(diǎn)至關(guān)重要。
# 讀取動態(tài)鏈接庫,
lib = ctypes.CDLL('./libperlinNoise.dylib')
# 從句柄中拿到PerlinNoise2D的函數(shù)
perlinNoise2D = lib.perlinNoise2D
# 告訴函數(shù)傳入?yún)?shù)的個數(shù)和類型
perlinNoise2D.argtypes = (ctypes.c_int, ctypes.c_int,
ctypes.c_int, ctypes.c_int)
# 告訴函數(shù)返回的類型,是c_float。shape是optinal的。
perlinNoise2D.restype = ndpointer(dtype=ctypes.c_float,
shape = (res[0], res[1]))
# 調(diào)用的方法非常簡單。
temp = perlinNoise2D(ctypes.c_int(frequency*lattice[1]),
ctypes.c_int(frequency*lattice[0]),
ctypes.c_int(res[1]),
ctypes.c_int(res[0]) )
在Python中調(diào)用動態(tài)鏈接庫后得到的加速效果(當(dāng)然我在C++用了單精度的float),讀者可以自行修改成雙精度去測試一下。
$ python caltime.py
2D noise, numpy time consuming: 0.08261830806732177
3D noise, numpy time consuming: 4.525643992424011
2D noise, cpp time consuming: 0.007184123992919922
3D noise, cpp time consuming: 0.1645211935043335
我們可以發(fā)現(xiàn)C語言的代碼可以說快了將近10倍以上。
最后上個圖,以饗讀者。
總結(jié)
以上是生活随笔為你收集整理的python中噪音是什么意思_Perlin噪声和Python的ctypes的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 9. 信息安全标准与法规
- 下一篇: 计算机组成原理-算术逻辑单元(ALU)