สร้างแอป Android เพื่อตรวจจับวัตถุภายในรูปภาพ

สร้างแอป Android เพื่อตรวจจับวัตถุภายในรูปภาพ

เกี่ยวกับ Codelab นี้

subjectอัปเดตล่าสุดเมื่อ เม.ย. 5, 2022
account_circleเขียนโดย Wei Wei

1 ข้อควรทราบก่อนที่จะเริ่มต้น

ใน Codelab นี้ คุณดูวิธีเรียกใช้การอนุมานการตรวจหาออบเจ็กต์จากแอป Android โดยใช้ TensorFlow Serving กับ REST และ gRPC

สิ่งที่ต้องมีก่อน

  • ความรู้เบื้องต้นเกี่ยวกับการพัฒนา Android ด้วย Java
  • ความรู้เบื้องต้นเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกอบรมและการทําให้ใช้งานได้
  • ความรู้เบื้องต้นเกี่ยวกับเทอร์มินัลและ Docker

สิ่งที่คุณจะได้เรียนรู้

  • วิธีค้นหาโมเดลการตรวจจับออบเจ็กต์ที่ฝึกไว้แล้วล่วงหน้าใน TensorFlow Hub
  • วิธีสร้างแอป Android แบบง่ายๆ และการคาดคะเนด้วยโมเดลการตรวจจับออบเจ็กต์ที่ดาวน์โหลดผ่าน TensorFlow Serving (REST และ gRPC)
  • วิธีแสดงผลการตรวจจับใน UI

สิ่งที่ต้องมี

2 ตั้งค่า

วิธีดาวน์โหลดโค้ดสําหรับ Codelab นี้

  1. ไปที่ที่เก็บ GitHub สําหรับ Codelab นี้
  2. คลิก Code > Download ZIP เพื่อดาวน์โหลดโค้ดทั้งหมดสําหรับ Codelab นี้

a72f2bb4caa9a96.png

  1. แตกไฟล์ ZIP ที่ดาวน์โหลดเพื่อคลายโฟลเดอร์รูท codelabs ด้วยทรัพยากรทั้งหมดที่ต้องการ

Codelab นี้ต้องการเฉพาะไฟล์ในไดเรกทอรีย่อย TFServing/ObjectDetectionAndroid ในที่เก็บ ซึ่งมี 2 โฟลเดอร์ดังนี้

  • โฟลเดอร์ starter มีโค้ดเริ่มต้นที่คุณสร้างสําหรับ Codelab นี้
  • โฟลเดอร์ finished มีโค้ดที่สมบูรณ์สําหรับแอปตัวอย่างที่สมบูรณ์

3 เพิ่มทรัพยากร Dependency ลงในโปรเจ็กต์

นําเข้าแอปเริ่มต้นไปยัง Android Studio

  • ใน Android Studio ให้คลิก File > New > Import project แล้วเลือกโฟลเดอร์ starter จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้

เพิ่มทรัพยากร Dependency สําหรับ OkHttp และ gRPC

  • ในไฟล์ app/build.gradle ของโปรเจ็กต์ ให้ยืนยันว่ามีทรัพยากร Dependency อยู่
dependencies {
 
// ...
    implementation
'com.squareup.okhttp3:okhttp:4.9.0'
    implementation
'javax.annotation:javax.annotation-api:1.3.2'
    implementation
'io.grpc:grpc-okhttp:1.29.0'
    implementation
'io.grpc:grpc-protobuf-lite:1.29.0'
    implementation
'io.grpc:grpc-stub:1.29.0'
}

ซิงค์โปรเจ็กต์ด้วยไฟล์ Gradle

  • เลือก541e90b497a7fef7.pngซิงค์โปรเจ็กต์ด้วย Gradle Files จากเมนูการนําทาง

4 เรียกใช้แอปเริ่มต้น

เรียกใช้และสํารวจแอป

แอปควรเปิดตัวในอุปกรณ์ Android UI มีความเรียบง่าย: จะมีรูปภาพแมวที่คุณต้องการตรวจหาออบเจ็กต์และผู้ใช้เลือกวิธีส่งข้อมูลไปยังแบ็กเอนด์ได้ด้วย REST หรือ gRPC แบ็กเอนด์จะตรวจจับออบเจ็กต์ในรูปภาพและส่งผลลัพธ์ของการตรวจจับไปยังแอปไคลเอ็นต์ ซึ่งจะแสดงผล UI อีกครั้ง

24eab579530e9645.png

ขณะนี้หากคุณคลิกเรียกใช้การอนุมาน ก็จะไม่มีอะไรเกิดขึ้น เนื่องจากยังไม่สามารถสื่อสารกับแบ็กเอนด์

5 ทําให้โมเดลการตรวจจับออบเจ็กต์ใช้งานได้ด้วยการแสดงผล TensorFlow

การตรวจหาออบเจ็กต์เป็นงาน ML ที่พบบ่อยที่สุดและเป้าหมายของออบเจ็กต์นี้คือ การตรวจหาออบเจ็กต์ภายในรูปภาพ ซึ่งก็คือการคาดการณ์หมวดหมู่ที่เป็นไปได้ของออบเจ็กต์และกรอบล้อมรอบ ด้านล่างนี้เป็นตัวอย่างของผลการตรวจหา

a68f9308fb2fc17b.png

Google ได้เผยแพร่โมเดลที่ฝึกล่วงหน้าแล้วจํานวนหนึ่งใน TensorFlow Hub หากต้องการดูรายการทั้งหมด ให้ไปที่หน้า Object_detection คุณใช้โมเดล SSD MobileNet V2 FPNLite 320x320 ที่ค่อนข้างหนักสําหรับ Codelab นี้เพื่อที่จะได้ไม่ต้องใช้ GPU ในการเรียกใช้

หากต้องการทําให้โมเดลการตรวจจับออบเจ็กต์ใช้งานได้ด้วยการแสดงผล TensorFlow ให้ทําดังนี้

  1. ดาวน์โหลดไฟล์โมเดล
  2. ยกเลิกการบีบอัดไฟล์ .tar.gz โดยใช้เครื่องมือขยายข้อมูลที่บีบอัด เช่น 7-Zip
  3. สร้างโฟลเดอร์ ssd_mobilenet_v2_2_320 แล้วสร้างโฟลเดอร์ย่อย 123 ในโฟลเดอร์นั้น
  4. วางโฟลเดอร์ variables และไฟล์ saved_model.pb ที่แยกไว้ในโฟลเดอร์ย่อย 123

คุณจะอ้างอิงโฟลเดอร์ ssd_mobilenet_v2_2_320 ว่าเป็นโฟลเดอร์ SavedModel ก็ได้ 123 เป็นหมายเลขเวอร์ชันตัวอย่าง คุณเลือกหมายเลขอื่นได้หากต้องการ

โครงสร้างโฟลเดอร์ควรมีลักษณะเช่นนี้

42c8150a42033767.png

เริ่มแสดงโฆษณา TensorFlow

  • ในเทอร์มินัล ให้เริ่มแสดงโฆษณา TensorFlow ด้วย Docker แต่แทนที่ตัวยึดตําแหน่ง PATH/TO/SAVEDMODEL ด้วยเส้นทางสัมบูรณ์ของโฟลเดอร์ ssd_mobilenet_v2_2_320 ในคอมพิวเตอร์
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/ssd_mobilenet_v2_2" -e MODEL_NAME=ssd_mobilenet_v2_2 tensorflow/serving

Docker จะดาวน์โหลดอิมเมจการแสดงผล TensorFlow โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น TensorFlow Serving ควรจะเริ่มแสดง บันทึกควรมีลักษณะเหมือนข้อมูลโค้ดนี้

2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz
2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123
2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds.
2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests
2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: ssd_mobilenet_v2_2 version: 123}
2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

6 เชื่อมต่อแอป Android กับ TensorFlow Serving ผ่าน REST

แบ็กเอนด์พร้อมใช้งานแล้ว คุณจึงส่งคําขอของไคลเอ็นต์ไปยังการแสดงของ TensorFlow เพื่อตรวจหาออบเจ็กต์ภายในรูปภาพได้ คุณส่งคําขอไปยังการแสดง TensorFlow ได้ 2 วิธีดังนี้

  • REST
  • gRPC

ส่งคําขอและรับการตอบกลับผ่าน REST

มี 3 ขั้นตอนง่ายๆ ดังนี้

  • สร้างคําขอ REST
  • ส่งคําขอ REST ไปยังการแสดงผล TensorFlow
  • ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ REST และแสดง UI

คุณจะบรรลุเป้าหมายเหล่านี้ใน MainActivity.java.

สร้างคําขอ REST

ขณะนี้มีฟังก์ชัน createRESTRequest() ที่ว่างเปล่าในไฟล์ MainActivity.java คุณใช้ฟังก์ชันนี้เพื่อสร้างคําขอ REST ได้

private Request createRESTRequest() {
}

การแสดงผล TensorFlow ต้องการคําขอ POST ที่มี Tensor รูปภาพสําหรับโมเดล SSD MobileNet ที่คุณใช้ คุณจึงต้องดึงค่า RGB จากแต่ละพิกเซลของรูปภาพเป็นอาร์เรย์ แล้วรวมอาร์เรย์ไว้ใน JSON ซึ่งเป็นเพย์โหลดของคําขอ

  • เพิ่มโค้ดนี้ลงในฟังก์ชัน createRESTRequest()
//Create the REST request.
int[] inputImg = new int[INPUT_IMG_HEIGHT * INPUT_IMG_WIDTH];
int[][][][] inputImgRGB = new int[1][INPUT_IMG_HEIGHT][INPUT_IMG_WIDTH][3];
inputImgBitmap
.getPixels(inputImg, 0, INPUT_IMG_WIDTH, 0, 0, INPUT_IMG_WIDTH, INPUT_IMG_HEIGHT);
int pixel;
for (int i = 0; i < INPUT_IMG_HEIGHT; i++) {
   
for (int j = 0; j < INPUT_IMG_WIDTH; j++) {
   
// Extract RBG values from each pixel; alpha is ignored
    pixel
= inputImg[i * INPUT_IMG_WIDTH + j];
    inputImgRGB
[0][i][j][0] = ((pixel >> 16) & 0xff);
    inputImgRGB
[0][i][j][1] = ((pixel >> 8) & 0xff);
    inputImgRGB
[0][i][j][2] = ((pixel) & 0xff);
   
}
}

RequestBody requestBody =
   
RequestBody.create("{\"instances\": " + Arrays.deepToString(inputImgRGB) + "}", JSON);

Request request =
   
new Request.Builder()
       
.url("http://" + SERVER + ":" + REST_PORT + "/v1/models/" + MODEL_NAME + ":predict")
       
.post(requestBody)
       
.build();

return request;    

ส่งคําขอ REST ไปยังการแสดงโฆษณา TensorFlow

แอปช่วยให้ผู้ใช้เลือก REST หรือ gRPC เพื่อสื่อสารกับ TensorFlow Serving จึงมี 2 สาขาใน Listener onClick(View view)

predictButton.setOnClickListener(
   
new View.OnClickListener() {
       
@Override
       
public void onClick(View view) {
           
if (requestRadioGroup.getCheckedRadioButtonId() == R.id.rest) {
               
// TODO: REST request
           
}
           
else {

           
}
       
}
   
}
)
  • เพิ่มโค้ดนี้ลงในสาขา REST ของ Listener onClick(View view) เพื่อใช้ OkHttp เพื่อส่งคําขอไปยัง TensorFlow Serving ดังต่อไปนี้
// Send the REST request.
Request request = createRESTRequest();
try {
    client
=
       
new OkHttpClient.Builder()
           
.connectTimeout(20, TimeUnit.SECONDS)
           
.writeTimeout(20, TimeUnit.SECONDS)
           
.readTimeout(20, TimeUnit.SECONDS)
           
.callTimeout(20, TimeUnit.SECONDS)
           
.build();
   
Response response = client.newCall(request).execute();
   
JSONObject responseObject = new JSONObject(response.body().string());
    postprocessRESTResponse
(responseObject);
} catch (IOException | JSONException e) {
   
Log.e(TAG, e.getMessage());
    responseTextView
.setText(e.getMessage());
   
return;
}

ประมวลผลการตอบกลับ REST จาก TensorFlow Serving

โมเดล SDD MobileNet จะแสดงผลลัพธ์จํานวนหนึ่ง ซึ่งรวมถึง

  • num_detections: จํานวนการตรวจจับ
  • detection_scores: คะแนนการตรวจจับ
  • detection_classes: ดัชนีคลาสการตรวจจับ
  • detection_boxes: พิกัดกล่องขอบเขต

คุณใช้ฟังก์ชัน postprocessRESTResponse() ในการจัดการคําตอบ

private void postprocessRESTResponse(Predict.PredictResponse response) {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน postprocessRESTResponse()
// Process the REST response.
JSONArray predictionsArray = responseObject.getJSONArray("predictions");
//You only send one image, so you directly extract the first element.
JSONObject predictions = predictionsArray.getJSONObject(0);
// Argmax
int maxIndex = 0;
JSONArray detectionScores = predictions.getJSONArray("detection_scores");
for (int j = 0; j < predictions.getInt("num_detections"); j++) {
    maxIndex
=
        detectionScores
.getDouble(j) > detectionScores.getDouble(maxIndex + 1) ? j : maxIndex;
}
int detectionClass = predictions.getJSONArray("detection_classes").getInt(maxIndex);
JSONArray boundingBox = predictions.getJSONArray("detection_boxes").getJSONArray(maxIndex);
double ymin = boundingBox.getDouble(0);
double xmin = boundingBox.getDouble(1);
double ymax = boundingBox.getDouble(2);
double xmax = boundingBox.getDouble(3);
displayResult
(detectionClass, (float) ymin, (float) xmin, (float) ymax, (float) xmax);

ตอนนี้ฟังก์ชันหลังการประมวลผลจะดึงค่าที่คาดการณ์ไว้จากการตอบกลับ ระบุหมวดหมู่ที่น่าจะเป็นมากที่สุดของวัตถุ และพิกัดของจุดยอดกล่องล้อมรอบ และแสดงผลกรอบล้อมรอบการตรวจจับบน UI ครั้งล่าสุด

เรียกใช้

  1. คลิกpng เรียกใช้ ‘app' ในเมนูการนําทางแล้วรอให้แอปโหลด
  2. เลือก REST > Run inference

ระบบจะใช้เวลา 2-3 วินาทีก่อนที่แอปจะแสดงผลกรอบล้อมรอบของแมวและแสดง 17 เป็นหมวดหมู่ของออบเจ็กต์ที่แมปกับออบเจ็กต์ cat ในชุดข้อมูล COCO

5a1a32768dc516d6.png

7 เชื่อมต่อแอป Android กับ TensorFlow Serving ผ่าน gRPC

นอกจาก REST แล้ว TensorFlow Serving ยังรองรับ gRPC อีกด้วย

b6f4449c2c850b0e.png

gRPC เป็นเฟรมเวิร์ก Call Procedure Call (RPC) แบบโอเพนซอร์สที่มีประสิทธิภาพสูงและใช้งานได้กับทุกสภาพแวดล้อม เครื่องมือนี้จะเชื่อมบริการอย่างมีประสิทธิภาพทั่วทั้งศูนย์ข้อมูลต่างๆ ที่รองรับความสามารถในการจัดสรรภาระงาน การติดตาม การตรวจสอบประสิทธิภาพการทํางาน และการตรวจสอบสิทธิ์แบบเสียบปลั๊กได้ พบว่า gRPC มีประสิทธิภาพมากกว่า REST ในทางปฏิบัติ

ส่งคําขอและรับการตอบกลับด้วย gRPC

มี 4 ขั้นตอนง่ายๆ ดังนี้

  • [ไม่บังคับ] สร้างโค้ดไคลเอ็นต์ gRPC
  • สร้างคําขอ gRPC
  • ส่งคําขอ gRPC ไปยัง TensorFlow Serving
  • ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ gRPC และแสดง UI

คุณจะบรรลุเป้าหมายเหล่านี้ใน MainActivity.java.

ไม่บังคับ: สร้างโค้ดไคลเอ็นต์ gRPC

หากต้องการใช้ gRPC กับการให้บริการ TensorFlow คุณต้องทําตามเวิร์กโฟลว์ gRPC ดูข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียดได้ที่เอกสารประกอบ gRPC

a9d0e5cb543467b4.png

TensorFlow Serving และ TensorFlow จะกําหนดไฟล์ .proto ให้คุณ เมื่อคํานึงถึง TensorFlow และ TensorFlow Serving 2.8 จึงต้องมีไฟล์ .proto รายการต่อไปนี้

tensorflow/core/example/example.proto
tensorflow
/core/example/feature.proto
tensorflow
/core/protobuf/struct.proto
tensorflow
/core/protobuf/saved_object_graph.proto
tensorflow
/core/protobuf/saver.proto
tensorflow
/core/protobuf/trackable_object_graph.proto
tensorflow
/core/protobuf/meta_graph.proto
tensorflow
/core/framework/node_def.proto
tensorflow
/core/framework/attr_value.proto
tensorflow
/core/framework/function.proto
tensorflow
/core/framework/types.proto
tensorflow
/core/framework/tensor_shape.proto
tensorflow
/core/framework/full_type.proto
tensorflow
/core/framework/versions.proto
tensorflow
/core/framework/op_def.proto
tensorflow
/core/framework/graph.proto
tensorflow
/core/framework/tensor.proto
tensorflow
/core/framework/resource_handle.proto
tensorflow
/core/framework/variable.proto

tensorflow_serving
/apis/inference.proto
tensorflow_serving
/apis/classification.proto
tensorflow_serving
/apis/predict.proto
tensorflow_serving
/apis/regression.proto
tensorflow_serving
/apis/get_model_metadata.proto
tensorflow_serving
/apis/input.proto
tensorflow_serving
/apis/prediction_service.proto
tensorflow_serving
/apis/model.proto
  • หากต้องการสร้างโค้ดนี้ ให้เพิ่มโค้ดนี้ลงในไฟล์ app/build.gradle
apply plugin: 'com.google.protobuf'

protobuf
{
    protoc
{ artifact = 'com.google.protobuf:protoc:3.11.0' }
    plugins
{
        grpc
{ artifact = 'io.grpc:protoc-gen-grpc-java:1.29.0'
       
}
   
}
    generateProtoTasks
{
        all
().each { task ->
            task
.builtins {
                java
{ option 'lite' }
           
}
            task
.plugins {
                grpc
{ option 'lite' }
           
}
       
}
   
}
}

สร้างคําขอ gRPC

คุณสร้างคําขอ gRPC ในฟังก์ชัน createGRPCRequest() เช่นเดียวกับคําขอ REST

private Request createGRPCRequest() {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน createGRPCRequest():
if (stub == null) {
  channel
= ManagedChannelBuilder.forAddress(SERVER, GRPC_PORT).usePlaintext().build();
  stub
= PredictionServiceGrpc.newBlockingStub(channel);
}

Model.ModelSpec.Builder modelSpecBuilder = Model.ModelSpec.newBuilder();
modelSpecBuilder
.setName(MODEL_NAME);
modelSpecBuilder
.setVersion(Int64Value.of(MODEL_VERSION));
modelSpecBuilder
.setSignatureName(SIGNATURE_NAME);

Predict.PredictRequest.Builder builder = Predict.PredictRequest.newBuilder();
builder
.setModelSpec(modelSpecBuilder);

TensorProto.Builder tensorProtoBuilder = TensorProto.newBuilder();
tensorProtoBuilder
.setDtype(DataType.DT_UINT8);
TensorShapeProto.Builder tensorShapeBuilder = TensorShapeProto.newBuilder();
tensorShapeBuilder
.addDim(TensorShapeProto.Dim.newBuilder().setSize(1));
tensorShapeBuilder
.addDim(TensorShapeProto.Dim.newBuilder().setSize(INPUT_IMG_HEIGHT));
tensorShapeBuilder
.addDim(TensorShapeProto.Dim.newBuilder().setSize(INPUT_IMG_WIDTH));
tensorShapeBuilder
.addDim(TensorShapeProto.Dim.newBuilder().setSize(3));
tensorProtoBuilder
.setTensorShape(tensorShapeBuilder.build());
int[] inputImg = new int[INPUT_IMG_HEIGHT * INPUT_IMG_WIDTH];
inputImgBitmap
.getPixels(inputImg, 0, INPUT_IMG_WIDTH, 0, 0, INPUT_IMG_WIDTH, INPUT_IMG_HEIGHT);
int pixel;
for (int i = 0; i < INPUT_IMG_HEIGHT; i++) {
   
for (int j = 0; j < INPUT_IMG_WIDTH; j++) {
   
// Extract RBG values from each pixel; alpha is ignored.
    pixel
= inputImg[i * INPUT_IMG_WIDTH + j];
    tensorProtoBuilder
.addIntVal((pixel >> 16) & 0xff);
    tensorProtoBuilder
.addIntVal((pixel >> 8) & 0xff);
    tensorProtoBuilder
.addIntVal((pixel) & 0xff);
   
}
}
TensorProto tensorProto = tensorProtoBuilder.build();

builder
.putInputs("input_tensor", tensorProto);

builder
.addOutputFilter("num_detections");
builder
.addOutputFilter("detection_boxes");
builder
.addOutputFilter("detection_classes");
builder
.addOutputFilter("detection_scores");

return builder.build();

ส่งคําขอ gRPC ไปยังการแสดงผล TensorFlow

คุณฟัง onClick(View view) Listener ได้แล้ว

predictButton.setOnClickListener(
   
new View.OnClickListener() {
       
@Override
       
public void onClick(View view) {
           
if (requestRadioGroup.getCheckedRadioButtonId() == R.id.rest) {

           
}
           
else {
               
// TODO: gRPC request
           
}
       
}
   
}
)
  • เพิ่มโค้ดนี้ลงในสาขา gRPC
try {
   
Predict.PredictRequest request = createGRPCRequest();
   
Predict.PredictResponse response = stub.predict(request);
    postprocessGRPCResponse
(response);
} catch (Exception e) {
   
Log.e(TAG, e.getMessage());
    responseTextView
.setText(e.getMessage());
   
return;
}

ประมวลผลการตอบสนอง gRPC จาก TensorFlow Serving

คุณใช้ฟังก์ชัน postprocessGRPCResponse() เพื่อจัดการการตอบกลับได้เช่นเดียวกับ gRPC

private void postprocessGRPCResponse(Predict.PredictResponse response) {

}
  • เพิ่มโค้ดนี้ลงในฟังก์ชัน postprocessGRPCResponse()
// Process the response.
float numDetections = response.getOutputsMap().get("num_detections").getFloatValList().get(0);
List<Float> detectionScores =    response.getOutputsMap().get("detection_scores").getFloatValList();
int maxIndex = 0;
for (int j = 0; j < numDetections; j++) {
    maxIndex
= detectionScores.get(j) > detectionScores.get(maxIndex + 1) ? j : maxIndex;
}
Float detectionClass =    response.getOutputsMap().get("detection_classes").getFloatValList().get(maxIndex);
List<Float> boundingBoxValues =    response.getOutputsMap().get("detection_boxes").getFloatValList();
float ymin = boundingBoxValues.get(maxIndex * 4);
float xmin = boundingBoxValues.get(maxIndex * 4 + 1);
float ymax = boundingBoxValues.get(maxIndex * 4 + 2);
float xmax = boundingBoxValues.get(maxIndex * 4 + 3);
displayResult
(detectionClass.intValue(), ymin, xmin, ymax, xmax);

ตอนนี้ฟังก์ชันหลังการประมวลผลสามารถแยกค่าที่คาดการณ์ไว้จากการตอบกลับ และแสดงผลกล่องขอบเขตการตรวจจับใน UI ได้

เรียกใช้

  1. คลิกpng เรียกใช้ ‘app' ในเมนูการนําทางแล้วรอให้แอปโหลด
  2. เลือก gRPC > Run inference

โปรดรอ 2-3 วินาทีก่อนที่แอปจะแสดงผลกรอบล้อมรอบของแมวและแสดง 17 เป็นหมวดหมู่ของออบเจ็กต์ที่แมปกับหมวดหมู่ cat ในชุดข้อมูล COCO