זיהוי טקסט בתמונות באמצעות ערכת למידת מכונה ב-iOS

אפשר להשתמש ב-ML Kit כדי לזהות טקסט בתמונות. ‫ML Kit כולל גם API לשימוש כללי שמתאים לזיהוי טקסט בתמונות, כמו טקסט של תמרור, וגם API שעבר אופטימיזציה לזיהוי טקסט במסמכים. ל-API לשימוש כללי יש מודלים במכשיר ומודלים מבוססי-ענן. זיהוי טקסט במסמך זמין רק כמודל מבוסס-ענן. בסקירה הכללית מופיעה השוואה בין המודלים בענן ובמכשיר.

לפני שמתחילים

  1. אם עדיין לא הוספתם את Firebase לאפליקציה, אתם צריכים לעשות זאת לפי השלבים במדריך לתחילת העבודה.
  2. מוסיפים את ספריות ML Kit ל-Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel', '6.25.0'
    
    אחרי שמתקינים או מעדכנים את ה-Pods של הפרויקט, חשוב לפתוח את פרויקט Xcode באמצעות .xcworkspace.
  3. באפליקציה, מייבאים את Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. אם אתם רוצים להשתמש במודל מבוסס-Cloud, ולא הפעלתם עדיין את ממשקי ה-API מבוססי-Cloud בפרויקט שלכם, עכשיו זה הזמן:

    1. פותחים את הדף ML Kit APIs במסוף Firebase.
    2. אם עדיין לא שדרגתם את הפרויקט לתוכנית התמחור Blaze, לוחצים על שדרוג כדי לעשות זאת. (ההודעה על הצורך בשדרוג תוצג רק אם הפרויקט לא מוגדר בתוכנית Blaze).

      רק בפרויקטים ברמת Blaze אפשר להשתמש בממשקי API מבוססי-Cloud.

    3. אם ממשקי API מבוססי-ענן לא מופעלים כבר, לוחצים על Enable Cloud-based APIs.

    אם רוצים להשתמש רק במודל במכשיר, אפשר לדלג על השלב הזה.

עכשיו אפשר להתחיל לזהות טקסט בתמונות.

הנחיות לגבי תמונות קלט

  • כדי ש-ML Kit יזהה טקסט בצורה מדויקת, התמונות שמוזנות לו צריכות להכיל טקסט שמיוצג על ידי נתוני פיקסלים מספיקים. באופן אידיאלי, עבור טקסט לטיני, כל תו צריך להיות בגודל 16x16 פיקסלים לפחות. בטקסט בסינית, ביפנית ובקוריאנית (שנתמך רק על ידי ממשקי ה-API מבוססי-הענן), כל תו צריך להיות בגודל 24x24 פיקסלים. בכל השפות, בדרך כלל אין יתרון בדיוק אם התווים גדולים מ-24x24 פיקסלים.

    לדוגמה, תמונה בגודל ‎640x480 יכולה להתאים לסריקה של כרטיס ביקור שממלא את כל הרוחב של התמונה. כדי לסרוק מסמך שמודפס על נייר בגודל Letter, יכול להיות שתידרש תמונה בגודל 720x1280 פיקסלים.

  • פוקוס לא טוב של התמונה עלול לפגוע בדיוק של זיהוי הטקסט. אם התוצאות לא מספיק טובות, אפשר לבקש מהמשתמש לצלם מחדש את התמונה.

  • אם אתם מזהים טקסט באפליקציה בזמן אמת, כדאי גם לקחת בחשבון את הממדים הכוללים של תמונות הקלט. אפשר לעבד תמונות קטנות יותר מהר יותר, ולכן כדי לצמצם את זמן האחזור, כדאי לצלם תמונות ברזולוציות נמוכות יותר (תוך הקפדה על דרישות הדיוק שצוינו למעלה) ולוודא שהטקסט תופס כמה שיותר מהתמונה. כדאי לעיין גם בטיפים לשיפור הביצועים בזמן אמת.


זיהוי טקסט בתמונות

כדי לזהות טקסט בתמונה באמצעות מודל מבוסס-ענן או מודל שפועל במכשיר, מפעילים את הכלי לזיהוי טקסט כמו שמתואר בהמשך.

1. הפעלת הכלי לזיהוי טקסט

מעבירים את התמונה כ-`UIImage` או כ-`CMSampleBufferRef` לשיטה `process(_:completion:)` של `VisionTextRecognizer`:
  1. כדי לקבל מופע של VisionTextRecognizer, קוראים לאחת מהפונקציות הבאות: onDeviceTextRecognizer או cloudTextRecognizer:

    Swift

    כדי להשתמש במודל במכשיר:

    let vision = Vision.vision()
    let textRecognizer = vision.onDeviceTextRecognizer()

    כדי להשתמש במודל הענן:

    let vision = Vision.vision()
    let textRecognizer = vision.cloudTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudTextRecognizer(options: options)

    Objective-C

    כדי להשתמש במודל במכשיר:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];

    כדי להשתמש במודל הענן:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudTextRecognizerOptions *options =
            [[FIRVisionCloudTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizerWithOptions:options];
  2. יוצרים אובייקט VisionImage באמצעות UIImage או CMSampleBufferRef.

    כדי להשתמש ב-UIImage:

    1. אם צריך, מסובבים את התמונה כך שהמאפיין imageOrientation שלה יהיה .up.
    2. יוצרים אובייקט VisionImage באמצעות UIImage מסובב בצורה נכונה. לא מציינים מטא-נתונים של סיבוב – צריך להשתמש בערך ברירת המחדל, .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    כדי להשתמש ב-CMSampleBufferRef:

    1. יוצרים אובייקט VisionImageMetadata שמציין את הכיוון של נתוני התמונה שנמצאים במאגר CMSampleBufferRef.

      כדי לקבל את כיוון התמונה:

      Swift

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      לאחר מכן, יוצרים את אובייקט המטא-נתונים:

      Swift

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. יוצרים אובייקט VisionImage באמצעות האובייקט CMSampleBufferRef ומטא-נתוני הסיבוב:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. לאחר מכן, מעבירים את התמונה לשיטה process(_:completion:):

    Swift

    textRecognizer.process(visionImage) { result, error in
      guard error == nil, let result = result else {
        // ...
        return
      }
    
      // Recognized text
    }

    Objective-C

    [textRecognizer processImage:image
                      completion:^(FIRVisionText *_Nullable result,
                                   NSError *_Nullable error) {
      if (error != nil || result == nil) {
        // ...
        return;
      }
    
      // Recognized text
    }];

2. חילוץ טקסט מבלוקים של טקסט מזוהה

אם פעולת זיהוי הטקסט תצליח, יוחזר אובייקט [<code>VisionText</code>][VisionText]. אובייקט `VisionText` מכיל את הטקסט המלא שזוהה בתמונה, ואפס או יותר אובייקטים מסוג [`VisionTextBlock`][VisionTextBlock]. כל `VisionTextBlock` מייצג בלוק טקסט מלבני, שמכיל אפס או יותר אובייקטים מסוג [`VisionTextLine`][VisionTextLine]. כל אובייקט `VisionTextLine` מכיל אפס או יותר אובייקטים מסוג [`VisionTextElement`][VisionTextElement], שמייצגים מילים וישויות דמויות מילים (תאריכים, מספרים וכו'). לכל אובייקט `VisionTextBlock`,‏ `VisionTextLine` ו-`VisionTextElement`, אפשר לקבל את הטקסט שזוהה באזור ואת קואורדינטות התיחום של האזור. לדוגמה:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockConfidence = block.confidence
    let blockLanguages = block.recognizedLanguages
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for line in block.lines {
        let lineText = line.text
        let lineConfidence = line.confidence
        let lineLanguages = line.recognizedLanguages
        let lineCornerPoints = line.cornerPoints
        let lineFrame = line.frame
        for element in line.elements {
            let elementText = element.text
            let elementConfidence = element.confidence
            let elementLanguages = element.recognizedLanguages
            let elementCornerPoints = element.cornerPoints
            let elementFrame = element.frame
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (FIRVisionTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (FIRVisionTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSNumber *lineConfidence = line.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (FIRVisionTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSNumber *elementConfidence = element.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *elementLanguages = element.recognizedLanguages;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

טיפים לשיפור הביצועים בזמן אמת

אם רוצים להשתמש במודל במכשיר כדי לזהות טקסט באפליקציה בזמן אמת, כדאי לפעול לפי ההנחיות האלה כדי להשיג את קצב הפריימים הטוב ביותר:

  • הגבלת מספר השיחות לזיהוי הטקסט. אם פריים חדש של סרטון הופך לזמין בזמן שרכיב זיהוי הטקסט פועל, צריך להשליך את הפריים.
  • אם אתם משתמשים בפלט של הכלי לזיהוי טקסט כדי להוסיף גרפיקה לתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ולהוסיף את הגרפיקה בשלב אחד. כך, הרינדור מתבצע רק פעם אחת לכל מסגרת קלט. דוגמה אפשר לראות במחלקות previewOverlayView ו-FIRDetectionOverlayView באפליקציית הדוגמה showcase.
  • כדאי לצלם תמונות ברזולוציה נמוכה יותר. עם זאת, חשוב לזכור גם את הדרישות לגבי מידות התמונה ב-API הזה.

השלבים הבאים


זיהוי טקסט בתמונות של מסמכים

כדי לזהות את הטקסט במסמך, צריך להגדיר ולהפעיל את הכלי לזיהוי טקסט במסמכים שמבוסס על ענן, כמו שמתואר בהמשך.

ממשק ה-API לזיהוי טקסט במסמכים, שמתואר בהמשך, נועד להקל על העבודה עם תמונות של מסמכים. אבל אם אתם מעדיפים את הממשק שמספק ה-API של טקסט דליל, אתם יכולים להשתמש בו במקום זאת כדי לסרוק מסמכים. לשם כך, צריך להגדיר את הכלי לזיהוי טקסט בענן לשימוש במודל של טקסט צפוף.

כדי להשתמש ב-API לזיהוי טקסט במסמך:

1. הפעלת הכלי לזיהוי טקסט

מעבירים את התמונה כ-UIImage או כ-CMSampleBufferRef לשיטה process(_:completion:) של VisionDocumentTextRecognizer:

  1. מקבלים מופע של VisionDocumentTextRecognizer על ידי קריאה ל- cloudDocumentTextRecognizer:

    Swift

    let vision = Vision.vision()
    let textRecognizer = vision.cloudDocumentTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudDocumentTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudDocumentTextRecognizer(options: options)

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudDocumentTextRecognizerOptions *options =
            [[FIRVisionCloudDocumentTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizerWithOptions:options];
  2. יוצרים אובייקט VisionImage באמצעות UIImage או CMSampleBufferRef.

    כדי להשתמש ב-UIImage:

    1. אם צריך, מסובבים את התמונה כך שהמאפיין imageOrientation שלה יהיה .up.
    2. יוצרים אובייקט VisionImage באמצעות UIImage מסובב בצורה נכונה. לא מציינים מטא-נתונים של סיבוב – צריך להשתמש בערך ברירת המחדל, .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    כדי להשתמש ב-CMSampleBufferRef:

    1. יוצרים אובייקט VisionImageMetadata שמציין את הכיוון של נתוני התמונה שנמצאים במאגר CMSampleBufferRef.

      כדי לקבל את כיוון התמונה:

      Swift

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      לאחר מכן, יוצרים את אובייקט המטא-נתונים:

      Swift

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. יוצרים אובייקט VisionImage באמצעות האובייקט CMSampleBufferRef ומטא-נתוני הסיבוב:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. לאחר מכן, מעבירים את התמונה לשיטה process(_:completion:):

    Swift

    textRecognizer.process(visionImage) { result, error in
      guard error == nil, let result = result else {
        // ...
        return
      }
    
      // Recognized text
    }

    Objective-C

    [textRecognizer processImage:image
                      completion:^(FIRVisionDocumentText *_Nullable result,
                                   NSError *_Nullable error) {
      if (error != nil || result == nil) {
        // ...
        return;
      }
    
        // Recognized text
    }];

2. חילוץ טקסט מבלוקים של טקסט מזוהה

אם פעולת זיהוי הטקסט תצליח, יוחזר אובייקט VisionDocumentText. אובייקט VisionDocumentText מכיל את הטקסט המלא שזוהה בתמונה ואת ההיררכיה של האובייקטים שמשקפים את המבנה של המסמך שזוהה:

לכל אובייקט VisionDocumentTextBlock, VisionDocumentTextParagraph,‏ VisionDocumentTextWord ו-VisionDocumentTextSymbol, אפשר לקבל את הטקסט שזוהה באזור ואת קואורדינטות התיחום של האזור.

לדוגמה:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockConfidence = block.confidence
    let blockRecognizedLanguages = block.recognizedLanguages
    let blockBreak = block.recognizedBreak
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for paragraph in block.paragraphs {
        let paragraphText = paragraph.text
        let paragraphConfidence = paragraph.confidence
        let paragraphRecognizedLanguages = paragraph.recognizedLanguages
        let paragraphBreak = paragraph.recognizedBreak
        let paragraphCornerPoints = paragraph.cornerPoints
        let paragraphFrame = paragraph.frame
        for word in paragraph.words {
            let wordText = word.text
            let wordConfidence = word.confidence
            let wordRecognizedLanguages = word.recognizedLanguages
            let wordBreak = word.recognizedBreak
            let wordCornerPoints = word.cornerPoints
            let wordFrame = word.frame
            for symbol in word.symbols {
                let symbolText = symbol.text
                let symbolConfidence = symbol.confidence
                let symbolRecognizedLanguages = symbol.recognizedLanguages
                let symbolBreak = symbol.recognizedBreak
                let symbolCornerPoints = symbol.cornerPoints
                let symbolFrame = symbol.frame
            }
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (FIRVisionDocumentTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockRecognizedLanguages = block.recognizedLanguages;
  FIRVisionTextRecognizedBreak *blockBreak = block.recognizedBreak;
  CGRect blockFrame = block.frame;
  for (FIRVisionDocumentTextParagraph *paragraph in block.paragraphs) {
    NSString *paragraphText = paragraph.text;
    NSNumber *paragraphConfidence = paragraph.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *paragraphRecognizedLanguages = paragraph.recognizedLanguages;
    FIRVisionTextRecognizedBreak *paragraphBreak = paragraph.recognizedBreak;
    CGRect paragraphFrame = paragraph.frame;
    for (FIRVisionDocumentTextWord *word in paragraph.words) {
      NSString *wordText = word.text;
      NSNumber *wordConfidence = word.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *wordRecognizedLanguages = word.recognizedLanguages;
      FIRVisionTextRecognizedBreak *wordBreak = word.recognizedBreak;
      CGRect wordFrame = word.frame;
      for (FIRVisionDocumentTextSymbol *symbol in word.symbols) {
        NSString *symbolText = symbol.text;
        NSNumber *symbolConfidence = symbol.confidence;
        NSArray<FIRVisionTextRecognizedLanguage *> *symbolRecognizedLanguages = symbol.recognizedLanguages;
        FIRVisionTextRecognizedBreak *symbolBreak = symbol.recognizedBreak;
        CGRect symbolFrame = symbol.frame;
      }
    }
  }
}

השלבים הבאים