用圖像分割製做專屬表情包?這裏有妙招!

表情包鬥圖,做爲人生新晉一大樂事,已是廣大網友天天必經的聊天互動環節。什麼鬨堂大笑、滿腹槽點、完全無語……這些萬千語言沒法貼切描述的情緒細節,總能被一張看似平平無奇的表情包完美形容,可謂一圖勝千言,四兩撥千斤!android

現在,在表情包鬥圖進入白熱化階段,人們對錶情包的定製化需求日益增多,人人是表情包的搬運工,人人也是潛力熱圖的創造者!賦予我的製做個性化表情包的能力頗有必要。使用機器學習的圖像分割功能,輕鬆分割複雜圖片背景,讓表情包製做簡單而高效,讓咱們來看看如何將一張圖片變成傳情達意的表情包吧!git

開發準備

Maven倉和SDK的配置步驟能夠參考開發者網站中的應用開發介紹github

developer.huawei.com/consumer/cn…算法

配置集成的SDK包

圖像分割提供了兩種SDK集成方式,一種是預先將分割算法包預先集成在應用中,另外一種是在應用安裝運行後,再將所需的算法包下載到應用中,能夠根據應用的使用場景和所需效果進行選擇。 本文是使用了Full SDK的集成方案,在應用的build.gradle文件中,dependencies內添加圖像分割的SDK依賴markdown

implementation 'com.huawei.hms:ml-computer-vision-segmentation:2.2.0.300'
implementation 'com.huawei.hms:ml-computer-vision-image-segmentation-body-model:2.2.0.300'
複製代碼

配置AndroidManifest.xml

打開main文件夾中的AndroidManifest.xml文件,能夠根據場景和使用須要,配置讀取和寫入手機存儲的權限,在前添加機器學習

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
複製代碼

在內添加以下語句,當應用安裝後,會自動更新最新的機器學習模型到設備異步

<meta-data
    android:name="com.huawei.hms.ml.DEPENDENCY"
    android:value= "imagesuperresolution"/>
複製代碼

開發步驟

配置存儲權限申請

手機的存儲權限,除了在Manifest中聲明,還須要在Activity中進行動態申請。 在MainActivity的onCreate()方法中,調用requestPermission方法,對WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE權限進行申請async

protected void onCreate(Bundle savedInstanceState) {
    ……
    requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
    requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
……
}
複製代碼

requestPermission方法的實現以下,首先對權限進行判斷,若是未獲取權限,則進行申請,若是已經獲取了,則返回ide

private void requestPermission(String permisssions) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        return;
    }
		    if (ContextCompat.checkSelfPermission(this, permisssions)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{permisssions}, REQUEST_CODE);
    } else {
        return;
    }
}
複製代碼

讀取相冊中的圖片

咱們先從相冊中選取要進行表情包製做的圖片,在xml文件中建立一個按鈕chooseImg,點擊後調用selectLocalImage方法oop

this.relativeLayoutLoadPhoto = this.findViewById(R.id.chooseImg);

this.relativeLayoutLoadPhoto.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
 MainActivity.this.selectLocalImage(StillCutPhotoActivity.this.REQUEST_CHOOSE_ORIGINPIC);
    }
});

複製代碼

selectLocalImage方法的實現以下

private void selectLocalImage(int requestCode) {
    Intent intent = new Intent(Intent.ACTION_PICK, null);
    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
    this.startActivityForResult(intent, requestCode);
}
複製代碼

進行圖像分割製做表情包

再建立一個按鈕cut,點擊後調用createImageTransactor方法,進行圖像分割分析器的建立

this.relativeLayoutCut = this.findViewById(R.id.cut);
this.relativeLayoutCut.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (MainActivity.this.imageUri == null) {
            Toast.makeText(MainActivity.this.getApplicationContext(), R.string.please_select_picture, Toast.LENGTH_SHORT).show();
        } else {
            MainActivity.this.createImageTransactor();
            Toast.makeText(MainActivity.this.getApplicationContext(), R.string.cut_success, Toast.LENGTH_SHORT).show();
        }
    }
});
複製代碼

在createImageTransactor方法中,咱們首先建立一個圖像分割的分析器,再進行分析器的配置,將其設置爲人像分割模式

private MLImageSegmentationAnalyzer analyzer;

MLImageSegmentationSetting setting = new MLImageSegmentationSetting.Factory().setAnalyzerType(MLImageSegmentationSetting.BODY_SEG).create();
this.analyzer = MLAnalyzerFactory.getInstance().getImageSegmentationAnalyzer(setting);
複製代碼

從相冊中選取的文件,經過imageUri,將其打開爲Bitmap格式

Pair<Integer, Integer> targetedSize = this.getTargetSize();
int targetWidth = targetedSize.first;
int targetHeight = targetedSize.second;
this.originBitmap = BitmapUtils.loadFromPath(StillCutPhotoActivity.this, this.imageUri, targetWidth, targetHeight);
複製代碼

以後建立MLFrame,調用asyncAnalyseFrame進行異步圖像分割處理

MLFrame mlFrame = new MLFrame.Creator().setBitmap(this.originBitmap).create();
Task<MLImageSegmentation> task = this.analyzer.asyncAnalyseFrame(mlFrame);
複製代碼

圖像分割完成後,對返回的結果進行處理,將去除背景後的圖像保存到processedImage中

task.addOnSuccessListener(new OnSuccessListener<MLImageSegmentation>() {
    @Override
    public void onSuccess(MLImageSegmentation mlImageSegmentationResults) {
        // Transacting logic for segment success.
        if (mlImageSegmentationResults != null) {
            StillCutPhotoActivity.this.foreground = mlImageSegmentationResults.getForeground();
            StillCutPhotoActivity.this.preview.setImageBitmap(StillCutPhotoActivity.this.foreground);
            StillCutPhotoActivity.this.processedImage = ((BitmapDrawable) ((ImageView) StillCutPhotoActivity.this.preview).getDrawable()).getBitmap();
        } else {
            StillCutPhotoActivity.this.displayFailure();
        }
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(Exception e) {
        // Transacting logic for segment failure.
        StillCutPhotoActivity.this.displayFailure();
        return;
    }
});
複製代碼

保存表情包

最後將處理好的圖像轉換成png格式,存儲到系統相冊中

public void saveToAlbum(Bitmap bitmap){
    File file = null;
    String fileName = System.currentTimeMillis() +".png";
    File root = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), this.context.getPackageName());
    File dir = new File(root, "image");
    if(dir.mkdirs() || dir.isDirectory()){
        file = new File(dir, fileName);
    }
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
        os.flush();

    } catch (FileNotFoundException e) {
        Log.e(TAG, e.getMessage());
    } catch (IOException e) {
        Log.e(TAG, e.getMessage());
    }finally {
        try {
            if(os != null) {
                os.close();
            }
        }catch (IOException e){
            Log.e(TAG, e.getMessage());
        }
    }
    if(file == null){
        return;
    }
    if(imageUtilCallBack != null) {
        try {
            imageUtilCallBack.callSavePath(file.getCanonicalPath());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }
    // Gallery refresh.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        String path = null;
        try {
            path = file.getCanonicalPath();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
						}
        MediaScannerConnection.scanFile(this.context, new String[]{path}, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    @Override
                    public void onScanCompleted(String path, Uri uri) {
                        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                        mediaScanIntent.setData(uri);
                        ImageUtils.this.context.sendBroadcast(mediaScanIntent);
                    }
                });
    } else {
        String relationDir = file.getParent();
        File file1 = new File(relationDir);
        this.context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(file1.getAbsoluteFile())));
    }
}
複製代碼

效果示例

編譯運行後,能夠從相冊中選擇想要製做表情包的照片,點擊Cut,ML Kit會完成以後的人像識別和圖像分割步驟,將雜亂的背景去除,返回人像的圖片,以後點擊Save便可將其保存爲沒有背景的表情包。

保存後便可將表情包添加到社交軟件中啦,快來試試吧!

瞭解更多相關內容 訪問華爲機器學習圖像分割服務官網

獲取華爲機器學習服務開發指導文檔

華爲HMS Core官方論壇

華爲機器學習開源倉地址:GitHubGitee

解決集成問題請到Stack Overflow

點擊關注,第一時間瞭解HMS Core最新技術~

相關文章
相關標籤/搜索