01 背景
UI視覺研發擁有明顯的特徵:元件,位置和佈局,符合機器學習處理範疇。能否透過機器視覺和深度學習等手段自動生成UI介面程式碼,來解放重複勞動力,成為我們關注的方向。
02 UI 2 Code是什麼
UI2CODE專案是閒魚技術團隊研發的一款透過機器視覺理解+AI人工智慧將UI視覺圖片轉化為端側程式碼的工具。
2018年3月UI2CODE開始啟動技術可行性預研工作,到目前為止,經歷了3次整體方案的重構(或者重寫)。我們參考了大量的利用機器學習生成程式碼的方案,但都無法達到商用指標,UI2CODE的主要思想是將UI研發特徵分而治之,避免雞蛋放在一個籃子裡。我們著重關注以下3個問題的解法:
視覺稿還原精度:我們的設計師甚至無法容忍1畫素的位置偏差;
準確率:機器學習還處於機率學範疇,但我們需要100%的準確率;
易維護性:工程師們看的懂,改的動是起點,合理的佈局結構才能保障介面流暢執行。
03 UI 2 Code執行效果
UI2CODE外掛化執行效果,如下影片:進過幾輪重構,最終我們定義UI2CODE主要解決feeds流的卡片自動生成,當然它也可以對頁面級自動生成。
04 架構設計
1.透過機器視覺技術,從視覺稿提取GUI元素
2.透過深度學習技術,識別GUI元素型別
3.透過遞迴神經網路技術,生成DSL
4.透過語法樹模板匹配,生成flutter程式碼
05 版面分析
版面分析只做一件事:切圖。
圖片切割效果直接決定UI2CODE輸出結果的準確率。我們拿白色背景的簡單UI來舉例:
上圖是一個白色背景的UI,我們將圖片讀入記憶體,進行二值化處理:
def image_to_matrix(filename):
im = Image.open(filename)
width, height = im.size
im = im.convert("L")
matrix = np.asarray(im)
return matrix, width, height
得到一個二維矩陣:將白色背景的值轉化為0。
像切西瓜一樣,我們只需要5刀,就可以將GUI元素分離,切隔方法多種多樣:(下面是橫切的程式碼片段,實際切割邏輯稍微複雜些,基本是遞迴過程)
def cut_by_col(cut_num, _im_mask):
zero_start = None
zero_end = None
end_range = len(_im_mask)
for x in range(0, end_range):
im = _im_mask[x]
if len(np.where(im==0)[0]) == len(im):
if zero_start == None:
zero_start = x
elif zero_start != None and zero_end == None:
zero_end = x
if zero_start != None and zero_end != None:
start = zero_start
if start > 0:
cut_num.append(start)
zero_start = None
zero_end = None
if x == end_range-1 and zero_start != None and zero_end == None and zero_start > 0:
zero_end = x
start = zero_start
if start > 0:
cut_num.append(start)
zero_start = None
zero_end = None
客戶端的UI基本都是縱向流式佈局,我們可以先橫切在縱切。
將切割點的x,y軸座標記錄下來,它將是處理元件位置關係的核心。切割完成後,我們獲取到2組資料:6個GUI元素圖片和對應的座標系記錄。後續步驟透過分類神經網路進行元件識別。
在實際生產過程中,版面分析會複雜些,主要是在處理複雜背景方面。關注我們的技術公眾號,我們後續會詳細分解。
06 元件識別
進行元件識別前我們需要收集一些元件樣本進行訓練,使用Tensorflow提供的CNN模型和SSD模型等進行增量訓練。
UI2CODE對GUI進行了幾十種型別分類:IMAGE, TEXT,SHAPE/BUTTON,ICON,PRICE等等,分別歸類為UI元件,CI元件和BI元件。
UI元件,主要針對flutter原生的元件進行分類。
CI元件,主要針對閒魚自定義UIKIT進行分類。
BI元件,主要針對具備一定業務意義的feed卡片進行分類。
元件的識別需要反覆的透過全域性特徵反饋來糾正,通常會採用SSD+CNN協同工作,比如下圖的紅色“全新“shape,這該圖例中是richtext的部分,同樣的shape樣式可能屬於button或者icon。
07 屬性提取
這塊的技術點比較雜,歸納起來需要處理3部分內容:shape輪廓, 字型屬性和元件的寬高。
完成屬性提取,基本上我們完成所有GUI資訊的提取。生成的GUI DSL如下圖:
透過這些資料我們就可以進行佈局分析了。其中文字屬性的提取最為複雜,後續我們會專門介紹。
08 佈局分析
前期我們採用4層LSTM網路進行訓練學習,由於樣本量比較小,我們改為規則實現。規則實現也比較簡單,我們在第一步切圖時5刀切割的順序就是row和col。缺點是佈局比較死板,需要結合RNN進行前置反饋。
影片中展示的是透過4層LSTM預測佈局結構的效果,UI的佈局結構就像房屋的框架,建造完成後透過GUI的屬性進行精裝修就完成了一個UI圖層的程式碼還原工作。
09 程式碼生成及外掛化
機器學習本質上來說還屬於機率學範疇,自動生成的程式碼需要非常高的還原度和100%的準確率,機率註定UI2CODE很難達到100%的準確率,所以我們需要提供一個可編輯工具,由開發者透過工具能夠快速理解UI的佈局結構和修改佈局結構。
我們將UI2CODE生成的DSL TREE進行程式碼模板化匹配,程式碼模板的內容由資深的flutter技術專家來定義,它代表目前我們發現的最優程式碼實現方案。
程式碼模板中會引入一些標籤,由Intellij plugin來檢索flutter工程中是否存在對應的自定義UIKIT,並進行替換,提高程式碼的複用度。
整個外掛化工程需要提供自定義UIKIT的檢索,替換和校驗工作,以及DSL Tree的建立,修改,圖示等工作,總體來說,更像ERP系統,花費一些時間能夠做的更加完美。
10 小結
本篇我們簡單介紹了UI2CODE的設計思路,我們將整個工程結構分為5個部分,其中4塊內容核心處理機器視覺的問題,透過機器學習將它們連結起來。程式碼的線上釋出是非常嚴格的事情,而機器學習屬於機率學解法,很難達到我們要求的精度,所以我們選擇以機器視覺理解為主,機器學習為輔的方式,構建整個UI2CODE工程體系。我們將持續關注AI技術,來打造一個完美的UI2CODE工具。