最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Java 實現(xiàn)一個“你畫手機猜”的小游戲

 更新時間:2020年09月25日 09:39:19   作者:削微寒  
這篇文章主要介紹了使用Java 實現(xiàn)一個“你畫手機猜”的小游戲,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

本文適合有 Java 基礎(chǔ)的人群

作者:DJL-Lanking

HelloGitHub 推出的《講解開源項目》系列。有幸邀請到了亞馬遜 + Apache 的工程師:Lanking( https://github.com/lanking520 ),為我們講解 DJL —— 完全由 Java 構(gòu)建的深度學(xué)習(xí)平臺,本文為系列的第三篇。

一、前言

在 2018 年時,Google 推出了《猜畫小歌》應(yīng)用:玩家可以直接與AI進行你畫我猜的游戲。通過畫出一個房子或者一個貓,AI 會推斷出各種物品被畫出的概率。它的實現(xiàn)得益于深度學(xué)習(xí)模型在其中的應(yīng)用,通過深度神經(jīng)網(wǎng)絡(luò)的歸納,曾經(jīng)令人頭疼的繪畫識別也變得易如反掌。現(xiàn)如今,只要使用一個簡單的圖片分類模型,我們便可以輕松的實現(xiàn)繪畫識別。試試看這個在線涂鴉小游戲吧:

在線涂鴉小游戲:https://djl.ai/website/demo.html

在當(dāng)時,大部分機器學(xué)習(xí)計算任務(wù)仍舊需要依托網(wǎng)絡(luò)在云端進行。隨著算力的不斷增進,機器學(xué)習(xí)任務(wù)已經(jīng)可以直接在邊緣設(shè)備部署,包括各類運行安卓系統(tǒng)的智能手機。但是,由于安卓本身主要是用 Java ,部署基于 Python 的各類深度學(xué)習(xí)模型變成了一個難題。為了解決這個問題,AWS 開發(fā)并開源了 DeepJavaLibrary (DJL),一個為 Java 量身定制的深度學(xué)習(xí)框架。

在這個文章中,我們將嘗試通過 PyTorch 預(yù)訓(xùn)練模型在在安卓平臺構(gòu)建一個涂鴉繪畫的應(yīng)用。由于總代碼量會比較多,我們這次會挑重點把最關(guān)鍵的代碼完成。你可以后續(xù)參考我們完整的項目進行構(gòu)建。

涂鴉應(yīng)用完整代碼:https://github.com/aws-samples/djl-demo/tree/master/android

二、環(huán)境配置

為了兼容 DJL 需求的 Java 功能,這個項目需要 Android API 26 及以上的版本。你可以參考我們案例配置來節(jié)約一些時間,下面是這個項目需要的依賴項:

案例 gradle: https://github.com/aws-samples/djl-demo/blob/master/android/quickdraw_recognition/build.gradle

dependencies {
 implementation 'androidx.appcompat:appcompat:1.2.0'
 implementation 'ai.djl:api:0.7.0'
 implementation 'ai.djl.android:core:0.7.0'
 runtimeOnly 'ai.djl.pytorch:pytorch-engine:0.7.0'
 runtimeOnly 'ai.djl.android:pytorch-native:0.7.0'
}

我們將使用 DJL 提供的 API 以及 PyTorch 包。

三、構(gòu)建應(yīng)用

3.1 第一步:創(chuàng)建 Layout

我們可以先創(chuàng)建一個 View class 以及 layout(如下圖)來構(gòu)建安卓的前端顯示界面。

如上圖所示,你可以在主界面創(chuàng)建兩個 View 目標(biāo)。PaintView 是用來讓用戶畫畫的,在右下角 ImageView 是用來展示用于深度學(xué)習(xí)推理的圖像。同時我們預(yù)留一個按鈕來進行畫板的清空操作。

3.2 第二步: 應(yīng)對繪畫動作

在安卓設(shè)備上,你可以自定義安卓的觸摸事件響應(yīng)來應(yīng)對用戶的各種觸控操作。在我們的情況下,我們需要定義下面三種時間響應(yīng):

  • touchStart:感應(yīng)觸碰時觸發(fā)
  • touchMove:當(dāng)用戶在屏幕上移動手指時觸發(fā)
  • touchUp:當(dāng)用戶抬起手指時觸發(fā)

與此同時,我們用 paths 來存儲用戶在畫板所繪制的路徑?,F(xiàn)在我們看一下實現(xiàn)代碼。

3.2.1 重寫 OnTouchEventOnDraw 方法

現(xiàn)在我們重寫 onTouchEvent 來應(yīng)對各種響應(yīng):

@Override
public boolean onTouchEvent(MotionEvent event) {
 float x = event.getX();
 float y = event.getY();

 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN :
  touchStart(x, y);
  invalidate();
  break;
 case MotionEvent.ACTION_MOVE :
  touchMove(x, y);
  invalidate();
  break;
 case MotionEvent.ACTION_UP :
  touchUp();
  runInference();
  invalidate();
  break;
 }

 return true;
}

如上面代碼所示,你可以添加一個 runInference 方法在 MotionEvent.ACTION_UP 事件響應(yīng)上。這個方法是用來在用戶繪制完后對結(jié)果進行推理。在之后的幾步中,我們會講解它的具體實現(xiàn)。

我們同樣需要重寫 onDraw 方法來展示用戶繪制的圖像:

@Override
protected void onDraw(Canvas canvas) {
 canvas.save();
 this.canvas.drawColor(DEFAULT_BG_COLOR);

 for (Path path : paths) {
 paint.setColor(DEFAULT_PAINT_COLOR);
 paint.setStrokeWidth(BRUSH_SIZE);
 this.canvas.drawPath(path, paint);
 }
 canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
 canvas.restore();
}

真正的圖像會保存在一個 Bitmap 上。

3.2.2 操作開始(touchStart)

當(dāng)用戶觸碰行為開始時,下面的代碼會建立一個新的路徑同時記錄路徑中每一個點在屏幕上的坐標(biāo)。

private void touchStart(float x, float y) {
 path = new Path();
 paths.add(path);
 path.reset();
 path.moveTo(x, y);
 this.x = x;
 this.y = y;
}

3.2.3 手指移動(touchMove)

在手指移動中,我們會持續(xù)記錄坐標(biāo)點然后將它們構(gòu)成一個 quadratic bezier. 通過一定的誤差閥值來動態(tài)優(yōu)化用戶的繪畫動作。只有差別超出誤差范圍內(nèi)的動作才會被記錄下來。

quadratic bezier 文檔: https://developer.android.com/reference/android/graphics/Path

private void touchMove(float x, float y) {
 if (x < 0 || x > getWidth() || y < 0 || y > getHeight()) {
 return;
 }
 float dx = Math.abs(x - this.x);
 float dy = Math.abs(y - this.y);

 if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
 path.quadTo(this.x, this.y, (x + this.x) / 2, (y + this.y) / 2);
 this.x = x;
 this.y = y;
 }
}

3.2.4 操作結(jié)束(touchUp)

當(dāng)觸控操作結(jié)束后,下面的代碼會繪制一個路徑同時計算最小長方形目標(biāo)框。

private void touchUp() {
 path.lineTo(this.x, this.y);
 maxBound.add(new Path(path));
}

3.3 第三步:開始推理

為了在安卓設(shè)備上進行推理任務(wù),我們需要完成下面幾個任務(wù):

  • 從 URL 讀取模型
  • 構(gòu)建前處理和后處理過程
  • 從 PaintView 進行推理任務(wù)

為了完成以下目標(biāo),我們嘗試構(gòu)建一個 DoodleModel class。在這一步,我們將介紹一些完成這些任務(wù)的關(guān)鍵步驟。

3.3.1 讀取模型

DJL 內(nèi)建了一套模型管理系統(tǒng)。開發(fā)者可以自定義儲存模型的文件夾。

File dir = getFilesDir();
System.setProperty("DJL_CACHE_DIR", dir.getAbsolutePath());

通過更改 DJL_CACHE_DIR 屬性,模型會被存入相應(yīng)路徑下。

下一步可以通過定義 Criteria 從指定 URL 處下載模型。下載的 zip 文件內(nèi)包含:

  • doodle_mobilenet.pt:PyTorch 模型
  • synset.txt:包含分類任務(wù)中所有類別的名稱
Criteria<Image, Classifications> criteria =
  Criteria.builder()
   .setTypes(Image.class, Classifications.class)
   .optModelUrls("https://djl-ai.s3.amazonaws.com/resources/demo/pytorch/doodle_mobilenet.zip")
   .optTranslator(translator)
   .build();
return ModelZoo.loadModel(criteria);

上述代碼同時定義了 translator,它會被用來做圖片的前處理和后處理。

最后,如下述代碼創(chuàng)建一個 Model 并用它創(chuàng)建一個 Predictor

@Override
protected Boolean doInBackground(Void... params) {
 try {
 model = DoodleModel.loadModel();
 predictor = model.newPredictor();
 return true;
 } catch (IOException | ModelException e) {
 Log.e("DoodleDraw", null, e);
 }
 return false;
}

更多關(guān)于模型加載的信息,請參閱如何加載模型。

DJL 模型加載文檔:http://docs.djl.ai/docs/load_model.html

3.3.2 用 Translator 定義前處理和后處理

在 DJL 中,我們定義了 Translator 接口進行前處理和后處理。在 DoodleModel 中我們定義了 ImageClassificationTranslator 來實現(xiàn) Translator:

ImageClassificationTranslator.builder()
 .addTransform(new ToTensor())
 .optFlag(Image.Flag.GRAYSCALE)
 .optApplySoftmax(true).build());

下面我們詳細闡述 translator 所定義的前處理和后處理如何被用在模型的推理步驟中。當(dāng)你創(chuàng)建 translator 時,內(nèi)部程序會自動加載 synset.txt 文件得到做分類任務(wù)時所有類別的名稱。當(dāng)模型的 predict() 方法被調(diào)用時,內(nèi)部程序會先執(zhí)行所對應(yīng)的 translator 的前處理步驟,而后執(zhí)行實際推理步驟,最后執(zhí)行 translator 的后處理步驟。對于前處理,我們會將 Image 轉(zhuǎn)化 NDArray,用于作為模型推理過程的輸入。對于后處理,我們對推理輸出的結(jié)果(NDArray)進行 softmax 操作。最終返回結(jié)果為 Classifications 的一個實例。

自定義 Translator 案例:http://docs.djl.ai/jupyter/pytorch/load_your_own_pytorch_bert.html

3.3.3 用 PaintView 進行推理任務(wù)

最后,我們來實現(xiàn)之前定義好的 runInference 方法。

public void runInference() {
 // 拷貝圖像
 Bitmap bmp = Bitmap.createBitmap(bitmap);
 // 縮放圖像
 bmp = Bitmap.createScaledBitmap(bmp, 64, 64, true);
 // 執(zhí)行推理任務(wù)
 Classifications classifications = model.predict(bmp);
 // 展示輸入的圖像
 Bitmap present = Bitmap.createScaledBitmap(bmp, imageView.getWidth(), imageView.getHeight(), true);
 imageView.setImageBitmap(present);
 // 展示輸出的圖像
 if (messageToast != null) {
 messageToast.cancel();
 }
 messageToast = Toast.makeText(getContext(), classifications.toString(), Toast.LENGTH_SHORT);
 messageToast.show();
}

這將會創(chuàng)建一個 Toast 彈出頁面用于展示結(jié)果,示例如下:

恭喜你!我們完成了一個涂鴉識別小程序!

3.4 可選優(yōu)化:輸入裁剪

為了得到更高的模型推理準(zhǔn)確度,你可以通過截取圖像來去除無意義的邊框部分。

上面右側(cè)的圖片會比左邊的圖片有更好的推理結(jié)果,因為它所包含的空白邊框更少。你可以通過 Bound 類來尋找圖片的有效邊界,即能把圖中所有白色像素點覆蓋的最小矩形。在得到 x 軸最左坐標(biāo),y 軸最上坐標(biāo),以及矩形高度和寬度后,就可以用這些信息截取出我們想要的圖形(如右圖所示)實現(xiàn)代碼如下:

RectF bound = maxBound.getBound();
int x = (int) bound.left;
int y = (int) bound.top;
int width = (int) Math.ceil(bound.width());
int height = (int) Math.ceil(bound.height());
// 截取部分圖像
Bitmap bmp = Bitmap.createBitmap(bitmap, x, y, width, height);

恭喜你!現(xiàn)在你就掌握了全部教程內(nèi)容!期待看到你創(chuàng)建的第一個 DoodleDraw 安卓游戲!

最后,可以在GitHub找到本教程的完整案例代碼。

涂鴉應(yīng)用完整代碼:https://github.com/aws-samples/djl-demo/tree/master/android

關(guān)于 DJL

Deep Java Library (DJL) 是一個基于 Java 的深度學(xué)習(xí)框架,同時支持訓(xùn)練以及推理。 DJL 博取眾長,構(gòu)建在多個深度學(xué)習(xí)框架之上 (TenserFlow、PyTorch、MXNet 等) 也同時具備多個框架的優(yōu)良特性。你可以輕松使用 DJL 來進行訓(xùn)練然后部署你的模型。

它同時擁有著強大的模型庫支持:只需一行便可以輕松讀取各種預(yù)訓(xùn)練的模型。現(xiàn)在 DJL 的模型庫同時支持高達 70 個來自 GluonCV、 HuggingFace、TorchHub 以及 Keras 的模型。

項目地址:https://github.com/awslabs/djl/

到此這篇關(guān)于使用Java 實現(xiàn)一個“你畫手機猜”的小游戲的文章就介紹到這了,更多相關(guān)Java實現(xiàn)你畫手機猜小游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中對list元素進行排序的方法詳解

    Java中對list元素進行排序的方法詳解

    這篇文章主要介紹了Java中對list元素進行排序的方法詳解,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • mybatis-plus 通用字段自動化(如邏輯刪除和更新時間等)

    mybatis-plus 通用字段自動化(如邏輯刪除和更新時間等)

    這篇文章主要介紹了mybatis-plus 通用字段自動化(如邏輯刪除和更新時間等),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    這篇文章主要介紹了sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • maven父工程relativepath標(biāo)簽使用解讀

    maven父工程relativepath標(biāo)簽使用解讀

    文章主要介紹了在使用Maven構(gòu)建父子工程時如何通過設(shè)置父工程和子工程的pom文件來管理依賴和版本,當(dāng)子工程是Spring Boot項目時,可以通過關(guān)閉`relativePath`標(biāo)簽來繼承Spring Boot的父工程,同時在父工程中使用`dependencyManagement`標(biāo)簽來統(tǒng)一管理Spring Boot的依賴版本
    2024-11-11
  • mybatis xml如何使用not in 某個集合的格式

    mybatis xml如何使用not in 某個集合的格式

    這篇文章主要介紹了mybatis xml如何使用not in 某個集合的格式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java讀取properties配置文件時,出現(xiàn)中文亂碼的解決方法

    Java讀取properties配置文件時,出現(xiàn)中文亂碼的解決方法

    下面小編就為大家?guī)硪黄狫ava讀取properties配置文件時,出現(xiàn)中文亂碼的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • 詳解CopyOnWriteArrayList是如何保證線程安全

    詳解CopyOnWriteArrayList是如何保證線程安全

    這篇文章主要為大家介紹了CopyOnWriteArrayList是如何保證線程安全講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • Java中static和static?final的區(qū)別詳解

    Java中static和static?final的區(qū)別詳解

    這篇文章主要介紹了Java中static和static?final的區(qū)別詳解,開發(fā)時我們經(jīng)常用到static以及static?final來修飾我們的字段變量,那么他們到底有什么區(qū)別呢?其實他們的區(qū)別可以用使用字節(jié)碼文件來解析,需要的朋友可以參考下
    2023-10-10
  • Java網(wǎng)絡(luò)編程之簡單的服務(wù)端客戶端應(yīng)用實例

    Java網(wǎng)絡(luò)編程之簡單的服務(wù)端客戶端應(yīng)用實例

    這篇文章主要介紹了Java網(wǎng)絡(luò)編程之簡單的服務(wù)端客戶端應(yīng)用,以實例形式較為詳細的分析了java網(wǎng)絡(luò)編程的原理與服務(wù)器端客戶端的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • SpringMVC結(jié)合天氣api實現(xiàn)天氣查詢

    SpringMVC結(jié)合天氣api實現(xiàn)天氣查詢

    這篇文章主要為大家詳細介紹了SpringMVC結(jié)合天氣api實現(xiàn)天氣查詢,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評論

江山市| 图片| 苏尼特左旗| 昭通市| 余庆县| 祥云县| 蓝田县| 秦皇岛市| 曲水县| 达日县| 二连浩特市| 三明市| 林州市| 美姑县| 蕲春县| 宿州市| 凌源市| 九龙城区| 天峻县| 西林县| 富源县| 中方县| 台州市| 中超| 昭通市| 临安市| 安国市| 南郑县| 玉环县| 和政县| 五家渠市| 崇阳县| 恭城| 乐业县| 女性| 安丘市| 南投县| 万年县| 武功县| 北安市| 岳阳县|