13日早晨,當(dāng)北京市民拉開窗簾時(shí)發(fā)現(xiàn),窗外雪花紛紛揚(yáng)揚(yáng)在空中飄落,而且越下越大,樹上、草地、屋頂、道路上,都落滿雪花。京城銀裝素裹,這是今冬以來北京迎來的第二場(chǎng)降雪。
一下雪,北京就變成了北平,故宮就變成了紫禁城。八萬張門票在雪花飄下來之前,便早已預(yù)訂一空。
(圖片來源:故宮官網(wǎng)版權(quán)歸故宮官網(wǎng)所有)
看著朋友圈、微博好友都在紛紛曬圖,小編只能羨慕不已。
不過,突然想到,可以通過Python將故宮的建筑物圖片,轉(zhuǎn)化為手繪圖(素描效果)。效果圖如下:
一、概念與原理
我們都知道手繪圖效果的特征主要有:
黑白灰色;邊界線條較重;相同或相近色彩趨于白色;略有光源效果
核心原理:利用像素之間的梯度值和虛擬深度值對(duì)圖像進(jìn)行重構(gòu),根據(jù)灰度變化來模擬人類視覺的模擬程度
把圖像看成二維離散函數(shù),灰度梯度其實(shí)就是這個(gè)二維離散函數(shù)的求導(dǎo),用差分代替微分,求取圖像的灰度梯度。常用的一些灰度梯度模板有:Roberts 梯度、Sobel 梯度、Prewitt 梯度、Laplacian 梯度。
以Sobel 梯度計(jì)算來解釋:
首先計(jì)算出、,然后計(jì)算梯度角?梯度方向及圖像灰度增大的方向,其中梯度方向的梯度夾角大于平坦區(qū)域的梯度夾角。如下圖所示,灰度值增加的方向梯度夾角大,此時(shí)梯度夾角大的方向?yàn)樘荻确较颉?duì)應(yīng)在圖像中尋找某一點(diǎn)的梯度方向即通過計(jì)算該點(diǎn)與其8鄰域點(diǎn)的梯度角,梯度角最大即為梯度方向。
二、圖像的數(shù)組形式與變換
其中,需要用到的方法:
Image.open( ):打開圖片
np.array( ): 將圖像轉(zhuǎn)化為數(shù)組
convert("L"):將圖片轉(zhuǎn)換成二維灰度圖片
Image.fromarray( ):將數(shù)組還原成圖像uint8格式
代碼如下:
fromPILimportImageimportnumpyasnpim=Image.open(r"C:UsersAdministratorDesktopgugong微信圖片_20190216152248.jpg").convert('L')a=np.asarray(im).astype('float')print(a.shape,a.dtype)(1080,608)float64#(1080,608)分別表示高度,寬度
三、圖像的手繪效果處理
實(shí)現(xiàn)思路步驟:
1、梯度的重構(gòu)
numpy的梯度函數(shù)的介紹
np.gradient(a) : 計(jì)算數(shù)組a中元素的梯度,f為多維時(shí),返回每個(gè)維度的梯度
離散梯度: xy坐標(biāo)軸連續(xù)三個(gè)x軸坐標(biāo)對(duì)應(yīng)的y軸值:a, b, c 其中b的梯度是(c-a)/2
而c的梯度是: (c-b)/1
當(dāng)為二維數(shù)組時(shí),np.gradient(a) 得出兩個(gè)數(shù)組,第一個(gè)數(shù)組對(duì)應(yīng)最外層維度的梯度,第二個(gè)數(shù)組對(duì)應(yīng)第二層維度的梯度。
代碼如下:
grad=np.gradient(a)grad_x,grad_y=gradgrad_x=grad_x*depth/100.#對(duì)grad_x值進(jìn)行歸一化grad_y=grad_y*depth/100.#對(duì)grad_y值進(jìn)行歸一化
2、構(gòu)造guan光源效果
設(shè)計(jì)一個(gè)位于圖像斜上方的虛擬光源光源相對(duì)于圖像的視角為Elevation,方位角為Azimuth建立光源對(duì)各點(diǎn)梯度值的影響函數(shù)運(yùn)算出各點(diǎn)的新像素值
其中:
np.cos(evc.el) :單位光線在地平面上的投射長(zhǎng)度
dx,dy,dz :光源對(duì)x,y,z三方向的影響程度
3、梯度歸一化
構(gòu)造x和y軸梯度的三維歸一化單位坐標(biāo)系;
梯度與光源相互作用,將梯度轉(zhuǎn)化為灰度。
4、圖像生成
具體詳情代碼如下:
fromPILimportImageimportnumpyasnpimportosimportjoinimporttimedefimage(sta,end,depths=10):a=np.asarray(Image.open(sta).convert('L')).astype('float')depth=depths#深度的取值范圍(0-100),標(biāo)準(zhǔn)取10grad=np.gradient(a)#取圖像灰度的梯度值grad_x,grad_y=grad#分別取橫縱圖像梯度值grad_x=grad_x*depth/100.#對(duì)grad_x值進(jìn)行歸一化grad_y=grad_y*depth/100.#對(duì)grad_y值進(jìn)行歸一化A=np.sqrt(grad_x**2+grad_y**2+1.)uni_x=grad_x/Auni_y=grad_y/Auni_z=1./Avec_el=np.pi/2.2#光源的俯視角度,弧度值vec_az=np.pi/4.#光源的方位角度,弧度值dx=np.cos(vec_el)*np.cos(vec_az)#光源對(duì)x軸的影響dy=np.cos(vec_el)*np.sin(vec_az)#光源對(duì)y軸的影響dz=np.sin(vec_el)#光源對(duì)z軸的影響b=255*(dx*uni_x+dy*uni_y+dz*uni_z)#光源歸一化b=b.clip(0,255)im=Image.fromarray(b.astype('uint8'))#重構(gòu)圖像im.save(end)defmain():xs=10start_time=time.clock()startss=os.listdir(r"C:UsersAdministratorDesktopgugong")time.sleep(2)forstartsinstartss:start=''.join(starts)sta='C:/Users/Administrator/Desktop/gugong/'+startend='C:/Users/Administrator/Desktop/gugong/'+'HD_'+startimage(sta=sta,end=end,depths=xs)end_time=time.clock()print('程序運(yùn)行了----'+str(end_time-start_time)+'秒')time.sleep(3)main()程序運(yùn)行了----43.01828205879955秒#一共35張圖片
最終效果圖對(duì)比:
最后,你自己動(dòng)手試試吧?通過此代碼為自己畫一張手繪圖,也可以為自己的家鄉(xiāng)或母校畫。
參考資料:
http://www.icourse163.org/learn/BIT-1001870002?tid=1001963001#/learn/announce
代碼鏈接:
https://pan.baidu.com/s/1E_aZTRQWOzGV-2GV_iH43w
提取碼:64z9
-
圖像
+關(guān)注
關(guān)注
2文章
1088瀏覽量
40516 -
梯度
+關(guān)注
關(guān)注
0文章
30瀏覽量
10333 -
python
+關(guān)注
關(guān)注
56文章
4802瀏覽量
84890
原文標(biāo)題:只需45秒,Python給故宮畫一組手繪圖!
文章出處:【微信號(hào):rgznai100,微信公眾號(hào):rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論