RxFace - 用 RxJava, Retrofit, Okhttp 處理人臉識別的簡單用例

jopen 8年前發布 | 33K 次閱讀 RxFace Android開發 移動開發

RxFace

用 RxJava, Retrofit, Okhttp 處理人臉識別的簡單用例

Overview

這是一個人臉識別的簡單 Demo, 使用了 FacePlusPlus 的接口。他們的/detection/detect 人臉識別接口可以使用普通的 get 也可以用 post 傳遞圖片二進制流的形式。其中 post 的時候遇到了相當多的坑,下面會提。

該 demo 的網絡請求庫使用了 Retrofit 并集成了 OkHttp,使用 RxJava 進行封裝,方便以流的形式處理網絡回調以及圖片處理,View 的注入框架用了 ButterKnife,圖片加載使用 Glide

Difficult point

當直接使用 get 通過傳圖片 Url 拿到人臉識別數據的話是相當簡單的,如下請求鏈接只要使用 Retrofitget 請求的 @QueryMap 傳遞參數即可: Get數據Demo

主要存在的困難點是,當獲取本地圖片,再使用 post 傳二進制圖片數據時,post 要使用 MultipartTypedOutput,可參考 stackoverflow 的回答。然而,這樣并沒有結束,根據 FacePlusPlus 提供的 SDK Sample 里的 Httpurlconnection 的得到的 post 請求頭是這樣的:

[Content-Disposition: form-data; name="api_key", Content-Type: text/plain; charset=US-ASCII, Content-Transfer-Encoding: 8bit]

[Content-Disposition: form-data; name="img"; filename="NoName", Content-Type: application/octet-stream, Content-Transfer-Encoding: binary]

而使用 Retrofit 默認實現的話,我們這樣來實現:

public static MultipartTypedOutput mulipartData(Bitmap bitmap, String boundary){
    byte[] data = getBitmapByte(bitmap);
    MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
    multipartTypedOutput.addPart("api_key", new TypedString(Constants.API_KEY));
    multipartTypedOutput.addPart("api_secret", new TypedString(Constants.API_SECRET));
    multipartTypedOutput.addPart("img", new TypedByteArray("application/octet-stream", data));
    return multipartTypedOutput;
}

根據 Sample 的請求頭,RestAdapter 的請求頭參數我們這樣設置來:

private RequestInterceptor mRequestInterceptor = new RequestInterceptor() {
    @Override
    public void intercept(RequestFacade request) {
        request.addHeader("connection", "keep-alive");
        request.addHeader("Content-Type", "multipart/form-data; boundary="+ getBoundary() + "; charset=UTF-8");
    }
};

但是!!!它得到的String參數的頭是這樣的,這里沒有貼出其他的差異,

Content-Disposition: form-data; name="api_key"
Content-Type: text/plain; charset=UTF-8
Content-Length: 32
Content-Transfer-Encoding: 8bit

所以需要重寫三個類:

MultipartTypedOutput 為 final 類,所以重寫為 CustomMultipartTypedOutput,并使其構造函數,增加 boundary 的設置;

TypedString默認的編碼格式是UTF-8,所以重寫為 AsciiTypeString類,使其編碼格式改為 US-ASCII

TypedByteArray 默認的的 fileName() 方法返回的是 null,而當傳圖片數據時需要 fileName 為 "NoName",所以重寫為 CustomTypedByteArray 類,設置其 fileName 為 "NoName"。

同時需要注意的是在設置 RestAdapter 的 header 時,其 boundary 一定要和 CustomMultipartTypedOutput 的 boundary 相同,否則服務端無法匹配的!(這個地方,一時沒注意,被整了一個多小時才發現!!)

最后 body 的傳參,這樣來得到:

public static CustomMultipartTypedOutput mulipartData(Bitmap bitmap, String boundary){
    byte[] data = getBitmapByte(bitmap);
    CustomMultipartTypedOutput multipartTypedOutput = new CustomMultipartTypedOutput(boundary);
    multipartTypedOutput.addPart("api_key", "8bit", new AsciiTypeString(Constants.API_KEY));
    multipartTypedOutput.addPart("api_secret", "8bit", new AsciiTypeString(Constants.API_SECRET));
    multipartTypedOutput.addPart("img", new CustomTypedByteArray("application/octet-stream", data));
    return multipartTypedOutput;
}

Preview

image_screen

movie_screen

More about me

Acknowledgments

項目地址: https://github.com/MrFuFuFu/RxFace

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!