网传梅姨照片竟然是电脑合成的!仅需 100 行代码,你也能做到!
近日,有關人販子“梅姨”的圖片在朋友圈以及網絡平臺熱傳,所有人都以為這是一張官方發布的照片,于是紛紛在朋友圈轉發。
但是當天下午,公安部兒童失蹤信息緊急發布平臺曾發布消息稱,“梅姨”的第二張畫像非官方公布信息,CCSER不是公安機關官方權威平臺。
后來更是被爆料出CCSER其實是一個民間民間互助平臺,并非官方組織。
廣東省公安廳未邀請專家對"梅姨"進行二次畫像。那么這張彩色照片到底是怎么來的呢?
原來是今年3月份,因接觸過‘梅姨’的人認為此前‘梅姨’畫像不像,于是邀請了畫像專家林宇輝對進行了第二次畫像。
林宇輝說,通過與“梅姨”同居兩年的當地老人及其女兒進行溝通,畫出了這一張新的黑白照片。
這個林宇輝專家,在震驚中外的章瑩穎案件中,根據三段模糊的遠距離視頻,畫出嫌疑犯相貌。嫌疑犯抓獲后,發現其長相與畫上相似度達80%
有熱心人士看到這張新畫的黑白畫像后,用電腦合成了藍底的彩色“梅姨”畫像,發給了被拐兒童家屬。于是兒童家屬把這個彩色的畫像發布到社交平臺上和媒體手上。
后來被CCSER使用,加了二維碼,在朋友圈傳播開來。
新聞中說,彩色照片是通過黑白照片經過電腦合成的,那么,計算機在合成的時候,背后的技術原理是什么呢?
照片上色技術
這種技術被稱之為"圖像彩色化",這項技術目前已經非常成熟了,廣泛應用于各個領域,比較普遍的就是照片修復。
目前也有很多這樣的網站,下圖就是我們在https://colourise.sg/ 網站上,上傳了"梅姨"的黑白照,經過人工智能處理后,獲得的彩色照片。
提到人工智能為照片上色,不得不提的一個技術就是GAN(生成對抗網絡)。
生成式對抗網絡(GAN)是近年來大熱的深度學習模型。
GAN的基本原理其實非常簡單,這里以生成圖片為例進行說明。假設我們有兩個網絡,G(Generator)和D(Discriminator)。正如它的名字所暗示的那樣,它們的功能分別是:
G是一個生成圖片的網絡,它接收一個隨機的噪聲z,通過這個噪聲生成圖片,記做G(z)。
D是一個判別網絡,判別一張圖片是不是“真實的”。它的輸入參數是x,x代表一張圖片,輸出D(x)代表x為真實圖片的概率,如果為1,就代表100%是真實的圖片,而輸出為0,就代表不可能是真實的圖片。
在訓練過程中,生成網絡G的目標就是盡量生成真實的圖片去欺騙判別網絡D。而D的目標就是盡量把G生成的圖片和真實的圖片分別開來。這樣,G和D構成了一個動態的“博弈過程”。
最后博弈的結果是什么?在最理想的狀態下,G可以生成足以“以假亂真”的圖片G(z)。對于D來說,它難以判定G生成的圖片究竟是不是真實的,因此D(G(z)) = 0.5。
這樣我們的目的就達成了:我們得到了一個生成式的模型G,它可以用來生成圖片。
那么,如何利用GAN技術為圖片上色呢?
這要看下目前人工給圖片上色的過程:
對照片的歷史、地理、文化背景進行深入研究,以推斷出合適的顏色;
用 Photoshop 等軟件工具對黑白圖像進行上色。
同樣,計算機程序也需要完成兩項任務:
識別黑白照片中的目標并基于之前見過的照片推斷出適合目標的顏色;
給黑白照片上色
接下來我們直接上代碼,代碼參考自:https://zhuanlan.zhihu.com/p/70192339
上色實戰
上色的首要條件就是對圖片進行預處理:
class?PairImageDataset(data.Dataset):????def?__init__(self,?path):
????????files?=?os.listdir(path)
????????self.files?=?[os.path.join(path,?x)?for?x?in?files]
????def?__len__(self):
????????return?len(self.files)
????def?__getitem__(self,?index):
????????img?=?Image.open(self.files[index])
????????yuv?=?rgb2yuv(img)
????????y?=?yuv[...,?0]?-?0.5
????????u_t?=?yuv[...,?1]?/?0.43601035
????????v_t?=?yuv[...,?2]?/?0.61497538
????????return?torch.Tensor(np.expand_dims(y,?axis=0)),?torch.Tensor(
????????????np.stack([u_t,?v_t],?axis=0))
這段小巧的代碼,就是我們定義的數據輸入器,使用pytorch的dataset API編寫。通過讀取圖片,RGB轉到YUV,然后分離Y和UV通道,就可以構建我們的輸入數據了!
在之前我寫的30行代碼自動上色的程序里面,我們用很少的代碼實現了一個自動上色程序,這次使用GAN方法略顯復雜,但實際代碼并不多:
train_ds?=?PairImageDataset(args.training_dir)????logging.info('loaded?dataset?from:?{},?data?length:?{}'.format(args.training_dir,?train_ds.__len__()))
????train_dataloader?=?data.DataLoader(train_ds,?batch_size=args.batch_size,?shuffle=True,?num_workers=0)
????i?=?0
????adversarial_loss?=?torch.nn.BCELoss()
????optimizer_G?=?torch.optim.Adam(G.parameters(),
???????????????????????????????????lr=args.g_lr,
???????????????????????????????????betas=(0.5,?0.999))
????optimizer_D?=?torch.optim.Adam(D.parameters(),
???????????????????????????????????lr=args.d_lr,
???????????????????????????????????betas=(0.5,?0.999))
????for?epoch?in?range(start_epoch,?args.epoch):
????????for?i,?(y,?uv)?in?enumerate(train_dataloader):
????????????try:
????????????????#?Adversarial?ground?truths
????????????????valid?=?Variable(torch.Tensor(y.size(0),?1).fill_(1.0),
????????????????????????????????requires_grad=False).to(device)
????????????????fake?=?Variable(torch.Tensor(y.size(0),?1).fill_(0.0),
????????????????????????????????requires_grad=False).to(device)
????????????????yvar?=?Variable(y).to(device)
????????????????uvvar?=?Variable(uv).to(device)
????????????????real_imgs?=?torch.cat([yvar,?uvvar],?dim=1)
????????????????optimizer_G.zero_grad()
????????????????uvgen?=?G(yvar)
????????????????#?Generate?a?batch?of?images
????????????????gen_imgs?=?torch.cat([yvar.detach(),?uvgen],?dim=1)
????????????????#?Loss?measures?generator's?ability?to?fool?the?discriminator
????????????????g_loss_gan?=?adversarial_loss(D(gen_imgs),?valid)
????????????????g_loss?=?g_loss_gan?+?args.pixel_loss_weights?*?torch.mean(
????????????????????(uvvar?-?uvgen)**2)
????????????????if?i?%?args.g_every?==?0:
????????????????????g_loss.backward()
????????????????????optimizer_G.step()
????????????????optimizer_D.zero_grad()
????????????????#?Measure?discriminator's?ability?to?classify?real?from?generated?samples
????????????????real_loss?=?adversarial_loss(D(real_imgs),?valid)
????????????????fake_loss?=?adversarial_loss(D(gen_imgs.detach()),?fake)
????????????????d_loss?=?(real_loss?+?fake_loss)?/?2
????????????????d_loss.backward()
????????????????optimizer_D.step()
????????????????if?i?%?300?==?0:
????????????????????logging.info("Epoch:?%d,?iter:?%d,?D?loss:?%f,?G?total?loss:?%f,?GAN?Loss:?%f"
????????????????????????%?(epoch,?i,?d_loss.item(),?g_loss.item(),?g_loss_gan.item()))
????????????????????save_weights(
????????????????????????{'D':?D.state_dict(),?'G':?G.state_dict(),?'epoch':?epoch},
????????????????????????epoch
????????????????????)
????????????????????#?snap?some?images?from?dir
????????????????????test_imgs?=?glob.glob('images/*.jpeg')
????????????????????for?test_img?in?test_imgs:
????????????????????????snap_image_result_from_file(test_img,?G)
????????????except?KeyboardInterrupt:
????????????????logging.info('interrupted.?try?saving?model?now..')
????????????????save_weights(
????????????????????{'D':?D.state_dict(),?'G':?G.state_dict(),?'epoch':?epoch},?0
????????????????)
????????????????logging.info('saved.')
????????????????exit(0)
其中最核心是D和G的loss傳遞過程,首先我們定義了D的loss是BCEloss,也就是兩個類別的交叉商,然后將返回的插值用來更新G,而D的loss呢則是生成的BCE和真實值的BCE二者的均值。
代碼幾乎沒有什么比較難以理解的地方,唯一復雜的就是訓練的步驟和方式。
好啦,有了Python+GAN,我們也可以把黑白照片美化成彩色照片咯!~
參考資料:
https://zhuanlan.zhihu.com/p/24767059
https://zhuanlan.zhihu.com/p/70192339
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的网传梅姨照片竟然是电脑合成的!仅需 100 行代码,你也能做到!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zigbee之SampleApp_Pro
- 下一篇: 关于HashMap容量的初始化,还有这么