2018年2月8日 星期四

謹此感謝FakeApp對AI科技的付出

鬧上新聞的FakeApp被Reddit封鎖了。這感覺令人不悅。就像P2P事件一樣,一個好的工具因為影響了某些人的利益而被打壓。尊重彼此的利益是一種君子之爭。很顯然的,有一方人很不君子。

為了表達在下對FakeApp的支持。底下是我的使用手冊。軟體的部份因為主站被封鎖了。不過我相信一定會在哪裡重生。就請各位自己去找吧。


0. 準備程式
   下載FakeApp
   下載CUDA 8.0 (NVIDIA官網有),然後安裝。注意安裝後,其/bin要在%path%裡
   下載ffmpeg
1. 準備來源影片。在此稱...
   目標影片:
     - 人相會貼過來的影片
     - 感覺作者認為目標影片又分用來學習的和用來做成結果的
     - 我的實驗使用同一個
     - 作者稱Porn Video
   參考影片:
     - 人相的來源影片
     - 也可以是圖片
     - 目的是把這個畫面貼到目標影片去
     - 作者稱Celebrity Video
2. 將兩造影片切成數個frame(比如用ffmpeg),並做為不同的set
   指令:ffmpeg -i <.mp4> fps= ""
       - e.g. ffmpeg.exe -i y.mp4 -vf fps=23 "out%d.png"
   如果是參考圖檔,當然就不用切
   這兩種set作者稱Porn set與Celebrity set
     - 作者默認Porn set為A set;Celebrity set為B set
3. 將人相從frame取出(extract)
   執行FakeApp.bat以啟動GUI,到Extract頁,然後path指向各個set,然後按start
     - 兩個set都要做一次
   可以把沒有人相或人相不清楚的frame刪掉以節省時間。
     - 因為會刪掉部份的東西,最好把set再copy出來一份專門做Extract
   做完後會產生aligned目錄與alignments.json檔
4. 從兩個alignment中做學習(train),這個很花時間(hours, days...)
   執行FakeApp.bat以啟動GUI,到Train頁,然後指定目錄給算出來的模型(model)以及各個來源set的aligned,然後按start
   start後,FakeApp會開始學習。它會跳出一個Training Preview畫面顯示學習的結果
     - 當你覺得學得夠好了以後,於focus那個視窗時按下q離開
     - 你可以先離開以暫停,然後用同樣的設定再繼續算模型
   根據作者的說法,預設data A是參考影片的臉,data B是目標影片的臉,不過在大量學習後沒有差別
     - 不過記住在merge時,注意data A是參考影片,data B是目標影片 (AtoB)
   在model的路徑下會產生train好的檔案
   作者說,如果你的電腦慢的話,可以試著接上Google Cloud AI
5. 轉換目標影片
   將train好的檔案,如config.p、decoder...與encoder,copy到FakeApp/models的目錄下
   指定好model、目標影片frame的位置後按start
   完成後會放在merged目錄裡
6. 將merged目錄裡的frame結合成影片檔(比如用ffmpeg)
   指令:ffmpeg -r [INSERT FRAME RATE] -s [DIMENSIONS OF IMAGEs (i.e. 1280x720)] -pattern_type glob -i '*.png' -vcodec libx264 -crf 24 -pix_fmt yuv420p [OUTPUTFILENAME].mp4
     - 上面的指令無法在Windows執行,因為glob的檔案選擇法並不被Windows支援
     - 底下是一種Windows的解決方式
         1.將.png檔做成Windows支援的順序。在Windows,out120.png在out13.png之前。應將out13.png改為out013.png以修正順序。
           1.1.可以用dir > temp.txt的方式把檔案清單放到temp.txt,然後用類似Notepad++的編輯軟體做區塊的編輯,把所有要調整的檔案編輯成類似...
           1.2.ren
           1.3.然後把temp.txt改名為temp.bat,然後執行該.bat檔
         2.ffmpeg指令改用wildcard,如...
           ffmpeg -r [INSERT FRAME RATE] -s [DIMENSIONS OF IMAGEs (i.e. 1280x720)] -i out%04d.png -vcodec libx264 -crf 24 -pix_fmt yuv420p [OUTPUTFILENAME].mp4
           - e.g.ffmpeg.exe -r 30 -s 1920x1080 -start_number 1 -i out%04d.png -vcodec libx264 -crf 24 -pix_fmt yuv420p merged0126.mp4
           - 上面的e.g.有一個問題,就是,你的index不是1開始的話,或是中間有斷號,它就做不下去了...必須把index做好做滿
           - https://stackoverflow.com/questions/31201164/ffmpeg-error-pattern-type-glob-was-selected-but-globbing-is-not-support-ed-by


=============

ffmpeg在merge時遇到的問題,你也可以使用我寫的這個python來解決:

###########################################################
##
## This program uses to arrange file names
##
###########################################################

import sys

if len(sys.argv) !=3:
    print('wrong size of inputed arguments...; size: '+str(len(sys.argv)))
    print('usage: ')
    exit()

prefix = sys.argv[1]
subffix = sys.argv[2]

from pathlib import Path
path = Path('.');

print('looking for files in '+str(path.cwd())+' start with '+prefix+' and end with '+subffix)

listOfPath = list(path.glob(prefix+'*'+subffix))

print('number of found files with inputed condition: '+str(len(listOfPath)))

#########
# stage 1 take the same length of index number string
print('STAGE 1 MAKE THE SAME LENGTH OF INDEX NUMBER STRING')
# get max number for determine required zero
max = 0
for itemInPath in listOfPath:
    if itemInPath.is_file() == False:
        continue
       
    tmp = str(itemInPath)
    tmplen = len(tmp)
    tmp2 = tmp[len(prefix):(tmplen-len(subffix))]
    try:
        tmpnum = int(tmp2)
    except ValueError:
        print('invalid index number: '+tmp2)
        exit()
   
    if tmpnum > max:
        max = tmpnum
       
idxLen = len(str(max))
print('max number is '+str(max)+'; index string length is '+str(idxLen));

# check targets and determine destination file name
for itemInPath in listOfPath:
    if itemInPath.is_file() == False:
        continue
       
    tmp = str(itemInPath)
    tmplen = len(tmp)
    tmp2 = tmp[len(prefix):(tmplen-len(subffix))]
   
    needZero = idxLen - len(tmp2)
    if needZero <= 0:
        continue

    destName = tmp2 + subffix
    for i in range(needZero):
        destName = '0' + destName
    destName = prefix + destName
    print(tmp+' --> '+destName)
    #print(itemInPath)
    itemInPath.rename(destName)


#########
# stage 2 make index number string starts from 1
print('STAGE 2 MAKE INDEX NUMBER STRING STARTS FROM 1')
path = Path('.');

listOfPath = list(path.glob(prefix+'*'+subffix))

newIdx = 0
for itemInPath in listOfPath:
    if itemInPath.is_file() == False:
        continue
   
    newIdx+=1
   
    strIdx = str(newIdx)
    while len(strIdx)        strIdx = '0' + strIdx
   
    print(str(itemInPath)+' -> '+prefix+strIdx+subffix)
    itemInPath.rename(prefix+strIdx+subffix)

print("process done")

最後。謹此感謝FakeApp對AI科技的付出。
請不要不以為然,有時候,影響是來自意想不到的地方。

沒有留言: