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

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

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

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

قبل از شروع

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

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

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

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

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

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

    Swift

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

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

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

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

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

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

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

سپس، 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» را ندارید، آن را نصب کنید.
  4. پروژه Firebase را در فهرست راهنمای vision-annotate-image مقداردهی اولیه کنید. وقتی درخواست شد، پروژه خود را در فهرست انتخاب کنید.
    firebase init
  5. استقرار تابع:
    firebase deploy --only functions:annotateImage

افزودن «احراز هویت Firebase» به برنامه

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

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

از «مدیر بسته Swift» برای نصب کتابخانه «توابع ابری ویژه 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];
  }
}