شناسایی ایمن نوشتار در تصاویر با Cloud Vision بااستفاده از «احراز هویت Firebase» و «توابع» در پلاتفرم‌های Apple

برای فراخوانی Google Cloud API از برنامه‌تان، باید یک REST API واسطه ایجاد کنید که مجوزدهی را مدیریت کند و از مقادیر محرمانه مانند کلیدهای API محافظت کند. سپس باید در برنامه تلفن همراهتان کدی بنویسید تا با این سرویس واسطه اصالت‌سنجی و ارتباط برقرار کند.

یکی از راه‌های ایجاد این REST API استفاده از Firebase Authentication و Functions است که به شما یک درگاه مدیریت‌شده و بدون سرور به Google Cloud APIs می‌دهد که اصالت‌سنجی را مدیریت می‌کند و می‌تواند از برنامه تلفن همراه شما با کیت‌های توسعه نرم‌افزار ازپیش‌ساخته‌شده فراخوانی شود.

این راهنما نشان می‌دهد که چگونه از این تکنیک برای فراخوانی Cloud Vision API از برنامه‌تان استفاده کنید. این روش به همه کاربران اصالت‌سنجی‌شده اجازه می‌دهد تا ازطریق پروژه Cloud شما به سرویس‌های صورت‌حساب Cloud Vision دسترسی داشته باشند، بنابراین قبل‌از ادامه، درنظر بگیرید که آیا این سازوکار اصالت‌سنجی برای مورد استفاده شما کافی است یا نه.

قبل از شروع

پیکربندی پروژه

اگر Firebase را به برنامه‌تان اضافه نکرده‌اید، با دنبال کردن مراحل موجود در راهنمای شروع به کار این کار را انجام دهید.

از Swift Package Manager برای نصب و مدیریت وابستگی‌های Firebase استفاده کنید.

  1. در Xcode، درحالی‌که پروژه برنامه‌تان باز است، به File (فایل) > Add Packages (افزودن بسته‌ها) بروید.
  2. وقتی خواسته شد، مخزن کیت توسعه نرم‌افزار Firebase برای پلاتفرم‌های Apple را اضافه کنید:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. کتابخانه Firebase ML را انتخاب کنید.
  5. پرچم -ObjC را به بخش Other Linker Flags (سایر پرچم‌های پیونددهنده) در تنظیمات ساخت هدف اضافه کنید.
  6. پس‌از اتمام، Xcode به‌طور خودکار شروع به حل و بارگیری وابستگی‌های شما در پس‌زمینه می‌کند.

سپس، برخی‌از راه‌اندازی‌های درون‌برنامه را انجام دهید:

  1. در برنامه‌تان، Firebase را وارد کنید:

    Swift

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

چند مرحله پیکربندی دیگر باقی مانده است و سپس آماده شروع هستیم:

  1. اگر قبلاً میاناهای برنامه‌سازی کاربردی ابری را برای پروژه‌تان فعال نکرده‌اید، اکنون این کار را انجام دهید:

    1. Firebase ML صفحه API را در Firebase کنسول باز کنید.
    2. اگر قبلاً پروژه‌تان را به طرح قیمت‌گذاری Blaze پرداخت به اندازه استفاده ارتقا نداده‌اید، روی ارتقا دادن کلیک کنید تا این کار را انجام دهید. (فقط درصورتی از شما خواسته می‌شود ارتقا دهید که پروژه‌تان در طرح قیمت‌گذاری Blaze نباشد.)

      فقط پروژه‌هایی که در طرح قیمت‌گذاری Blaze هستند می‌توانند از میاناهای برنامه‌سازی کاربردی مبتنی بر Cloud استفاده کنند.

    3. اگر میاناهای برنامه‌سازی کاربردی مبتنی بر Cloud ازقبل فعال نشده‌اند، روی فعال کردن میاناهای برنامه‌سازی کاربردی مبتنی بر Cloud کلیک کنید.
  2. کلیدهای Firebase API موجودتان را پیکربندی کنید تا دسترسی به Cloud Vision API را غیرمجاز کنید:
    1. صفحه اعتبارنامه‌ها را در کنسول Cloud باز کنید.
    2. برای هر کلید میانای برنامه‌سازی کاربردی در فهرست، نمای ویرایش را باز کنید و در بخش «محدودیت‌های کلید»، همه میاناهای برنامه‌سازی کاربردی دردسترس را به‌جز میانای برنامه‌سازی کاربردی Cloud Vision به فهرست اضافه کنید.

استقرار تابع قابل‌فراخوانی

سپس، Cloud Function را که برای پل زدن بین برنامه و Cloud Vision API استفاده خواهید کرد مستقر کنید. مخزن functions-samples حاوی نمونه‌ای است که می‌توانید از آن استفاده کنید.

به‌طور پیش‌فرض، دسترسی به Cloud Vision API ازطریق این تابع فقط به کاربران اصالت‌سنجی‌شده برنامه‌تان اجازه می‌دهد به Cloud Vision API دسترسی داشته باشند. می‌توانید تابع را برای الزامات مختلف اصلاح کنید.

برای استقرار تابع:

  1. مخزن functions-samples را شبیه‌سازی یا بارگیری کنید و به دایرکتوری Node-1st-gen/vision-annotate-image بروید:
    git clone https://github.com/firebase/functions-samples
    cd Node-1st-gen/vision-annotate-image
    
  2. نصب وابستگی‌ها:
    cd functions
    npm install
    cd ..
  3. اگر Firebase CLI را ندارید، آن را نصب کنید.
  4. پروژه Firebase را در فهرست راهنمای vision-annotate-image مقداردهی اولیه کنید. وقتی درخواست شد، پروژه‌تان را در فهرست انتخاب کنید.
    firebase init
  5. تابع را مستقر کنید:
    firebase deploy --only functions:annotateImage

افزودن Firebase Auth به برنامه

تابع قابل‌فراخوانی که در بالا مستقر شده است، هر درخواستی را از کاربران غیرمعتبر برنامه‌تان رد خواهد کرد. اگر قبلاً این کار را نکرده‌اید، باید Firebase Auth را به برنامه‌تان اضافه کنید.

افزودن وابستگی‌های لازم به برنامه

از Swift Package Manager برای نصب کتابخانه Cloud Functions for Firebase استفاده کنید.

اکنون آماده‌اید تا تشخیص نوشتار در تصاویر را شروع کنید.

۱. آماده کردن تصویر ورودی

برای فراخوانی Cloud Vision، تصویر باید به‌صورت رشته کدبندی‌شده base64 قالب‌بندی شود. برای پردازش UIImage:

Swift

guard let imageData = uiImage.jpegData(compressionQuality: 1.0) else { return }
let base64encodedImage = imageData.base64EncodedString()

Objective-C

NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f);
NSString *base64encodedImage =
  [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

۲. فراخوانی تابع قابل‌فراخوانی برای تشخیص نوشتار

برای تشخیص مکان‌های دیدنی در تصویر، تابع قابل‌فراخوانی را با ارسال درخواست JSON Cloud Vision فراخوانی کنید.

  1. ابتدا، نمونه‌ای از Cloud Functions را مقداردهی اولیه کنید:

    Swift

    lazy var functions = Functions.functions()
    

    Objective-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. درخواست را ایجاد کنید. ‫Cloud Vision API از دو نوع تشخیص نوشتار پشتیبانی می‌کند: TEXT_DETECTION و DOCUMENT_TEXT_DETECTION. برای اطلاع از تفاوت بین این دو مورد استفاده، اسناد Cloud Vision OCR را ببینید.

    Swift

    let requestData = [
      "image": ["content": base64encodedImage],
      "features": ["type": "TEXT_DETECTION"],
      "imageContext": ["languageHints": ["en"]]
    ]
    

    Objective-C

    NSDictionary *requestData = @{
      @"image": @{@"content": base64encodedImage},
      @"features": @{@"type": @"TEXT_DETECTION"},
      @"imageContext": @{@"languageHints": @[@"en"]}
    };
    
  3. درنهایت، تابع را فراخوانی کنید:

    Swift

    do {
      let result = try await functions.httpsCallable("annotateImage").call(requestData)
      print(result)
    } catch {
      if let error = error as NSError? {
        if error.domain == FunctionsErrorDomain {
          let code = FunctionsErrorCode(rawValue: error.code)
          let message = error.localizedDescription
          let details = error.userInfo[FunctionsErrorDetailsKey]
        }
        // ...
      }
    }
    

    Objective-C

    [[_functions HTTPSCallableWithName:@"annotateImage"]
                              callWithObject:requestData
                                  completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
            if (error) {
              if ([error.domain isEqualToString:@"com.firebase.functions"]) {
                FIRFunctionsErrorCode code = error.code;
                NSString *message = error.localizedDescription;
                NSObject *details = error.userInfo[@"details"];
              }
              // ...
            }
            // Function completed succesfully
            // Get information about labeled objects
    
          }];
    

۳. استخراج نوشتار از بلوک‌های نوشتار تشخیص‌داده‌شده

اگر عملیات تشخیص نوشتار موفقیت‌آمیز باشد، پاسخ JSON BatchAnnotateImagesResponse در نتیجه تکلیف برگردانده خواهد شد. حاشیه‌نویسی‌های نوشتاری را می‌توانید در شیء fullTextAnnotation پیدا کنید.

می‌توانید نوشتار تشخیص‌داده‌شده را به‌صورت رشته در فیلد text دریافت کنید. برای مثال:

Swift

let annotation = result.flatMap { $0.data as? [String: Any] }
    .flatMap { $0["fullTextAnnotation"] }
    .flatMap { $0 as? [String: Any] }
guard let annotation = annotation else { return }

if let text = annotation["text"] as? String {
  print("Complete annotation: \(text)")
}

Objective-C

NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);

همچنین می‌توانید اطلاعات مختص به بخش‌های تصویر را دریافت کنید. برای هر block، paragraph، word، و symbol، می‌توانید نوشتار تشخیص‌داده‌شده در منطقه و مختصات مرزی منطقه را دریافت کنید. برای مثال:

Swift

guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
  var pageText = ""
  guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
  for block in blocks {
    var blockText = ""
    guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
    for paragraph in paragraphs {
      var paragraphText = ""
      guard let words = paragraph["words"] as? [[String: Any]] else { continue }
      for word in words {
        var wordText = ""
        guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
        for symbol in symbols {
          let text = symbol["text"] as? String ?? ""
          let confidence = symbol["confidence"] as? Float ?? 0.0
          wordText += text
          print("Symbol text: \(text) (confidence: \(confidence)%n")
        }
        let confidence = word["confidence"] as? Float ?? 0.0
        print("Word text: \(wordText) (confidence: \(confidence)%n%n")
        let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
        print("Word bounding box: \(boundingBox.description)%n")
        paragraphText += wordText
      }
      print("%nParagraph: %n\(paragraphText)%n")
      let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
      print("Paragraph bounding box: \(boundingBox)%n")
      let confidence = paragraph["confidence"] as? Float ?? 0.0
      print("Paragraph Confidence: \(confidence)%n")
      blockText += paragraphText
    }
    pageText += blockText
  }
}

Objective-C

for (NSDictionary *page in annotation[@"pages"]) {
  NSMutableString *pageText = [NSMutableString new];
  for (NSDictionary *block in page[@"blocks"]) {
    NSMutableString *blockText = [NSMutableString new];
    for (NSDictionary *paragraph in block[@"paragraphs"]) {
      NSMutableString *paragraphText = [NSMutableString new];
      for (NSDictionary *word in paragraph[@"words"]) {
        NSMutableString *wordText = [NSMutableString new];
        for (NSDictionary *symbol in word[@"symbols"]) {
          NSString *text = symbol[@"text"];
          [wordText appendString:text];
          NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
        }
        NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
        NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
        [paragraphText appendString:wordText];
      }
      NSLog(@"\nParagraph: \n%@\n", paragraphText);
      NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
      NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
      [blockText appendString:paragraphText];
    }
    [pageText appendString:blockText];
  }
}