Skynet

          ---------- ---------- 我的新 blog : liukaiyi.cublog.cn ---------- ----------

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            112 Posts :: 1 Stories :: 49 Comments :: 0 Trackbacks


          http://www.cnpython.org/docs/100/p_19.html


          1   影像與圖形資料的處理

          上一回我們談過了圖形介面程式的撰寫,這一次我們要討論圖形 (影像) 本身的處理,而討論的內容將會集中在 Python Imaging Library (PIL) 這一套程式庫上。

          PIL 是 Python 下最有名的影像處理套件,由許多不同的模組所組成,並且提供了許多的處理功能,允許我們在簡單的 Python 程式裡進行影像的處理。使用像 PIL 許樣的程式庫套件可以幫助我們把精力集中在影像處理的工作本身,避免迷失在底層的演算法裡面。

          由於影像處理牽涉到了大量的數學運算,因此 PIL 中有許多的模組是用 C 語言所寫成的,以提昇處理的效率。不過,在使用的時候,我們當然不必在意這樣的問題,只管放心地用就是了。

          1.1   PIL 能為你作的事

          PIL 具備 (但不限於) 以下的能力:

          • 數 十種圖檔格式的讀寫能力。常見的 JPEG, PNG, BMP, GIF, TIFF 等格式,都在 PIL 的支援之列。另外,PIL 也支援黑白、灰階、自訂調色盤、RGB true color、帶有透明屬性的 RBG true color、CMYK 及其它數種的影像模式。相當齊全。
          • 基本的影像資料操作:裁切、平移、旋轉、改變尺寸、調置 (transpose)、剪下與貼上等等。
          • 強化圖形:亮度、色調、對比、銳利度。
          • 色彩處理。
          • PIL 提供十數種濾鏡 (filter)。當然,這個數目遠遠不能與 Photoshop® 或 GIMP® 這樣的專業特效處理軟體相比;但 PIL 提供的這些濾鏡可以用在 Python 程式裡面,提供批次化處理的能力。
          • PIL 可以在影像中繪圖製點、線、面、幾何形狀、填滿、文字等等。

          接下來,我們開始一步一步地對 Python/PIL 的影像處理程式設計進行討論。

          2   轉換圖檔格式

          市面上有許多影像處理程式,一般人最常用它們來處理的工作大概就是圖檔格式轉換了;這是影像處理軟體最基本的功能,PIL 當然也要支援。

          假設我們有一個 JPG 檔案,名字叫作 sample01.jpg,那麼,以下的程式會把這個檔案載入 Python:

          >>> import Image

          >>> im = Image.open( "sample01.jpg" )



          im 這個物件是由 Image.open() 方法所產生出來的 Image 物件。我們可以用 Image 物件內的屬性來查詢關於此檔案的資訊:

          >>> print im.format, im.size, im.mode

          JPEG (2288, 1712) RGB



          格 式字串放在 format 屬性裡,尺寸放在 size 屬性裡,而 (調色盤) 模式放在 mode 屬性裡。從以上的執行結果,可以看出來我們讀的確實是一個 JPEG 檔案,檔案的尺寸是 2288 像素寬、1712 像素高,調色盤是 RGB 全彩模式。

          既然我們已經把圖檔讀入了 Python,要處理它就簡單了。利用 Image 類別的 save() 方法,可以把檔案儲存成 PIL 支援的格式:

          >>> im.save( "fileout.png" )



          如果圖檔很大,這會花上一點時間。Image.save() 方法會根據欲存檔的副檔名,自動判斷要存圖檔的格式 (剛剛我們用的 open() 函式也會這樣作)。

          save() 可以指定存檔格式。在以下的例子裡,我們把存檔格式指定為 JPEG:

          >>> im.save( "fileout.png", "JPEG" )



          這時候副檔名是無所謂的。

          只處理一兩個檔案的時候,使用 Python 直譯器就相當合適。然而若要處理一大群檔案,譬如把一整個目錄的 JPEG 檔轉換為 PNG 檔,那麼寫成一個程式檔會比較方便,例如:

          #!/usr/bin/env python



          from glob import glob

          from os.path import splitext

          import Image



          jpglist = glob( "python_imaging_pix/*.[jJ][pP][gG]" )



          for jpg in jpglist:

          im = Image.open(jpg)

          png = splitext(jpg)[0]+".png"

          im.save(png)

          print png





          只要在一個放了 *.jpg 或 *.JPG 檔案的目錄裡面執行這個指令稿,它就會把所有的 JPEG 檔轉成 PNG 檔案:

          $ ./convertdir.py

          file0001.png

          file0002.png

          .

          .

          file9999.png



          既然 PIL 會從檔名偵測常用的檔案格式,存檔時我們通常都不會指定存檔格式。

          然 而,依據檔案格式的不同,save() 方法提供了不同的選項參數。以 JPEG 而言,它可以接受 quality (從 1 到 100 的整數,預設為 75)、optimize (真假值) 及 progression (真假值)。在以下的例子裡,我們以 100 的 quality 來儲存 JPEG 檔案:

          >>> im.save( "quality100.jpg", quality=100 )



          要訣

          PIL 也支援 EPS (Encapsulate PostScript) 格式的寫入。TeX 的使用者可以利用 PIL 來簡單地把圖檔轉成 EPS 以供 TeX compiler 使用。

          3   改變影像與製作縮圖

          在了解了基本的圖檔轉換之後,我們來看看如何對影像進行尺寸方面的修改。PIL 對 Image 物件提供了 resize 方法,以執行影像的縮放工作。用我們的 sample01.jpg 檔案來當例子:

          >>> im = Image.open( "sample01.jpg" )

          >>> print im.size

          (2288, 1712)

          >>> width = 400

          >>> ratio = float(width)/im.size[0]

          >>> height = int(im.size[1]*ratio)

          >>> nim = im.resize( (width, height), Image.BILINEAR )

          >>> print nim.size

          (400, 299)

          >>> nim.save( "resized.jpg" )



          然後我們就會得到比較小的 resized.jpg:

          python_imaging_pix/resized.jpg

          resize() 這個方法會傳回一個新的 Image 物件,所以舊的 Image 不會被更動。resize() 接受兩個參數,第一個用來指定變更後的大小,是一個雙元素 tuple,分別用以指定影像的寬與高;第二個參數可以省略,是用來指定變更時使用的內插法,預設是 Image.NEAREST (取最近點),這裡我們指定為品質比較好的 Image.BILINEAR。

          resize() 可以把影像放大縮小,在使用時一定要傳入寬與高。上面的程式會先限定新影像的寬,再根據舊影像的長寬比例來算出新影像的高應該是多少,最後把尺寸值傳入 resize() 去。由此可知,resize() 是允許我們不等比例縮放的:

          >>> width = 400

          >>> height = 100

          >>> nim2 = im.resize( (width, height), Image.BILINEAR )

          >>> nim2.save( "resize2wide.jpg" )



          會得到形狀奇怪的縮圖:

          python_imaging_pix/resize2wide.jpg

          我們可以任意改變新影像的尺寸值。

          另一個常用的操作是旋轉;rotate() 方法可以用來旋轉影像。它取兩個參數,第一個參數是一個逆時針的度數,第二個參數則也是影像處理時的內插法,可省略:

          >>> nim3 = nim.rotate( 45, Image.BILINEAR )

          >>> nim3.save( "rotated.jpg" )



          rotate() 並不會改變影像的尺寸 (dimension),所以你會看到:

          python_imaging_pix/rotated.jpg

          出現了黑邊。如果我們想要連影像尺寸一起變動,得要改用 transpose() 方法:

          >>> nim4 = nim.transpose( Image.ROTATE_90 )

          >>> nim4.save( "transposed90.jpg" )



          結果是:

          python_imaging_pix/transposed90.jpg

          transpose() 方法接受 Image.FLIP_LEFT_RIGHT, Image.FLIP_TOP_DOWN, ROTATE_90, ROTATE_180, ROTATE_270 等五種參數;其中後三種的旋轉均為逆時針。rotate() 方法會對像素資料進行內插;而 transpose() 則只是轉置像素資料,所以沒有內插參數可以設定,也不會影響影像的品質。

          縮放與旋轉是最常用的兩個操 作,而在其中,縮圖的製作可能是特別常用的;PIL 對縮圖提供了一個方便的 thumbnail() 方法。thumbnail() 會直接修改 Image 物件本身,所以速度能比 resize() 更快,也消耗更少的記憶體。它不接受指定內插法的參數,而且只能縮小影像,不能放大影像;用法是:

          >>> im = Image.open( "sample01.jpg" )

          >>> im.thumbnail( (400,100) )

          >>> im.save( "thumbnail.jpg" )

          >>> print im.size

          (133, 100)



          thumbnail() 在接受尺寸參數的時候,行為與 resize() 不同;resize() 允許我們不等比例進行縮放,但 thumbnail() 只能進行等比例縮小,並且是以長、寬中比較小的那一個值為基準。因此,上面的程式所作出的 thumbnail.jpg 變成了 133*100 的小圖片:

          python_imaging_pix/thumbnail.jpg

          有了這些操作,我們可以很輕易地執行影像管理的任務。

          4   修改圖形內容

          除了可以針對圖形的尺寸作變更之外,PIL 更提供我們變更影像內容的能力。這樣,我們就不只能對影像進行管理,而能更進一步地利用程式來把影像的內容改成我們想要的樣子。

          我們從「貼圖」開始:

          >>> baseim = Image.open( "resized.jpg" )

          >>> floatim = Image.open( "thumbnail.jpg" )

          >>> baseim.paste( floatim, (150, 50) )

          >>> baseim.save( "pasted.jpg" )



          利用 paste() 方法,把之前作的 thumbnail.jpg 貼到 resized.jpg 裡面去:

          python_imaging_pix/pasted.jpg

          此種用法的 paste() 方法要求兩個參數,第一是要貼上的 Image,第二是要貼上的位置。第二個參數有三種指定的方式:

          • None:不指定位置與尺寸,那麼 pasted() 會假設要貼上的 Image 與被貼上的 Image 的尺寸完全相同。
          • (left, upper):雙元素 tuple。pasted() 會把要貼上的 Image 的左上角對齊在指定的位置。
          • (left, upper, right, lower):四元素 tuple。paste()` 除了會把 Image 的左上角對齊外,也會對齊右下角。不過基本上這種寫法和上面那一種一樣,因為 paste() 要求要貼上的影像與這裡指定的尺寸一致,所以不可能出現不同的兩組 right, lower。

          除了「貼圖」之外,我們還可以對影像的內容進行裁切:

          >>> im = Image.open( "sample01.jpg" )

          >>> nim = im.crop( (700, 300, 1500, 1300) )

          >>> nim.thumbnail( (400,400) )

          >>> nim.save( "croped.jpg" )



          (因為裁切之後的圖形還是大了點,所以再縮圖一次) 得到的結果是:

          python_imaging_pix/croped.jpg

          crop() 接受的 box 參數指定要裁切的左、上、右、下四個邊界值,形成一個矩形。

          除了剪貼之外,PIL 還可以使用內建的濾鏡 (filter) 作一些特效處理。這些濾鏡都放在 ImageFilter 模組裡面,使用前要先匯入這個模組:

          >>> import ImageFilter



          我們用個例子,對剛剛裁切的 "No Riding" 禁止牌作 20 次 blur (糊化),來看看 PIL 濾鏡的效果:

          >>> im = Image.open( "croped.jpg" )

          >>> nim = im

          >>> for i in range(20): nim = nim.filter( ImageFilter.BLUR )

          ...

          >>> nim.save( "blured.jpg" )



          你應該看不出來它是 "No Riding" 了吧:

          python_imaging_pix/blured.jpg

          使用濾鏡的基本語法是:

          newim = im.filter( ImageFilter.FILTERNAME )



          其 中 FILTERNAME 是 PIL 中支援的濾鏡名稱,目前有:BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, SHARPEN,此處就不一一介紹了,但建議你可以自己來把每一個濾鏡都試試看。

          利用濾鏡,我們可以對同一類的影像進行相同的特效處理。當然,影像特效需要很精細的調整,在自動化作業中通常只能達到很粗略的效果;但 PIL 既然提供了,我們的自動程序就擁有更多的工具可以使用。

          5   用 PIL 製作新影像

          除了對已存在的影像進行編修之外,從零開始建立新影像也是很重要的工作。PIL 中的 ImageDraw 模組提供給我們繪製影像內容的能力。在使用 ImageDraw 之前,要先建立好空白的新影像:

          >>> import ImageDraw

          >>> im = Image.new( "RGB", (400,300) )

          >>> draw = ImageDraw.Draw( im )



          最 後建出來的 draw 是一個 ImageDraw 物件會提供各種繪製影像的方法。針對幾何圖形,draw 物件提供 arc() (弧線)、chord() (弦)、line() (線段)、ellipse() (橢圓)、point() (點)、rectangle() (矩形) 與 polygon() (多邊形)。不過,我們不準備討論幾何圖形的繪製;相信這些方法的使用對一般人來說應該都很直覺才是。

          要訣

          你 可以在指令行輸入 pydoc ImageDraw.ImageDraw.<<methodname>> 來查詢上述方法 (<<methodname>>) 的說明,譬如 pydoc ImageDraw.ImageDraw.line。

          這裡要介紹的不是幾何圖形,而是文字的繪製。我們要再介紹一個模組:ImageFont,並且以實例來說明如何用 PIL 「寫字」:

          >>> import Image, ImageDraw, ImageFont

          >>> font = ImageFont.truetype( "

          ... "/usr/share/fonts/truetype/freefont/FreeMono.ttf", 24 )

          >>> im = Image.new( "RGB", (400,300) )

          >>> draw = ImageDraw.Draw( im )

          >>> draw.text( (20,20), "TEXT", font=font )

          >>> im.save( "text.jpg" )



          這樣就在一個黑色底圖上用白筆寫了 "TEXT" 四個大字:

          python_imaging_pix/text.jpg

          接 著一一說明剛剛作的動作。首先我們用 ImageFont 的 truetype() 函式建立了一個 TrueType 字型,大小設定為 16 點。truetype() 函式的第一個參數必須是字型檔的搜尋路徑,第二個參數是字型的點數。然後依序建立影像物件與 draw 物件。寫字的動作用 draw 物件的 text() 方法來完成,它接受兩個參數,分別是文字的左上角點、字串,另外可以用 font 選項來指定所使用的字型 (若不指定,便使用預設字型)。

          在 1.1.4 版之前,PIL 是只能使用點陣字型的。現在 PIL 加入了 TrueType 向量字型的支援,對於要「寫字」的人來說實在是一大福音。對點陣字來說,想改變字型的大小得要更換字型才作得到,但 TrueType 就沒有這個限制。如果我們想要寫出兩串不同大小的文字,這樣作就可以了:

          >>> largefont = ImageFont.truetype( "

          ... "/usr/share/fonts/truetype/freefont/FreeMono.ttf", 48 )

          >>> smallfont = ImageFont.truetype( "

          ... "/usr/share/fonts/truetype/freefont/FreeMono.ttf", 24 )

          >>> im = Image.new( "RBG", (400,300) )

          >>> draw = ImageDraw.Draw( im )

          >>> draw.text( (20,20), "SmallTEXT", font=smallfont )

          >>> draw.text( (20,120), "LargeTEXT", font=largefont )

          >>> im.save( "multitext.jpg" )



          結果如:

          python_imaging_pix/multitext.jpg

          以上就是在 PIL 裡建立文字圖形的方法。

          最後,我們要說明如何改變繪製圖形 (文字) 時的顏色;繪圖時畫筆的顏色是透過 draw 物件的 ink 屬性來改變的:

          >>> draw.ink = 0 + 255*256 + 0*256*256



          以上會把畫筆設成綠色。ink 值必須要是一個整數,其值由色彩的 RGB 值算出。舉幾個 ink 值的例子:

          • 紅色的 ink 值應設為 255(R) + 0(G)*256 + 0(B)*256*256,
          • 藍色的 ink 值應設為 0(R) + 0(G)*256 + 255(B)*256*256,
          • 靛色的 ink 值應設為 0(R) + 255(G)*256 + 255(B)*256*256

          所設定的 ink 會影響所有後續的繪圖動作。

          6   結語

          本文介紹了方便好用的 PIL 套件,可以讓我們用 Python 撰寫影像處理的程式。我們對圖檔的格式處理、尺寸處理以及內容的編修都作了討論,最後也說明如何從零開始創作一個影像。

          對網頁程式來說,動態產生簡單的影像是特別有用的功能,可以用來補足 HTML 與 CSS 的不足之處。利用 PIL 來執行批次影像處理的工作,更能省去我們許多的操作時間。相信讀者能從其中發現它所提供的生產力。


             



          整理 www.aygfsteel.com/Good-Game
          posted on 2009-11-28 00:10 劉凱毅 閱讀(9340) 評論(0)  編輯  收藏 所屬分類: pythonimage
          主站蜘蛛池模板: 仁寿县| 彭阳县| 泗洪县| 盱眙县| 土默特左旗| 九江市| 江川县| 连山| 威宁| 班戈县| 清原| 南乐县| 张家港市| 肃北| 远安县| 庆安县| 贵港市| 尚志市| 石泉县| 黄浦区| 大荔县| 固阳县| 雷州市| 呼图壁县| 响水县| 上高县| 九龙县| 旬邑县| 四子王旗| 怀宁县| 磐安县| 辰溪县| 永顺县| 潞西市| 修文县| 南乐县| 凌海市| 连山| 盈江县| 泰和县| 紫云|