ในการเรียก Google Cloud API จากแอปของคุณ คุณต้องสร้าง REST API ระดับกลางที่จัดการการให้สิทธิ์และปกป้องค่าลับ เช่น คีย์ API จากนั้นคุณจะต้องเขียนโค้ดในแอพมือถือของคุณเพื่อตรวจสอบและสื่อสารกับบริการระดับกลางนี้
วิธีหนึ่งในการสร้าง REST API นี้คือการใช้ Firebase Authentication and Functions ซึ่งให้เกตเวย์แบบไร้เซิร์ฟเวอร์ที่มีการจัดการไปยัง Google Cloud API ที่จัดการการตรวจสอบสิทธิ์ และสามารถเรียกได้จากแอปบนอุปกรณ์เคลื่อนที่ด้วย SDK ที่สร้างไว้ล่วงหน้า
คู่มือนี้สาธิตวิธีใช้เทคนิคนี้เพื่อเรียก Cloud Vision API จากแอปของคุณ วิธีนี้จะอนุญาตให้ผู้ใช้ที่ตรวจสอบสิทธิ์ทั้งหมดเข้าถึงบริการที่เรียกเก็บเงิน Cloud Vision ผ่านโปรเจ็กต์ Cloud ของคุณ ดังนั้นให้พิจารณาว่ากลไกการตรวจสอบสิทธิ์นี้เพียงพอสำหรับกรณีการใช้งานของคุณหรือไม่ก่อนดำเนินการต่อ
ก่อนจะเริ่ม
กำหนดค่าโครงการของคุณ
- หากคุณยังไม่ได้ เพิ่ม Firebase ในโครงการ Android ของคุณ
หากคุณยังไม่ได้เปิดใช้งาน API แบบ Cloud-based สำหรับโปรเจ็กต์ของคุณ ให้ดำเนินการดังนี้:
- เปิดหน้า Firebase ML APIs ของคอนโซล Firebase
หากคุณยังไม่ได้อัปเกรดโปรเจ็กต์ของคุณเป็นแผนราคา Blaze ให้คลิก อัปเกรด เพื่อดำเนินการดังกล่าว (คุณจะได้รับแจ้งให้อัปเกรดเฉพาะเมื่อโปรเจ็กต์ของคุณไม่อยู่ในแผน Blaze)
เฉพาะโปรเจ็กต์ระดับ Blaze เท่านั้นที่สามารถใช้ API แบบคลาวด์ได้
- หากไม่ได้เปิดใช้งาน API แบบคลาวด์ ให้คลิก เปิดใช้งาน API แบบคลาวด์
- กำหนดค่าคีย์ Firebase API ที่มีอยู่ของคุณเพื่อไม่อนุญาตให้เข้าถึง Cloud Vision API:
- เปิดหน้า ข้อมูลประจำตัว ของคอนโซลระบบคลาวด์
- สำหรับคีย์ API แต่ละรายการในรายการ ให้เปิดมุมมองการแก้ไข และในส่วนการจำกัดคีย์ ให้เพิ่ม API ที่มีอยู่ ทั้งหมดยกเว้น Cloud Vision API ลงในรายการ
ปรับใช้ฟังก์ชันที่เรียกได้
ขั้นต่อไป ปรับใช้ Cloud Function ที่คุณจะใช้เพื่อเชื่อมโยงแอปของคุณและ Cloud Vision API ที่เก็บ functions-samples
มีตัวอย่างที่คุณสามารถใช้ได้
ตามค่าเริ่มต้น การเข้าถึง Cloud Vision API ผ่านฟังก์ชันนี้จะอนุญาตให้เฉพาะผู้ใช้ที่ตรวจสอบสิทธิ์ของแอปของคุณเข้าถึง Cloud Vision API ได้ คุณสามารถปรับเปลี่ยนฟังก์ชันสำหรับข้อกำหนดต่างๆ ได้
ในการปรับใช้ฟังก์ชัน:
- โคลนหรือดาวน์โหลด ฟังก์ชั่นตัวอย่าง repo และเปลี่ยนเป็นไดเร็กทอรี
vision-annotate-image
:git clone https://github.com/firebase/functions-samples
cd vision-annotate-image
- ติดตั้งการพึ่งพา:
cd functions
npm install
cd ..
- หากคุณไม่มี Firebase CLI ให้ ติดตั้ง
- เริ่มต้นโปรเจ็กต์ Firebase ในไดเร็กทอรี
vision-annotate-image
เมื่อได้รับแจ้ง ให้เลือกโครงการของคุณในรายการfirebase init
- ปรับใช้ฟังก์ชัน:
firebase deploy --only functions:annotateImage
เพิ่ม Firebase Auth ให้กับแอปของคุณ
ฟังก์ชัน callable ที่ปรับใช้ด้านบนจะปฏิเสธคำขอใดๆ จากผู้ใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์ของแอปของคุณ หากยังไม่ได้ดำเนินการ คุณจะต้อง เพิ่ม Firebase Auth ในแอปของคุณ
เพิ่มการพึ่งพาที่จำเป็นให้กับแอปของคุณ
implementation 'com.google.firebase:firebase-functions:20.1.0' implementation 'com.google.code.gson:gson:2.8.6'
ตอนนี้คุณพร้อมที่จะติดป้ายกำกับรูปภาพแล้ว
1. เตรียมอิมเมจอินพุต
ในการเรียก Cloud Vision รูปภาพต้องได้รับการจัดรูปแบบเป็นสตริงที่เข้ารหัส base64 ในการประมวลผลรูปภาพจากไฟล์ URI ที่บันทึกไว้:- รับภาพเป็นวัตถุ
Bitmap
:Java
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
Kotlin+KTX
var bitmap: Bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
- คุณสามารถเลือกลดขนาดรูปภาพเพื่อประหยัดแบนด์วิดท์ ดู ขนาดรูปภาพที่แนะนำของ Cloud Vision
Java
private Bitmap scaleBitmapDown(Bitmap bitmap, int maxDimension) { int originalWidth = bitmap.getWidth(); int originalHeight = bitmap.getHeight(); int resizedWidth = maxDimension; int resizedHeight = maxDimension; if (originalHeight > originalWidth) { resizedHeight = maxDimension; resizedWidth = (int) (resizedHeight * (float) originalWidth / (float) originalHeight); } else if (originalWidth > originalHeight) { resizedWidth = maxDimension; resizedHeight = (int) (resizedWidth * (float) originalHeight / (float) originalWidth); } else if (originalHeight == originalWidth) { resizedHeight = maxDimension; resizedWidth = maxDimension; } return Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false); }
Kotlin+KTX
private fun scaleBitmapDown(bitmap: Bitmap, maxDimension: Int): Bitmap { val originalWidth = bitmap.width val originalHeight = bitmap.height var resizedWidth = maxDimension var resizedHeight = maxDimension if (originalHeight > originalWidth) { resizedHeight = maxDimension resizedWidth = (resizedHeight * originalWidth.toFloat() / originalHeight.toFloat()).toInt() } else if (originalWidth > originalHeight) { resizedWidth = maxDimension resizedHeight = (resizedWidth * originalHeight.toFloat() / originalWidth.toFloat()).toInt() } else if (originalHeight == originalWidth) { resizedHeight = maxDimension resizedWidth = maxDimension } return Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false) }
Java
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640);
Kotlin+KTX
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640)
- แปลงวัตถุบิตแมปเป็นสตริงที่เข้ารหัส base64:
Java
// Convert bitmap to base64 encoded string ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); byte[] imageBytes = byteArrayOutputStream.toByteArray(); String base64encoded = Base64.encodeToString(imageBytes, Base64.NO_WRAP);
Kotlin+KTX
// Convert bitmap to base64 encoded string val byteArrayOutputStream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream) val imageBytes: ByteArray = byteArrayOutputStream.toByteArray() val base64encoded = Base64.encodeToString(imageBytes, Base64.NO_WRAP)
รูปภาพที่แสดงโดยวัตถุ
Bitmap
จะต้องตั้งตรง โดยไม่ต้องหมุนเพิ่มเติม2. เรียกใช้ฟังก์ชันที่เรียกได้เพื่อติดป้ายกำกับรูปภาพ
หากต้องการติดป้ายกำกับวัตถุในรูปภาพ ให้เรียกใช้ฟังก์ชันที่เรียกได้ โดย ส่งคำขอ JSON Cloud Visionขั้นแรก เริ่มต้นอินสแตนซ์ของ Cloud Functions:
Java
private FirebaseFunctions mFunctions; // ... mFunctions = FirebaseFunctions.getInstance();
Kotlin+KTX
private lateinit var functions: FirebaseFunctions // ... functions = Firebase.functions
กำหนดวิธีการเรียกใช้ฟังก์ชัน:
Java
private Task<JsonElement> annotateImage(String requestJson) { return mFunctions .getHttpsCallable("annotateImage") .call(requestJson) .continueWith(new Continuation<HttpsCallableResult, JsonElement>() { @Override public JsonElement then(@NonNull Task<HttpsCallableResult> task) { // This continuation runs on either success or failure, but if the task // has failed then getResult() will throw an Exception which will be // propagated down. return JsonParser.parseString(new Gson().toJson(task.getResult().getData())); } }); }
Kotlin+KTX
private fun annotateImage(requestJson: String): Task<JsonElement> { return functions .getHttpsCallable("annotateImage") .call(requestJson) .continueWith { task -> // This continuation runs on either success or failure, but if the task // has failed then result will throw an Exception which will be // propagated down. val result = task.result?.data JsonParser.parseString(Gson().toJson(result)) } }
สร้างคำขอ JSON โดยตั้งค่า Type เป็น
LABEL_DETECTION
:Java
// Create json request to cloud vision JsonObject request = new JsonObject(); // Add image to request JsonObject image = new JsonObject(); image.add("content", new JsonPrimitive(base64encoded)); request.add("image", image); //Add features to the request JsonObject feature = new JsonObject(); feature.add("maxResults", new JsonPrimitive(5)); feature.add("type", new JsonPrimitive("LABEL_DETECTION")); JsonArray features = new JsonArray(); features.add(feature); request.add("features", features);
Kotlin+KTX
// Create json request to cloud vision val request = JsonObject() // Add image to request val image = JsonObject() image.add("content", JsonPrimitive(base64encoded)) request.add("image", image) //Add features to the request val feature = JsonObject() feature.add("maxResults", JsonPrimitive(5)) feature.add("type", JsonPrimitive("LABEL_DETECTION")) val features = JsonArray() features.add(feature) request.add("features", features)
ในที่สุด เรียกใช้ฟังก์ชัน:
Java
annotateImage(request.toString()) .addOnCompleteListener(new OnCompleteListener<JsonElement>() { @Override public void onComplete(@NonNull Task<JsonElement> task) { if (!task.isSuccessful()) { // Task failed with an exception // ... } else { // Task completed successfully // ... } } });
Kotlin+KTX
annotateImage(request.toString()) .addOnCompleteListener { task -> if (!task.isSuccessful) { // Task failed with an exception // ... } else { // Task completed successfully // ... } }
3. รับข้อมูลเกี่ยวกับวัตถุที่มีป้ายกำกับ
หากการดำเนินการติดป้ายกำกับรูปภาพสำเร็จ การตอบสนอง JSON ของ BatchAnnotateImagesResponse จะถูกส่งคืนในผลลัพธ์ของงาน แต่ละอ็อบเจ็กต์ในอาlabelAnnotations
แสดงถึงสิ่งที่ติดป้ายกำกับไว้ในรูปภาพ สำหรับแต่ละป้ายชื่อ คุณสามารถรับคำอธิบายข้อความของป้ายชื่อ รหัสเอนทิตีกราฟความรู้ (ถ้ามี) และคะแนนความเชื่อมั่นของการจับคู่ ตัวอย่างเช่น: Java
for (JsonElement label : task.getResult().getAsJsonArray().get(0).getAsJsonObject().get("labelAnnotations").getAsJsonArray()) {
JsonObject labelObj = label.getAsJsonObject();
String text = labelObj.get("description").getAsString();
String entityId = labelObj.get("mid").getAsString();
float score = labelObj.get("score").getAsFloat();
}
Kotlin+KTX
for (label in task.result!!.asJsonArray[0].asJsonObject["labelAnnotations"].asJsonArray) {
val labelObj = label.asJsonObject
val text = labelObj["description"]
val entityId = labelObj["mid"]
val confidence = labelObj["score"]
}