點擊上方「 CSDN 」,選擇「置頂公眾號」
關鍵時刻,第一時間送達!
從昨天到現在,朋友圈裡便持續性地見到了許多「請給我一頂聖誕帽@微信官方」,正如前文《 如何從技術上實現「朋友圈@微信官方頭像添加聖誕帽」? 》所說,朋友們紛紛求問如何給自己的頭像加上聖誕帽,然後,一場花式求聖誕帽的儀式開始刷屏了,還混入了各種奇怪的東西。但是卻發現 @微信官方 並不能帶上聖誕帽,才知道「被騙」了。
而昨晚,微信官方還特地發了一篇《 聽說你們都在@我? 》的文章就此事情進行闢謠,表示:
然而,技術人們紛紛表示不服!「雖然微信沒這個功能,但並不代表實現不了!在現有的技術環境下,這點需求都實現不了也未免太看不起我們程式設計師了吧?!」
閱文集團首席架構師徐海峰老師就表示,使用大數據分析+AI+圖片動態處理實現能夠實現「朋友圈@微信官方頭像添加聖誕帽」,並為此撰文進行了架構上的分析。
而在 CSDN 文章的微信留言中,也有許多程式設計師小夥伴們表示「從技術上講這個功能完全可以實現」,並為此紛紛出了主意。
@微信官方,聖誕節就在眼前,能不能如願就看你的了!實在不行來年也是可以的。
接下來,我們有請徐海峰老師,從架構上分享,如何全自動無手工幹預地實現「朋友圈@微信官方頭像添加聖誕帽」。
以下為正文(經授權轉自 徐海峰老師個人公眾號「94geek的大嘴」) :
我們先變身為產品,分析需求,如下:
從上圖可以看出:「@」是發動者,頭像更變是最後的結果。對於程式設計師來說,需要處理的問題點有幾個:
如何知道用戶發起來需要戴聖誕帽的要求;
如何識別出用戶頭像圖片中的頭部位置及其走向,然後儘可能正確的加上聖誕帽;
如何通知微信程序更新最新頭像。
首先,我們來解決第一個難點:如何知道用戶發起需要戴聖誕帽的要求?
用戶發一條朋友圈,微信伺服器可以完整地得到該朋友圈的內容,所以微信後臺可以對其進行內容解析。只要解析到朋友圈內容中帶有「@微信官方」並且內容是「加/戴聖誕帽」相關的,就將該條朋友圈看做是用戶需要更改頭像。
在技術上,我們將其視為給微信發送了一個通知,考慮到朋友圈的發送量和改變圖片的實時性需求,稍微延遲一點更改頭像也沒有特別大的關係,所以將處理頭像設計成異步模式,最簡單的辦法就是將通知放入隊列,緩存起來。架構圖如下:
第二步:解決圖片識別問題。
鑑於頭像圖片識別頭部的需求,我們不需要太過於精確,所以也沒有必要大張旗鼓地使用很多的 AI 臉部識別技術(PS:當然有更好),目前開源的項目中 OpenCV 即可解決識別問題。OpenCV 可以識別出人臉在圖片中位置,將其用坐標的形式「框」起來。考慮到有些用戶頭像的頭部有幹擾項:比如頭部正好是黑色背景、頭像中的人是光頭……,可以適當的增加一些抗幹擾的考慮項;如果要求更高一些,還可以根據眼睛、鼻子、耳朵等頭部特徵將頭部的走向(防止有歪頭的)大體計算清楚。
這樣,在得到頭部大體大小、坐標、走向的情況下,適當的調整聖誕帽的大小、坐標、走向,合併成一張圖片即可。這部是整個技術的核心,如果需要提高正確率,可以對圖片進行大數據分析,儘量的找到圖片的公共點,提高識別的準確率。
最後:通知微信更新最新頭像。
微信作為一個社交產品,它肯定會考慮加聖誕帽這個需求的時間效應:聖誕帽頭像嚴格意義上說是具有極強時間效應的,所以這個頭像存在的時間很短。用戶更改頭像的初衷並不是出於真心的喜歡,而只是圖新鮮,2-5 天度過聖誕節後即沒用了。
所以,微信沒必要真正地去更改用戶的頭像,這也就意味著我們根本不需要更改任何資料庫的操作,我們直接從原頭像的基礎上更改,將更改好的圖片使用原來頭像的文件名推入緩存系統、並且通知微信 App 更新即可。只要保證在 2-5 之內頭像存在就可以完成任務。當然,如果需要永久保留圖片,這就增加資料庫標誌位欄位,然後將加好帽子的圖片存入到圖片伺服器,並且更新緩存伺服器的頭像圖片。
綜上所述,整套架構如下所示:
整個架構圖都畫出來,但是肯定還有很多的同學會懵逼,竟然不把生成的圖片都存儲下來?好吧,順便也科普一下行業內存儲圖片和處理圖片的常用方案。
業內處理圖片有一個不成文的規定: 存原圖,給效果圖。展開來說就是:
程序在存儲用戶上傳圖片的時候儘量不處理或者少處理用戶的圖片,等到用戶獲取的時候再由程序根據當時的需求給出不同的圖片。
我們最常見的圖片操作:加水印、裁剪圖片、縮放圖片、壓縮圖片大小……,很多時候我們都在上傳的時候解決了。這種方案不是不可以,但是並不好。不好的地方主要有 2 個:
浪費存儲空間。上傳的時候進行處理,也就意味著程序要存儲一張原圖,還有 N 張效果圖。這就是存儲可能被擴大了 N 倍;
擴展難。目前的業務需求圖片是 200200;過了 3 個月,業務方需要 400400;又過了 2 個月,業務方又需要一個 300*300 的……,縱使我們新需求可以通過更改代碼來解決,老圖片是不是還要創建一個 job 來遍歷的跑一下才行?
所以,圖片處理正確的做法應該是:在用戶獲取圖片的時候交給圖片的 HTTP 伺服器處理。這種解決方案會在一定程度上增加 HTTP 伺服器的壓力,但我們可以使用 Varlish/Squid/CDN 等成熟的緩存系統將其做到「儘可能的一次寫 N 次讀」。
圖片只有在第一次被訪問的時候需要圖片 HTTP 伺服器對其進行處理,以後只要這張圖片不過期/不被回收,這張圖片一直存在於緩存中,根據反向代理原理,請求在緩存處已經獲取文件,故不會對圖片 HTTP 產生任何壓力。雖然技術實現難度有所增加,但是卻解決上面提到的 2 個最主要的問題。
作者聲明:以上方案純屬大體方向和個人揣測,實踐中還需要再根據具體的業務做具體的調整。如有雷同,純屬巧合!