המשימה של MediaPipe Image Embedder מאפשרת להמיר נתוני תמונה למצג שווא מספרי כדי לבצע משימות של עיבוד תמונות שקשורות ללמידת מכונה, כמו השוואת הדמיון בין שתי תמונות.
דוגמת הקוד שמתוארת בהוראות האלה זמינה ב-GitHub. אתם יכולים לראות את המשימה הזו בפעולה בהדגמה הזו לאינטרנט. מידע נוסף על היכולות, המודלים והאפשרויות להגדרה של המשימה הזו זמין בסקירה הכללית.
קוד לדוגמה
הקוד לדוגמה של MediaPipe Tasks הוא הטמעה בסיסית של אפליקציית כלי להטמעת תמונות ל-iOS. בדוגמה הזו נעשה שימוש במצלמה במכשיר iOS פיזי כדי להטמיע תמונות באופן רציף, ואפשר גם להפעיל את הכלי להטמעת תמונות בקובצי תמונות מהגלריה של המכשיר.
אפשר להשתמש באפליקציה כנקודת התחלה לאפליקציה משלכם ל-iOS, או להיעזר בה כשמשנים אפליקציה קיימת. קוד הדוגמה של Image Embedder מתארח ב-GitHub.
להורדת הקוד
בהוראות הבאות מוסבר איך ליצור עותק מקומי של הקוד לדוגמה באמצעות כלי שורת הפקודה git.
כדי להוריד את הקוד לדוגמה:
משכפלים את מאגר git באמצעות הפקודה הבאה:
git clone https://github.com/google-ai-edge/mediapipe-samples
אפשר גם להגדיר את מכונה של git כך שתשתמש ב-sparse checkout, כך שיישארו רק הקבצים של אפליקציית הדוגמה Image Embedder:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/image_embedder/ios
אחרי שיוצרים גרסה מקומית של הקוד לדוגמה, אפשר להתקין את ספריית המשימות MediaPipe, לפתוח את הפרויקט באמצעות Xcode ולהריץ את האפליקציה. הוראות מופיעות במדריך ההגדרה ל-iOS.
רכיבים מרכזיים
הקבצים הבאים מכילים את הקוד החשוב לאפליקציית הדוגמה של Image Embedder:
- ImageEmbedderService.swift: הפעלת הכלי להטמעה של תמונות, טיפול בבחירת המודל והפעלת ההסקה על נתוני הקלט.
- CameraViewController.swift: הקוד הזה מטמיע את ממשק המשתמש של מצב הקלט של פיד המצלמה בשידור חי ומציג את התוצאות באופן חזותי.
- MediaLibraryViewController.swift: הקוד מטמיע את ממשק המשתמש של מצב הקלט של תמונות סטילס ומציג את התוצאות באופן חזותי.
הגדרה
בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח ופרויקטי הקוד לשימוש ב-Image Embedder. במדריך ההגדרה ל-iOS תוכלו לקרוא מידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות MediaPipe, כולל הדרישות לגרסת הפלטפורמה.
יחסי תלות
הספרייה MediaPipeTasksVision
משמשת את Image Embedder, וצריך להתקין אותה באמצעות CocoaPods. הספרייה תואמת לאפליקציות Swift וגם לאפליקציות Objective-C, ולא נדרשת הגדרה נוספת ספציפית לשפה.
הוראות להתקנת CocoaPods ב-macOS מפורטות במדריך להתקנת CocoaPods.
הוראות ליצירת Podfile
עם ה-pods הנדרשים לאפליקציה מפורטות במאמר שימוש ב-CocoaPods.
מוסיפים את ה-pod של MediaPipeTasksVision
ב-Podfile
באמצעות הקוד הבא:
target 'MyImageEmbedderApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
אם האפליקציה כוללת יעדי בדיקת יחידה, תוכלו לעיין במדריך ההגדרה ל-iOS כדי לקבל מידע נוסף על הגדרת Podfile
.
דגם
כדי לבצע את המשימה 'הטמעת תמונות ב-MediaPipe', נדרש מודל מאומן שתואם למשימה הזו. מידע נוסף על המודלים המאומנים הזמינים ל-Image Embedder זמין בקטע 'מודלים'.
בוחרים מודל ומורידים אותו, ומוסיפים אותו לספריית הפרויקט באמצעות Xcode. הוראות להוספת קבצים לפרויקט ב-Xcode מפורטות במאמר ניהול קבצים ותיקיות בפרויקט ב-Xcode.
השתמשו במאפיין BaseOptions.modelAssetPath
כדי לציין את הנתיב למודל בקובץ האפליקציה.
יצירת המשימה
אפשר ליצור את המשימה 'הטמעת תמונות' על ידי קריאה לאחד מהמפעילים שלה. ה-initializer של ImageEmbedder(options:)
מקבל ערכים לאפשרויות ההגדרה.
אם אתם לא צריכים כלי להטמעת תמונות שמאותחל עם אפשרויות תצורה בהתאמה אישית, תוכלו להשתמש במפעיל ImageEmbedder(modelPath:)
כדי ליצור כלי להטמעת תמונות עם אפשרויות ברירת המחדל. למידע נוסף על אפשרויות ההגדרה, ראו סקירה כללית של ההגדרות.
במשימה של הכלי להטמעת תמונות יש תמיכה בשלושה סוגים של נתוני קלט: תמונות סטילס, קובצי וידאו וסטרימינג של וידאו בשידור חי. כברירת מחדל, ImageEmbedder(modelPath:)
מאתחלת משימה לתמונות סטילס. אם רוצים שהמשימה תאופס לעיבוד קובצי וידאו או סטרימינג של וידאו בשידור חי, צריך להשתמש ב-ImageEmbedder(options:)
כדי לציין את מצב ההפעלה של הסרטון או השידור החי. למצב של השידור החי נדרשת גם אפשרות הגדרה נוספת imageEmbedderLiveStreamDelegate
, שמאפשרת למטמיע תמונות לספק למיופה התמונה תוצאות של הטמעת תמונות באופן אסינכרוני.
בוחרים את הכרטיסייה שמתאימה למצב ההפעלה כדי לראות איך יוצרים את המשימה ומפעילים את ההסקה.
Swift
תמונה
import MediaPipeTasksVision let modelPath = Bundle.main.path( forResource: "model", ofType: "tflite") let options = ImageEmbedderOptions() options.baseOptions.modelAssetPath = modelPath options.quantize = true options.l2Normalize = true let imageEmbedder = try ImageEmbedder(options: options)
וידאו
import MediaPipeTasksVision let modelPath = Bundle.main.path( forResource: "model", ofType: "tflite") let options = ImageEmbedderOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.quantize = true options.l2Normalize = true let imageEmbedder = try ImageEmbedder(options: options)
שידור חי
import MediaPipeTasksVision // Class that conforms to the `ImageEmbedderLiveStreamDelegate` protocol and // implements the method that the image embedder calls once it finishes // embedding each input frame. class ImageEmbedderResultProcessor: NSObject, ImageEmbedderLiveStreamDelegate { func imageEmbedder( _ imageEmbedder: ImageEmbedder, didFinishEmbedding result: ImageEmbedderResult?, timestampInMilliseconds: Int, error: Error?) { // Process the image embedder result or errors here. } } let modelPath = Bundle.main.path( forResource: "model", ofType: "tflite") let options = ImageEmbedderOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.quantize = true options.l2Normalize = true // Assign an object of the class to the `imageEmbedderLiveStreamDelegate` // property. let processor = ImageEmbedderResultProcessor() options.imageEmbedderLiveStreamDelegate = processor let imageEmbedder = try ImageEmbedder(options: options)
Objective-C
תמונה
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.quantize = YES; options.l2Normalize = YES; MPPImageEmbedder *imageEmbedder = [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
וידאו
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.quantize = YES; options.l2Normalize = YES; MPPImageEmbedder *imageEmbedder = [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
שידור חי
@import MediaPipeTasksVision; // Class that conforms to the `MPPImageEmbedderLiveStreamDelegate` protocol // and implements the method that the image embedder calls once it finishes // embedding each input frame. @interface APPImageEmbedderResultProcessor : NSObject@end @implementation APPImageEmbedderResultProcessor - (void)imageEmbedder:(MPPImageEmbedder *)imageEmbedder didFinishEmbeddingWithResult:(MPPImageEmbedderResult *)imageEmbedderResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the image embedder result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.quantize = YES; options.l2Normalize = YES; // Assign an object of the class to the `imageEmbedderLiveStreamDelegate` // property. APPImageEmbedderResultProcessor *processor = [APPImageEmbedderResultProcessor new]; options.imageEmbedderLiveStreamDelegate = processor; MPPImageEmbedder *imageEmbedder = [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
אפשרויות הגדרה
למשימה הזו יש את אפשרויות התצורה הבאות לאפליקציות ל-iOS:
שם האפשרות | תיאור | טווח ערכים | ערך ברירת מחדל |
---|---|---|---|
runningMode |
הגדרת מצב ההפעלה של המשימה. ל-Image Embedder יש שלושה מצבים:
IMAGE: המצב להזנת תמונה אחת. VIDEO: המצב של פריימים מפוענחים של סרטון. LIVE_STREAM: המצב של שידור חי של נתוני קלט, למשל ממצלמה. במצב הזה, צריך להגדיר את imageEmbedderLiveStreamDelegate למכונה של כיתה שמטמיעה את ImageEmbedderLiveStreamDelegate כדי לקבל את התוצאות של הטמעת מסגרות התמונות באופן אסינכרוני.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream} | {RunningMode.image} |
l2Normalize |
האם לבצע נורמליזציה של וקטור המאפיינים המוחזר באמצעות נורמלי L2. צריך להשתמש באפשרות הזו רק אם המודל לא מכיל כבר גרסה מקורית של L2_NORMALIZATION בפורמט TFLite Op. ברוב המקרים, זה כבר המצב, ונירמול L2 מתקבל באמצעות הסקת TFLite ללא צורך באפשרות הזו. | בוליאני | false |
quantize |
האם להצפין את הטמעת הנתונים שחוזרת לבייטים באמצעות קידוד סקלר. ההנחה במרומז היא שהטמעות הטמעות הן יחידה נורמלית (unit-norm), ולכן מובטח שלכל מאפיין יהיה ערך בתקן [ -1.0, 1.0]. אם לא, צריך להשתמש באפשרות l2Normalize. | בוליאני | false |
כשמצב ההרצה מוגדר כשידור חי, להטמעה של תמונות נדרשת אפשרות הגדרה נוספת imageEmbedderLiveStreamDelegate
, שמאפשרת למטמיע תמונות לספק תוצאות של הטמעת תמונות באופן אסינכרוני. הנציג חייב להטמיע את השיטה imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:)
, שנקראת על ידי Image Embedder אחרי עיבוד התוצאות של הטמעת כל פריים של תמונת הקלט.
שם האפשרות | תיאור | טווח ערכים | ערך ברירת מחדל |
---|---|---|---|
imageEmbedderLiveStreamDelegate |
מאפשר למטמיע תמונות לקבל את התוצאות של הטמעת תמונות באופן אסינכרוני במצב חי. המחלקה שהמכונה שלה מוגדרת למאפיין הזה צריכה להטמיע את השיטה imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) . |
לא רלוונטי | לא מוגדר |
הכנת נתונים
צריך להמיר את התמונה או את המסגרת של הקלט לאובייקט MPImage
לפני שמעבירים אותו ל-Image Embedder. MPImage
תומך בסוגים שונים של פורמטים של תמונות ב-iOS, וניתן להשתמש בהם בכל מצב ריצה לצורך הסקת מסקנות. למידע נוסף על MPImage
, אפשר לעיין במאמר MPImage API.
בוחרים את פורמט התמונה ל-iOS בהתאם לתרחיש לדוגמה ולמצב ההפעלה שנדרש לאפליקציה. MPImage
תומך בפורמטים של תמונות ל-iOS UIImage
, CVPixelBuffer
ו-CMSampleBuffer
.
UIImage
הפורמט UIImage
מתאים במיוחד למצבי הריצה הבאים:
תמונות: אפשר להמיר תמונות מחבילת אפליקציות, מגלריית משתמשים או ממערכת קבצים בפורמט
UIImage
לאובייקטMPImage
.סרטונים: משתמשים ב-AVAssetImageGenerator כדי לחלץ פריימים של סרטונים לפורמט CGImage, ולאחר מכן ממירים אותם לתמונות
UIImage
.
Swift
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(uiImage: image)
Objective-C
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
בדוגמה מתבצעת אתחול של MPImage
עם כיוון ברירת המחדל UIImage.Orientation.Up. אפשר לאתחל את MPImage
עם כל אחד מהערכים הנתמכים של UIImage.Orientation. הכלי להטמעת תמונות לא תומך בכיוונים מוחזרים כמו .upMirrored
, .downMirrored
, .leftMirrored
, .rightMirrored
.
מידע נוסף על UIImage
זמין במסמכי התיעוד למפתחים של Apple בנושא UIImage.
CVPixelBuffer
הפורמט CVPixelBuffer
מתאים לאפליקציות שיוצרות פריימים ומשתמשות במסגרת CoreImage של iOS לעיבוד.
הפורמט CVPixelBuffer
מתאים במיוחד למצבי ההפעלה הבאים:
תמונות: אפליקציות שיוצרות תמונות
CVPixelBuffer
אחרי עיבוד מסוים באמצעות מסגרתCoreImage
של iOS יכולות להישלח ל-Image Embedder במצב ההפעלה של התמונה.סרטונים: אפשר להמיר פריימים של סרטונים לפורמט
CVPixelBuffer
לצורך עיבוד, ואז לשלוח אותם לכלי להטמעת תמונות במצב וידאו.שידור חי: יכול להיות שאפליקציות שמשתמשות במצלמת iOS כדי ליצור פריימים יומרו לפורמט
CVPixelBuffer
לצורך עיבוד לפני שהן נשלחות ל-Image Embedder במצב שידור חי.
Swift
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(pixelBuffer: pixelBuffer)
Objective-C
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
מידע נוסף על CVPixelBuffer
זמין במסמכי התיעוד למפתחים של CVPixelBuffer Apple.
CMSampleBuffer
בפורמט CMSampleBuffer
מאוחסנות דגימות מדיה מסוג מדיה אחיד, והוא מתאים במיוחד למצב ההפעלה של שידור חי. פריימים חיים ממצלמות iOS נשלחים באופן אסינכרוני בפורמט CMSampleBuffer
על ידי iOS AVCaptureVideoDataOutput.
Swift
// Obtain a CMSampleBuffer. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(sampleBuffer: sampleBuffer)
Objective-C
// Obtain a `CMSampleBuffer`. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
מידע נוסף על CMSampleBuffer
זמין במסמכי העזרה למפתחים של Apple בנושא CMSampleBuffer.
הרצת המשימה
כדי להריץ את Image Embedder, משתמשים בשיטה embed()
שספציפית למצב ההפעלה שהוקצה:
- תמונת סטילס:
embed(image:)
- סרטון:
embed(videoFrame:timestampInMilliseconds:)
- צפייה בשידור חי:
embedAsync(image:timestampInMilliseconds:)
בדוגמאות הקוד הבאות מפורטות דוגמאות בסיסיות להרצת Image Embedder במצבי ההפעלה השונים:
Swift
תמונה
let result = try imageEmbedder.embed(image: image)
וידאו
let result = try imageEmbedder.embed( videoFrame: image, timestampInMilliseconds: timestamp)
שידור חי
try imageEmbedder.embedAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
תמונה
MPPImageEmbedderResult *result = [imageEmbedder embedImage:image error:nil];
וידאו
MPPImageEmbedderResult *result = [imageEmbedder embedVideoFrame:image timestampInMilliseconds:timestamp error:nil];
שידור חי
BOOL success = [imageEmbedder embedAsyncImage:image timestampInMilliseconds:timestamp error:nil];
בדוגמה לקוד של Image Embedder מפורטות ההטמעות של כל אחד מהמצבים האלה: embed(image:)
, embed(videoFrame:timestampInMilliseconds:)
ו-embedAsync(image:timestampInMilliseconds:)
. הקוד לדוגמה מאפשר למשתמש לעבור בין מצבי עיבוד, שיכול להיות שלא נדרשים לתרחיש לדוגמה.
שימו לב לנקודות הבאות:
כשמריצים את הקוד במצב וידאו או במצב שידור חי, צריך לספק גם את חותמת הזמן של פריים הקלט למשימה Image Embedder.
כשהיא פועלת במצב תמונה או סרטון, המשימה Image Embedder חוסמת את השרשור הנוכחי עד שהיא מסיימת לעבד את התמונה או את הפריים של הקלט. כדי למנוע חסימה של השרשור הנוכחי, צריך להריץ את העיבוד בשרשור רקע באמצעות מסגרות ה-iOS Dispatch או NSOperation. אם האפליקציה נוצרה באמצעות Swift, אפשר גם להשתמש ב-Swift Concurrency להרצת חוט ברקע.
כשהיא פועלת במצב של שידור חי, המשימה 'הטמעת תמונות' חוזרת מיד ולא חוסמת את השרשור הנוכחי. הוא מפעיל את השיטה
imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:)
עם התוצאות, אחרי הטמעת כל פריים של הקלט. הכלי להטמעת תמונות מפעיל את השיטה הזו באופן אסינכרוני בתור ייעודי לשליחה טורית. כדי להציג את התוצאות בממשק המשתמש, שולחים את התוצאות לתור הראשי אחרי העיבוד שלהן. אם מתבצעת קריאה לפונקציהembedAsync
כשמשימה של כלי הטמעה של תמונות עסוקה בעיבוד פריים אחר, הכלי להטמעת תמונות מתעלם ממסגרת הקלט החדשה.
טיפול בתוצאות והצגתן
לאחר הפעלת ההסקה, ה-Image Embedder מחזיר אובייקט ImageEmbedderResult
שמכיל רשימה של הטמעות (נקודות צפות או סקלר-קוונטיזציה) של תמונת הקלט.
בדוגמה הבאה אפשר לראות את נתוני הפלט מהמשימה:
ImageEmbedderResult:
Embedding #0 (sole embedding head):
float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
head_index: 0
התוצאה הזו התקבלה על ידי הטמעת התמונה הבאה:
אפשר להשוות את הדמיון בין שני הטמעות באמצעות הפונקציה ImageEmbedder.cosineSimilarity
.
Swift
let similarity = try ImageEmbedder.cosineSimilarity( embedding1: result.embeddingResult.embeddings[0], embedding2: otherResult.embeddingResult.embeddings[0])
Objective-C
NSNumber *similarity = [MPPImageEmbedder cosineSimilarityBetweenEmbedding1:result.embeddingResult.embeddings[0] andEmbedding2:otherResult.embeddingResult.embeddings[0] error:nil];