久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

兔年了,,利用AI風格化實現剪紙兔,、年畫兔、煙花兔

 TF男孩 2023-01-16 發(fā)布于山東

一,、圖像風格化簡介

說起圖像風格化(image stylization),,你可能會感覺到陌生。盡管這項技術,,已經深入你的生活很久了,。

專業(yè)名詞,有時候,,溝通起來不方便,。

記得高中時,我看見同桌帶了一個書包,。很特別,。我就問他這是什么材料的。他說是PP的,。我搖了搖頭。他又說,,就是聚丙烯,。當時我很自卑,他說了兩遍我依然不懂,,感覺我知識太貧乏了,。即便如此,我還是虛偽地點了點頭,。

多少年之后,。我才了解到,,原來聚丙烯的袋子從我出生時,我就見過了,,就是下圖這樣的:

從那一刻起,,我發(fā)誓,對于專業(yè)名詞,,我要做到盡量不提,。

但是不提,同行又以為我不專業(yè),。因此,,我現在就是,說完了通俗的,,再總結專業(yè)的,。我會說編織袋或者蛇皮袋,文雅一點可以稱為:聚丙烯可延展包裝容器,。

而對于圖像風格化,,其實就類似你的照片加梵高的畫作合成梵高風格的你。又或者你的照片直接轉為動漫頭像,。

風格化需要有兩個參數,。一個叫 content 原內容,另一個叫 style 風格參照,。兩者經過模型,,可以將原內容變?yōu)閰⒄盏娘L格。

舉個例子,。如果 content 是一只兔子,,style 是上面的聚丙烯編織袋,那么兩者融合會發(fā)生什么呢,?

那肯定是一個帶有編織袋風格的……兔子,!

上面的風格融合,多少有點下里巴人,。

我再來一個陽春白雪的,。讓兔子和康定斯基的抽象畫做一次融合。

看著還不錯,,雖然沒有抽象感,,但是起碼風格是有的。

大家想象一下,,在兔年來臨之際,,如果兔子和年畫、剪紙,、煙花這類春節(jié)元素融合起來,,會是怎樣的效果呢,?從技術上(不調用API接口)又該如何實現呢?

下面,,跟隨我的鏡頭,,我們來一探究竟(我已經探完了,不然不能有上面的圖),。

二,、技術實現講解

首先說啊,咱們不調用網絡API,。其次,,我們是基于開源項目。

調用第三方API,,會實時依附于服務提供商,。一般來說,它處于自主產品鄙視鏈的底層,。

我了解一些大牛,,尤其是領導,聲稱實現了很多高級功能,。結果一深究,,是調用了別家的能力。這類人,,把購買接口的年租費用,,稱為“研發(fā)投入”,。把忘記續(xù)費,,歸咎于“服務器故障”,。

那么,,鄙視鏈再上升一層,。就是拿國外的開源項目,,自己部署服務用。盡管這種行為依然不露臉。但是,這在國內已經算很棒的了。因為他們會把部署好的服務,,再賣給上面的大牛領導,然后還鄙視他只能調API,。

今天,我要使用的,,就是從開源項目本地部署這條路,。

因此,,你學會了也不要驕傲,這并沒有什么自主的知識產權,。學不會也不用自卑,,你還可以試試調用API,。

我們選用的開源項目就是TensorFlow Hub,。地址是 https://github.com/tensorflow/hub ,。

2.1 TensorFlow Hub庫

可以說我對 TensorFlow 很熟,而且是它的鐵桿粉絲,。鐵到我的昵稱“TF男孩”的TF指的就是 TensorFlow ,。

TensorFlow 已經很簡單和人性化了。簡單到幾十行代碼,,就可以實現數字識別的全流程(我都不好意寫這個教程),。

但是,它依然不滿足于此,。代碼調用已經夠簡單了,。但是對于訓練的樣本數據、設備性能這些條件,,仍然是限制普通人去涉足的門檻。

于是,,TensorFlow 就推出了一個 TensorFlow Hub 來解決上面的問題,。你可以利用它訓練好的模型和權重,自己再做微調,,以此適配成自己的成果,。這節(jié)省了大量的人力和物力的投入。

Hub 是輪轂的意思,。

這讓我們很容易就聯(lián)想到“重復造輪子”這個話題,。但是,它又很明確,,不是輪子,,是輪轂。這說明,,它把最硬的部件做好了,,你只需要往上放輪胎就行。到這里,,我開始感覺,,雖然我很討厭有些人說一句話,又是帶中文,,又是帶英文的,。但是,這個 Hub ,,很難翻譯,,還是叫 TensorFlow Hub 更為貼切。

2.2 加載image-stylization模型

如果你打算使用 hub 預訓練好的風格化模型,,自己不做任何改動的話,,效果就像下面這樣,。這是我搞的一個梵高《星空》風格的兔子:

而代碼其實很簡單,也就是下面幾行:

# 導入hub庫
import tensorflow_hub as hub
# 加載訓練好的風格化模型
hub_model = hub.load('https://v/google/magenta/arbitrary-image-stylization-v1-256/1')
# 將content和style傳入
stylized_image = hub_model(content_image, style_image)[0]
# 獲取風格化后的圖片并打印出來
tensor_to_image(stylized_image)

這,,看起來很簡單,。似乎人工智能的工作很容易干。

事實,,并非如此,。

我建議大家都來學習人工智能,利用成熟的代碼或工具,,解決生活中遇到的問題,。

但是,我不建議你著急轉行到人工智能的工作崗位中來,。

因為在學習過程中,,你會發(fā)現,相比于其他語言,,人工智能具有更多的網絡限制和基礎學科要求,。因此,作為使用體驗者和制作開發(fā)者,,會是兩個不同的心境,。

隨著下面的講解,上面的問題我們會逐個碰到,。

首先,,上面的 hub.load('https://v/……') 你就加載不下來。而這個地址,,正是圖像風格化的模型文件,。咔,晴天霹靂啊,,剛起頭就是挫折,。

下面,我們不改變網絡代理,,用正常的途徑解決,。TensorFlow 是谷歌的。因此他們很多項目的資源是共享的,。也就是說,,同一份資源會有多個入口。雖然 https://v/google/magenta/arbitrary-image-stylization-v1-256/1 無法訪問,,但是 https://storage./tfhub-modules/google/magenta/arbitrary-image-stylization-v1-256/1.tar.gz 是可以訪問的,。

技巧就是替換 v 為 storage./tfhub-modules 。并且在末尾加上后綴 .tar.gz ,。這樣,,就可以下載同一個文件了,。

下載完成之后,解壓文件,,然后指定加載路徑,。其實這一步操作,也是框架的操作,。它也是先下載到本地某處,,然后從本地加載。

比如,,我將 .tar.gz 解壓到同級目錄下,。然后調用 hub.load('image-stylization-v1-256_1') 即可完成 hub 的加載。

這就是我說的網絡限制,。

相比較而言,,Java 或者 Php 這類情況也會有,但是頻率沒有這么高,。

下面,,我們繼續(xù)。還會有其他驚喜

2.3 輸入圖片轉為tensor格式

hub_model = hub.load(……) 是加載模型,。我們是加載了圖像風格化的模型,。

賦值的名稱隨便起就行,上面我起的名是 hub_model ,。之所以說這句話,,是因為我發(fā)現有些人感覺改個名字,代碼就會運行不起來,。其實,,變一變,更有利于理解代碼,。而項目運行不起來,,向上帝祈禱不起作用,是需要看報錯信息的,。

如果完全不更改 hub 預置模型的話,,再一行代碼就完工了。

這行代碼就是 stylized_images = hub_model(content_image, style_image) ,。

這行代碼是把內容圖片 content_image 和風格參照圖片 style_image 傳給加載好的模型 hub_model ,。模型就會輸出風格化后的結果圖片stylized_images

哇哦,,瞬間感覺自己能賣API了,。

但是,,這個圖片參數的格式,卻并沒有那么簡單,。

前面說了,,TensorFlow Hub 是 TensorFlow 的輪轂,不是輪子,,更不是自動駕駛,。它的參數和返回值,都是一個 flow 流的形式,。

TensorFlow 中的 flow 是什么,?這很像《道德經》里的“道”是什么一樣。它們只能在自己的語言體系里能說清楚,。

但是在這里,,你只需要知道調用一個 tf.constant(……) ,或者其他 tf 開頭的函數,,就可把一個字符,、數組或者結構體,包裝成為 tensor flow 的格式,。

那么下面,,我們就要把圖片文件包裝成這個格式。

先放代碼:

import tensorflow as tf

# 根據路徑加載圖片,,并縮小至512像素,,轉為tensor
max_dim = 512
img = tf.io.read_file(path_to_img)
img = tf.image.decode_image(img, channels=3)
img = tf.image.convert_image_dtype(img, tf.float32)
shape = tf.cast(tf.shape(img)[:-1], tf.float32)
long_dim = max(shape)
scale = max_dim / long_dim
new_shape = tf.cast(shape * scale, tf.int32)
img = tf.image.resize(img, new_shape)
img = img[tf.newaxis, :]
tf_img = tf.constant(img)

首先,模型在訓練和預測時,,是有固定尺寸的,。比如,寬高統(tǒng)一是512像素,。

然后,,對于用戶的輸入,我們是不能限制的,。比如,,用戶輸入一個高度為863像素的圖,這時我們不能讓用戶裁剪好了再上傳,。應該是用戶上傳后,,我們來處理。

最后,,要搞成tensorflow需要的格式,。

上面的代碼片段,把這三條都搞定了。

read_file 從路徑讀入文件,。然后通過 decode_image 將文件解析成數組,。

這時,如果打印img,,具體如下:

shape=(434, 650, 3), dtype=uint8
array([[[219, 238, 245],
...,
[219, 238, 245]]
,
[[219, 238, 245],
...,
[219, 238, 245]]
])

shape=(434, 650, 3) 說明這是一個三維數組,,看數據這是一張650×434像素且具有RGB三個通道的圖片。其中的array是具體像素的數值,,在某個顏色通道內,,255表示純白,0表示純黑,。

接著 convert_image_dtype(img, tf.float32) 把img轉成了float形式,。

此時,img的信息為:

shape=(434, 650, 3), dtype=float32
array([[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]]
,
[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]]
])

為啥要把int轉為float呢,?初學者往往會有這樣的疑問,。

因為他們發(fā)現,只要是計算,,就要求搞成float類型,。就算明明是9個分類,也不能用1,、2,、3、4來表示,,也要轉為一堆的小數點,。

今天這個圖片的像素,也是如此,,255個色值多好辨認,,為什么非要轉為看不懂的小數呢,?

別攔著我,,我今天非要要解釋一下。

這并不是算法沒事找事,,假裝高級,。其實,這是為了更好地對應到很多基礎學科的知識,。

比如,,我在《詳解激活函數》中講過很多激活函數。激活函數決定算法如何做決策,,可以說是算法的指導思想,。

你看幾個就知道了。不管是sigmoid還是tanh,,它的值都是以0或者1為邊界的,。

也就是說你的模型做數字識別的時候,,計算的結果并不是1、2,、3,、4,而是0到1之間的小數,。最后,,算法根據概率得出屬于哪個分類。哎,,你看概率的表示也是0到1之間的數,。

除此之外,計算機的二進制也是0或者1,。芯片的計算需要精度,,整數類型不如小數精確。

各種原因,,導致還是浮點型的小數更適合算法的計算,。甚至,人工智能的體系中,,還具有float64類型,,也就是64位的小數。

變?yōu)樾抵?,后面就是將圖片數組做縮放,。根據數據的shape,找到最長的邊,。然后縮放到512像素以內,。

這就到了 resize(img, new_shape) 這行代碼。

到這一步時,,img的數據如下:

shape=(341, 512, 3), dtype=float32
array([[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]]
,
[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]]
])

原來的 (434, 650, 3) 圖片被重新定義成了 (341, 512, 3) ,。依然是3通道的色彩,,但是長寬尺寸經過計算,最大已經不超過512像素了。

為什么做縮放,?除了模型要求,,還要防止用戶有可能上傳一張1億像素的圖片,,這時你的服務器就冒煙了,。

(434, 650, 3) 代表的是一張圖。但是縱觀所有算法模型,,不管是 model.fit(train_ds) 訓練階段,,還是 model.predict(tf_imgs) 預測階段。就沒有處理單張圖片的代碼邏輯,全都是批量處理,。

它不能處理單張圖片的結構,,你別說它不人性化,不用跟他杠,。兄弟,,模型要的只是一個數組結構,它并不關心里面圖片的數量,。一張圖片可以是 ["a.png"] 這種形式,。

說到這里,我又忍不住想談談關于接口設計的話題了,。

我給業(yè)務方提供了一個算法接口能力,,就是查詢一張圖上存在的特定目標信息。我也是返回多個結果的結構,。盡管樣本中只有一個目標,。業(yè)務方非要返回一個。從長遠來講,,誰也不敢保證以后場景中只有一個目標,。我必須要如實返回,有一個返回一個,,有兩個返回兩個,,你可以只取第一個。但是,,結構肯定是要支持多個的,。

從成本和風險權衡的角度,從列表中取一條數據的成本,,要遠小于程序出錯或者失靈的風險,。但是業(yè)務方比較堅持返回一個就行。

后來,,他們讓我把圖片的base64返回值帶上 data:image/jpeg;base64, 以便于前端直接展示,。那一刻,我就明白了,,跟他們較這個真,,是我沖動了,。

而對于 TensorFlow 的要求,,你必須要包裝成批量的形式。我認為這很規(guī)范,。

這句代碼 img = img[tf.newaxis, :] 就是將維度上升一層,。可以將 1 變?yōu)?nbsp;[1] ,也可以將 [[1],[2]] 變?yōu)?nbsp;[[[1],[2]]] ,。

此時再打印img,,它已經變?yōu)榱巳缦陆Y構:

shape=(1, 341, 512, 3), dtype=float32
array([[[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]],
[[0.8588236, 0.9333334, 0.9607844],
...,
[0.8588236, 0.9333334, 0.9607844]]]]
)

shape=(1, 341, 512, 3) 表示有1張512×341的彩圖。那么,,這個結構它也可以承載100張這樣的圖,,那時就是shape=(100, 341, 512, 3)。這就做到了,,以不變應萬變,。

最后一步的 tf_img = tf.constant(img) ,作用是通過 tf.constant 把圖片數據,,包裝成 TensorFlow 需要的格式,。

這個格式,就可以傳給hub_model去處理了,。

經過 stylized_images = hub_model(tf_img_content, tf_img_style) 這行代碼的處理,。它會將處理結果放到 stylized_images 中。你馬上就可以看到融合結果了,。

不過,,好像也沒有那么簡單。這個結果的呈現,,實際上是圖片到tensor格式的逆向過程,。

我們下面就來處理它。

2.4 tensor格式結果轉為圖片

上一步經過 hub_model 轉化,,我們獲取到了 stylized_images ,。這是我們辛苦那么久的產物。你是否會好奇 stylized_images 到底是怎樣的結構,。

我們來打印一下:

[<tf.Tensor: shape=(1, 320, 512, 3), dtype=float32, numpy=
array([[[[0.31562978, 0.47748038, 0.7790847 ],
...,
[0.7430198 , 0.733053 , 0.6921962 ]],
[[0.76158 , 0.6912774 , 0.5468565 ],
...,
[0.69527835, 0.70888966, 0.6492392 ]]]]
, dtype=float32)>]

厲害了,,它是一個 shape=(1, 320, 512, 3) 形狀的 tf.Tensor 的數組。

不要和我說這些,,我要把它轉為圖片看結果,。

來,先上代碼:

import numpy as np
import PIL.Image

tensor = stylized_images[0]
tensor = tensor*255
tensor_arr = np.array(tensor, dtype=np.uint8)
img_arr = tensor_arr[0]
img = PIL.Image.fromarray(img_arr)
img.save(n_path)

相信有了上面圖片轉 tensor 的過程,,這個反著轉化的過程,,你很容易就能理解。

  • 第1步:取結果中的第一個 stylized_images[0] ,,那是 shape=(1, 320, 512, 3) ,。

  • 第2步:小數轉為255色值的整數數組 tensor*255、 np.array(tensor, dtype=np.uint8) ,。

  • 第3步:取出 shape=(1, 320, 512, 3) 中的那個1,,也就是512×320的那張圖,。

  • 第4步:通過 fromarray(img_arr) 加載圖片的數組數據,保存為圖片文件,。

我敢保證,,后面的事情,你只管享受就好了,。

源碼在這里 https://github.com/hlwgy/image-stylization ,。你可以親自運行試驗下效果。

不過,,多數人還是會選擇看完文章再試,。

三、一切皆可兔圖的效果

春節(jié)就要到了,,新的一年是兔年(抱歉,,我好像說過了)。

下面,,我就把小兔子畫面和一些春節(jié)元素,,做一個風格融合。

3.1 年畫兔

當然,,我只說我這個年齡段的春節(jié)場景,。

年畫,過年是必須貼的,,在我老家(倒裝句暴露了家鄉(xiāng)),。而且年畫種類很豐富。

有這樣的:

還有這樣的:

它們的制作工藝不同,,作用不同,,貼的位置也大不相同。

我最喜歡貼的是門神,。老家的門是木頭門,。搞一盆漿糊,拿掃帚往門上抹,。然后把年畫一放,,就粘上了。紙的質量不是很好,,漿糊又是濕的,,漿糊融合著彩紙還會把染料擴散開來。估計現在的孩子很少再見到了,。

我們看一下,,可愛的小兔子遇到門神年畫,會發(fā)生怎樣的反應:

你們知道年畫是怎么制作的嗎,?在沒有印刷機的年代,,年畫的制作完全靠手工。

需要先雕刻模子,,其作用類似于印章,。有用木頭雕刻的模具,印出來的就是木板年畫,。

好了,,雕刻完了。最終的模子是這樣的,。

模板里放上不同的染料,,然后印在紙上,年畫就出來了,。

如果兔子遇到這種木板模具,,會是什么風格呢?我有點好奇,,我們看一下:

我想,,這個圖,再結合3D打印機,,是不是就不用工匠雕刻了,。

3.2 剪紙兔

剪紙,也是過春節(jié)的一項民俗,。

我老家有一種特殊的剪紙的工藝,,叫“掛門箋”。當地叫“門吊子”,,意思就是吊在門下的旗子,。

其實這個習俗來源于南宋。那時候過年,,大戶人家都掛絲綢旗幟,,以示喜慶。但是普通百姓買不起啊,,就改成了彩紙,。

跟年畫比,這個工藝現在依然活躍,,農村大集還有賣的,。

如果小兔子遇到剪紙,會是什么風格呢,?揭曉一下效果:

3.3 煙花兔

說起煙花,,就不是哪個年齡段的專利了。現如今,,即便是小孩子,,也很喜歡看煙花,。

如果兔子遇到煙花,會產生什么樣的融合呢,?放圖揭曉答案:

確實很美麗,。

四、無限遐想

最后,,我仍然意猶未盡,。

我嘗試自己畫了個小兔子,和掘金的吉祥物們做了一個融合:

這……我感覺比較失落,。

但是,,轉念一想,其實作為抽象畫也可以,,反正大多數人都看不懂,。

我又融合了一張,裱起來,,打上落款,,好像也過得去。

上面的例子,,我們是 hub.load 了 https://v/……image-stylization-v1-256/2 這個模型,。

其實,你可以試試 https://v/……image-stylization-v1-256/1 這個模型,,它是一個帶有發(fā)光效果的模型,。

嗨,技術人,,不管你是前端還是后端,,如果春節(jié)沒事干,想跨界,、想突破,,試試這個人工智能的項目吧。搞個小程序,,給親友用一下,,也挺好的。

我是IT男,,一位講代碼過程中,,多少帶點人文氣息的編程表演藝術家。兼職中國TensorFlow框架嬰幼兒編程,,非官方認證的公益推廣大使,。

    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多