برای فراخوانی یک API گوگل کلود از برنامه خود، باید یک API REST واسط ایجاد کنید که مجوزها را مدیریت کرده و از مقادیر مخفی مانند کلیدهای API محافظت کند. سپس باید در برنامه تلفن همراه خود کدی بنویسید تا احراز هویت شده و با این سرویس واسط ارتباط برقرار کند.
یک راه برای ایجاد این REST API استفاده از Firebase Authentication and Functions است که یک دروازه مدیریتشده و بدون سرور به APIهای Google Cloud در اختیار شما قرار میدهد که احراز هویت را مدیریت میکند و میتوان آن را از طریق برنامه تلفن همراه شما با SDKهای از پیش ساخته شده فراخوانی کرد.
این راهنما نحوه استفاده از این تکنیک را برای فراخوانی API Cloud Vision از برنامه شما نشان میدهد. این روش به همه کاربران احراز هویت شده اجازه میدهد تا از طریق پروژه Cloud شما به سرویسهای دارای صورتحساب Cloud Vision دسترسی پیدا کنند، بنابراین قبل از ادامه، در نظر بگیرید که آیا این مکانیسم احراز هویت برای مورد استفاده شما کافی است یا خیر.
قبل از اینکه شروع کنی
پروژه خود را پیکربندی کنید
- اگر هنوز Firebase را به پروژه اندروید خود اضافه نکردهاید، آن را اضافه کنید.
اگر هنوز APIهای مبتنی بر ابر را برای پروژه خود فعال نکردهاید، اکنون این کار را انجام دهید:
- صفحه Firebase ML APIs را در کنسول Firebase باز کنید.
اگر هنوز پروژه خود را به طرح قیمتگذاری پرداخت در محل Blaze ارتقا ندادهاید، برای انجام این کار روی ارتقا کلیک کنید. (فقط در صورتی که پروژه شما در طرح قیمتگذاری Blaze نباشد، از شما خواسته میشود که آن را ارتقا دهید.)
فقط پروژههای موجود در طرح قیمتگذاری Blaze میتوانند از APIهای مبتنی بر ابر استفاده کنند.
- اگر APIهای مبتنی بر ابر از قبل فعال نشدهاند، روی فعال کردن APIهای مبتنی بر ابر کلیک کنید.
- کلیدهای API فایربیس موجود خود را پیکربندی کنید تا دسترسی به API کلود ویژن را غیرفعال کنید:
- صفحه اعتبارنامهها (Credentials) کنسول Cloud را باز کنید.
- برای هر کلید API موجود در لیست، نمای ویرایش را باز کنید و در بخش محدودیتهای کلید، تمام APIهای موجود به جز API Cloud Vision را به لیست اضافه کنید.
تابع قابل فراخوانی را مستقر کنید
در مرحله بعد، تابع ابری (Cloud Function) را که برای ایجاد پل بین برنامه خود و API Cloud Vision استفاده خواهید کرد، مستقر کنید. مخزن functions-samples شامل مثالی است که میتوانید از آن استفاده کنید.
به طور پیشفرض، دسترسی به API Cloud Vision از طریق این تابع، فقط به کاربران احراز هویت شده برنامه شما اجازه دسترسی به API Cloud Vision را میدهد. میتوانید این تابع را برای الزامات مختلف تغییر دهید.
برای استقرار تابع:
- مخزن functions-samples را کلون یا دانلود کنید و به دایرکتوری
Node-1st-gen/vision-annotate-imageتغییر دهید:git clone https://github.com/firebase/functions-samplescd Node-1st-gen/vision-annotate-image - نصب وابستگیها:
cd functionsnpm installcd .. - اگر Firebase CLI را ندارید، آن را نصب کنید .
- یک پروژه Firebase را در دایرکتوری
vision-annotate-imageراهاندازی کنید. در صورت درخواست، پروژه خود را از لیست انتخاب کنید.firebase init
- تابع را مستقر کنید:
firebase deploy --only functions:annotateImage
اضافه کردن Firebase Auth به برنامه شما
تابع فراخوانیشدهی فوق، هرگونه درخواستی از کاربران احراز هویت نشدهی برنامهی شما را رد میکند. اگر قبلاً این کار را انجام ندادهاید، باید Firebase Auth را به برنامهی خود اضافه کنید.
وابستگیهای لازم را به برنامه خود اضافه کنید
<project>/<app-module>/build.gradle.kts یا <project>/<app-module>/build.gradle ): implementation("com.google.firebase:firebase-functions:22.1.1") implementation("com.google.code.gson:gson:2.8.6")
حالا شما آمادهاید تا متن را در تصاویر تشخیص دهید.
۱. تصویر ورودی را آماده کنید
برای فراخوانی Cloud Vision، تصویر باید به صورت یک رشته کدگذاری شده با base64 فرمت شود. برای پردازش تصویر از یک فایل ذخیره شده، URI:- تصویر را به عنوان یک شیء
Bitmapدریافت کنید:Kotlin
var bitmap: Bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
Java
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
- در صورت تمایل، برای صرفهجویی در پهنای باند، مقیاس تصویر را کاهش دهید. به اندازههای تصویر توصیهشده توسط Cloud Vision مراجعه کنید.
Kotlin
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
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
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640)
Java
// Scale down bitmap size bitmap = scaleBitmapDown(bitmap, 640);
- شیء بیتمپ را به یک رشته کدگذاری شده با base64 تبدیل کنید:
Kotlin
// 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)
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);
تصویر نمایش داده شده توسط شیء
Bitmap باید عمودی باشد و نیازی به چرخش اضافی نباشد. ۲. تابع قابل فراخوانی را برای تشخیص متن فراخوانی کنید
برای تشخیص متن در یک تصویر، تابع قابل فراخوانی را فراخوانی کنید و یک درخواست JSON Cloud Vision ارسال کنید.
ابتدا، یک نمونه از توابع ابری را مقداردهی اولیه کنید:
Kotlin
private lateinit var functions: FirebaseFunctions // ... functions = Firebase.functionsJava
private FirebaseFunctions mFunctions; // ... mFunctions = FirebaseFunctions.getInstance();یک متد برای فراخوانی تابع تعریف کنید:
Kotlin
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)) } }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())); } }); }درخواست JSON را ایجاد کنید. API Cloud Vision از دو نوع تشخیص متن پشتیبانی میکند:
TEXT_DETECTIONوDOCUMENT_TEXT_DETECTION. برای تفاوت بین این دو مورد استفاده، به مستندات OCR Cloud Vision مراجعه کنید.Kotlin
// 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("type", JsonPrimitive("TEXT_DETECTION")) // Alternatively, for DOCUMENT_TEXT_DETECTION: // feature.add("type", JsonPrimitive("DOCUMENT_TEXT_DETECTION")) val features = JsonArray() features.add(feature) request.add("features", features)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("type", new JsonPrimitive("TEXT_DETECTION")); // Alternatively, for DOCUMENT_TEXT_DETECTION: //feature.add("type", new JsonPrimitive("DOCUMENT_TEXT_DETECTION")); JsonArray features = new JsonArray(); features.add(feature); request.add("features", features);در صورت تمایل، برای کمک به تشخیص زبان ، نکات زبانی ارائه دهید (به زبانهای پشتیبانیشده مراجعه کنید):
Kotlin
val imageContext = JsonObject() val languageHints = JsonArray() languageHints.add("en") imageContext.add("languageHints", languageHints) request.add("imageContext", imageContext)Java
JsonObject imageContext = new JsonObject(); JsonArray languageHints = new JsonArray(); languageHints.add("en"); imageContext.add("languageHints", languageHints); request.add("imageContext", imageContext);در نهایت، تابع را فراخوانی کنید:
Kotlin
annotateImage(request.toString()) .addOnCompleteListener { task -> if (!task.isSuccessful) { // Task failed with an exception // ... } else { // Task completed successfully // ... } }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 // ... } } });
۳. استخراج متن از بلوکهای متن شناختهشده
اگر عملیات تشخیص متن با موفقیت انجام شود، یک پاسخ JSON از نوع BatchAnnotateImagesResponse در نتیجهی وظیفه بازگردانده میشود. حاشیهنویسیهای متن را میتوان در شیءfullTextAnnotation یافت. میتوانید متن شناساییشده را به صورت یک رشته در فیلد text دریافت کنید. برای مثال:
Kotlin
val annotation = task.result!!.asJsonArray[0].asJsonObject["fullTextAnnotation"].asJsonObject
System.out.format("%nComplete annotation:")
System.out.format("%n%s", annotation["text"].asString)
Java
JsonObject annotation = task.getResult().getAsJsonArray().get(0).getAsJsonObject().get("fullTextAnnotation").getAsJsonObject();
System.out.format("%nComplete annotation:%n");
System.out.format("%s%n", annotation.get("text").getAsString());
همچنین میتوانید اطلاعات مربوط به نواحی خاص تصویر را دریافت کنید. برای هر block ، paragraph ، word و symbol ، میتوانید متن تشخیص داده شده در ناحیه و مختصات مرزی ناحیه را دریافت کنید. به عنوان مثال:
Kotlin
for (page in annotation["pages"].asJsonArray) {
var pageText = ""
for (block in page.asJsonObject["blocks"].asJsonArray) {
var blockText = ""
for (para in block.asJsonObject["paragraphs"].asJsonArray) {
var paraText = ""
for (word in para.asJsonObject["words"].asJsonArray) {
var wordText = ""
for (symbol in word.asJsonObject["symbols"].asJsonArray) {
wordText += symbol.asJsonObject["text"].asString
System.out.format(
"Symbol text: %s (confidence: %f)%n",
symbol.asJsonObject["text"].asString,
symbol.asJsonObject["confidence"].asFloat,
)
}
System.out.format(
"Word text: %s (confidence: %f)%n%n",
wordText,
word.asJsonObject["confidence"].asFloat,
)
System.out.format("Word bounding box: %s%n", word.asJsonObject["boundingBox"])
paraText = String.format("%s%s ", paraText, wordText)
}
System.out.format("%nParagraph: %n%s%n", paraText)
System.out.format("Paragraph bounding box: %s%n", para.asJsonObject["boundingBox"])
System.out.format("Paragraph Confidence: %f%n", para.asJsonObject["confidence"].asFloat)
blockText += paraText
}
pageText += blockText
}
}
Java
for (JsonElement page : annotation.get("pages").getAsJsonArray()) {
StringBuilder pageText = new StringBuilder();
for (JsonElement block : page.getAsJsonObject().get("blocks").getAsJsonArray()) {
StringBuilder blockText = new StringBuilder();
for (JsonElement para : block.getAsJsonObject().get("paragraphs").getAsJsonArray()) {
StringBuilder paraText = new StringBuilder();
for (JsonElement word : para.getAsJsonObject().get("words").getAsJsonArray()) {
StringBuilder wordText = new StringBuilder();
for (JsonElement symbol : word.getAsJsonObject().get("symbols").getAsJsonArray()) {
wordText.append(symbol.getAsJsonObject().get("text").getAsString());
System.out.format("Symbol text: %s (confidence: %f)%n", symbol.getAsJsonObject().get("text").getAsString(), symbol.getAsJsonObject().get("confidence").getAsFloat());
}
System.out.format("Word text: %s (confidence: %f)%n%n", wordText.toString(), word.getAsJsonObject().get("confidence").getAsFloat());
System.out.format("Word bounding box: %s%n", word.getAsJsonObject().get("boundingBox"));
paraText.append(wordText.toString()).append(" ");
}
System.out.format("%nParagraph:%n%s%n", paraText);
System.out.format("Paragraph bounding box: %s%n", para.getAsJsonObject().get("boundingBox"));
System.out.format("Paragraph Confidence: %f%n", para.getAsJsonObject().get("confidence").getAsFloat());
blockText.append(paraText);
}
pageText.append(blockText);
}
}