用Python實(shí)現(xiàn)圖像的手繪化

點(diǎn)擊原文地址以獲得更好的閱讀體驗(yàn)。

手繪風(fēng)圖片因其簡(jiǎn)約而典雅的線條,清晰而自然的紋理和充滿藝術(shù)的情趣感一直是許多人的熱寵。這種專注于圖形個(gè)性化和藝術(shù)化的表達(dá)方式深受人們的喜愛。

下面,我來(lái)介紹一下如何用Python代碼實(shí)現(xiàn)圖片的手繪化效果。

本文所用到的Python庫(kù):

PIL庫(kù)

PIL:Python Imaging Library,是Python一個(gè)強(qiáng)大而方便的圖像處理庫(kù)。不過(guò)PIL目前只支持到Python 2.7,而且從09年至今再也沒更新過(guò)
Pillow:PIL的一個(gè)派生分支,但如今已經(jīng)發(fā)展得比PIL本身更具活力,并且支持最新的Python3。

Numpy庫(kù)

Numpy:Numerrical Python, 是一個(gè)開源的Python科學(xué)計(jì)算庫(kù),可用來(lái)存儲(chǔ)和處理大型矩陣,據(jù)說(shuō)NumPy將Python相當(dāng)于變成一種免費(fèi)的更強(qiáng)大的MatLab系統(tǒng)。

在命令行使用PIP安裝:

pip install Pillow
pip install Numpy

然后通過(guò)

from PIL import Image
import numpy as np

就可以使用了

Image類的圖片模式

PIL中的Image類有9種不同圖片模式,分別為

  • 1 : 一位二值圖像

  • L : 8位灰色圖像

  • P : 8位彩色圖像

  • RGB:24位彩色圖像,紅綠藍(lán)三種色彩

  • RGBA : 32位彩色圖像,紅綠藍(lán)三種色彩加Alpha通道

  • CMYK : 32位彩色圖像,青、洋紅、黃、黑四種色彩的印刷四分色模式

  • YCbCr: 24位彩色圖像,彩色視頻格式

  • I : 32位整型灰色圖像

  • F : 32位浮點(diǎn)灰色圖像

在手繪化圖片前,我們要將圖片轉(zhuǎn)化為灰色圖像,進(jìn)行圖像的灰度化預(yù)處理。用PIL中的convert函數(shù)非常容易實(shí)現(xiàn):

img = img.convert("L")

模式“L”即為灰色圖像,它的每個(gè)像素用8個(gè)bit表示,0表示黑,255表示白,其他數(shù)字表示不同的灰度。

一般來(lái)說(shuō),圖像灰度化的方法有四種:

  • 分量法
    將彩色圖像中的三分量的亮度作為三個(gè)灰度圖像的灰度值,可根據(jù)應(yīng)用需要選取一種灰度圖像。
  • 最大值法
    將彩色圖像中的三分量亮度的最大值作為灰度圖的灰度值。
  • 平均值法
    將彩色圖像中的三分量亮度求平均得到一個(gè)灰度值。
  • 加權(quán)平均法
    根據(jù)重要性及其它指標(biāo),將三個(gè)分量以不同的權(quán)值進(jìn)行加權(quán)平均。

在PIL中,這個(gè)從“RGB”模式到“L模式的轉(zhuǎn)換公式為

L = R * 299/1000 + G * 587/1000+ B * 114/1000

這里,我以存儲(chǔ)位置為F:\python\Image-Freehand\中的tupian.jpg為例:


使用

Image.open(r'F:\python\Image-Freehand\tupian.jpg').convert('L')

將圖片tupian.jpg 轉(zhuǎn)換為灰色圖像,效果為:


數(shù)據(jù)的獲取與存儲(chǔ)

通過(guò)Numpy中的asarray函數(shù)將圖片的灰度值以浮點(diǎn)型矩陣的形式存儲(chǔ)起來(lái),再用gradient函數(shù)得出圖片灰度值的梯度

L=np.asarray(Image.open(r'F:\python\Image-Freehand\tupian.jpg').convert('L')).astype('float')
grad = np.gradient(L)

我們來(lái)觀察一下L矩陣

可以看出L是一個(gè)853*1280的二維浮點(diǎn)型矩陣,因此它的梯度grad里應(yīng)該有兩個(gè)數(shù)組矩陣,分別對(duì)應(yīng)兩層維度的梯度。
現(xiàn)取最外層維度梯度為x方向的梯度值grad_x,取第二層維度梯度值為y方向梯度值grad_y

grad_x, grad_y = grad

這時(shí)我們已經(jīng)取得了圖像的梯度值,就可以通過(guò)改變像素的梯度值來(lái)改變圖像的灰度變化,對(duì)圖像進(jìn)行重構(gòu)了

圖像的轉(zhuǎn)換

我們先設(shè)一個(gè)深度值depth,取值范圍為(0,100),然后利用深度調(diào)整x和y方向的梯度值。
我們使

grad_x = grad_x*depth/100.
grad_y = grad_y*depth/100.

深度值越小,重構(gòu)后的圖像梯度值越小,即圖像灰度值變化越小,畫面線條越少,整體更顯潔凈。

比如當(dāng)depth=1時(shí):

反之,深度值越大,重構(gòu)后的圖像梯度值越大,即圖像灰度值變化越大,畫面線條越多,整體更顯骯臟。

比如當(dāng)depth=100時(shí)

因此我們需要通過(guò)改變depth,找到最符合人類視覺遠(yuǎn)近程度的深度值。

經(jīng)過(guò)多次測(cè)試發(fā)現(xiàn),當(dāng)深度值為10左右時(shí),即圖像灰度梯度變?yōu)樵瓉?lái)的10%左右時(shí),畫面最接近手繪化效果。(當(dāng)然,對(duì)于不同的圖片,這個(gè)最佳深度值不一定相同)

在本文中我們?nèi)epth=10

制造光源效果

此時(shí)圖像的效果是這樣的:

類似版畫的效果,這是因?yàn)榇藭r(shí)的圖像還沒有光源效果,跟我們實(shí)際觀察事物的感覺不一樣,因此我們還需要為圖像制造光源效果。

如圖,我們先假設(shè)一個(gè)光源位于圖像斜上方,設(shè)俯視角為el,方位角為az,則單位光線在x,y,z方向上的投影長(zhǎng)度分別為:

dx = cos(el)*cos(az)
dy = cos(el)*sin(az)
dz = sin(el)

通過(guò)多次調(diào)整發(fā)現(xiàn),當(dāng)俯視角el=π/2.2, 方位角az=π/4時(shí)光照效果最好。(當(dāng)然對(duì)于不同圖像兩個(gè)角度的選取不一定相同)

實(shí)現(xiàn)代碼為:

el = np.pi/2.2                             
az = np.pi/4                              
dx = np.cos(el)*np.cos(az)              
dy = np.cos(el)*np.sin(az)              
dz = np.sin(el)

所以,此時(shí)圖像的灰度值變?yōu)?/p>

gd = 255*(dx*uni_x + dy*uni_y + dz*uni_z)

我們將這個(gè)過(guò)程叫做光源的歸一化

重構(gòu)圖像

由于灰度值的選取范圍為(0,255),為了避免數(shù)據(jù)越界,需要將生成的灰度值裁剪至0-255之間

gd = gd.clip(0,255)

由新的灰度值重構(gòu)圖像

im = Image.fromarray(gd.astype('uint8'))

其中uint8是一種數(shù)據(jù)類型

  • u : 正數(shù)
  • int : 整數(shù)
  • 8 : 8位信息,即最大值為255,最小值為0

這時(shí)圖像的手繪化效果已經(jīng)完成了

最后保存圖像:

im.save(r'F:\python\Image-Freehand\tupianHD.jpg')

完整代碼已經(jīng)托管到我的github倉(cāng)庫(kù)
https://github.com/Leotemp/Image-Freehand

本示例來(lái)源于北京理工大學(xué)嵩天老師的Python數(shù)據(jù)分析課程
老師講的特別好,在此安利給大家。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容