Giriş
Merhaba Dünya! eğiticisi, iOS'i geliştirmek için MediaPipe Framework'ü kullanır iOS'te MediaPipe grafiği çalıştıran bir uygulamadır.
Ne oluşturacaksınız?
Canlı bir videoya gerçek zamanlı Sobel kenar algılaması için uygulanan basit bir kamera uygulaması akışla aktarmanızı sağlar.
Kurulum
- Sisteminize MediaPipe Framework'ü yükleme için Çerçeve yüklemesi kurulumuna bakın rehberini inceleyin.
- Geliştirme için iOS cihazınızı ayarlayın.
- iOS uygulamasını oluşturmak ve dağıtmak için sisteminizde Bazel'i kurun.
Kenar algılama grafiği
Şu grafiği kullanacağız: edge_detection_mobile_gpu.pbtxt
:
# MediaPipe graph that performs GPU Sobel edge detection on a live video stream.
# Used in the examples
# mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic:helloworld
# and mediapipe/examples/ios/helloworld.
# Images coming into and out of the graph.
input_stream: "input_video"
output_stream: "output_video"
# Converts RGB images into luminance images, still stored in RGB format.
node: {
calculator: "LuminanceCalculator"
input_stream: "input_video"
output_stream: "luma_video"
}
# Applies the Sobel filter to luminance images stored in RGB format.
node: {
calculator: "SobelEdgesCalculator"
input_stream: "luma_video"
output_stream: "output_video"
}
Grafik görselleştirmesi aşağıda gösterilmektedir:
Bu grafikte, tüm gelen kareler için input_video
adlı tek bir giriş akışı bulunuyor
bir veri feed'i seçin.
Grafikteki ilk düğüm olan LuminanceCalculator
, tek bir paket alır (görüntü
çerçeve) ve bir OpenGL gölgelendirici kullanarak parlaklık değişikliği uygular. Bunun sonucunda
resim çerçevesi, luma_video
çıkış akışına gönderilir.
İkinci düğüm olan SobelEdgesCalculator
, gelen içeriğe uç algılamayı uygular
luma_video
akışındaki paketler ve çıkışlar, output_video
çıkışıyla sonuçlanır
akış şeklinde gösterilir.
iOS uygulamamız, output_video
çıktısının resim çerçevelerini görüntüler
akış şeklinde gösterilir.
İlk minimum uygulama kurulumu
Öncelikle basit bir iOS uygulamasıyla başlayıp bazel
ürününün nasıl kullanılacağını göstereceğiz.
sahip olacaksınız.
İlk olarak Dosya > üzerinden bir XCode projesi oluşturun Yeni > Tek Görünüm Uygulaması.
Ürün adını "HelloWorld" olarak ayarlayın ve uygun bir kuruluş kullanın
com.google.mediapipe
gibi bir tanımlayıcı içerir. Kuruluş tanımlayıcısı
ile birlikte ürün adı, uygulama için bundle_id
olacaktır. Örneğin,
com.google.mediapipe.HelloWorld
.
Dili Objective-C olarak ayarlayın.
Projeyi uygun bir konuma kaydedin. Buna şöyle diyelim:
$PROJECT_TEMPLATE_LOC
Bu nedenle projeniz,
$PROJECT_TEMPLATE_LOC/HelloWorld
dizini. Bu dizinde şunlar yer alır:
HelloWorld
adlı başka bir dizin ve bir HelloWorld.xcodeproj
dosyası.
HelloWorld.xcodeproj
, daha önce belirttiğimiz gibi bu eğitimde yararlı olmayacak
bazel kullanarak iOS uygulamasını oluşturabilirsiniz. The content of the
$PROJECT_TEMPLATE_LOC/HelloWorld/HelloWorld
dizini aşağıda listelenmiştir:
AppDelegate.h
veAppDelegate.m
ViewController.h
veViewController.m
main.m
Info.plist
Main.storyboard
veLaunch.storyboard
Assets.xcassets
dizini.
Bu dosyaları HelloWorld
adlı dizine kopyalayıp erişimi olan bir konuma kopyalayın
MediaPipe Framework kaynak kodu kullanılır. Örneğin,
bu eğitimde oluşturacağımız uygulama şuradadır:
mediapipe/examples/ios/HelloWorld
Bu yolu
Codelab boyunca $APPLICATION_PATH
.
$APPLICATION_PATH
içinde bir BUILD
dosyası oluşturun ve aşağıdaki derlemeyi ekleyin
kurallarınız:
MIN_IOS_VERSION = "11.0"
load(
"@build_bazel_rules_apple//apple:ios.bzl",
"ios_application",
)
ios_application(
name = "HelloWorldApp",
bundle_id = "com.google.mediapipe.HelloWorld",
families = [
"iphone",
"ipad",
],
infoplists = ["Info.plist"],
minimum_os_version = MIN_IOS_VERSION,
provisioning_profile = "//mediapipe/examples/ios:developer_provisioning_profile",
deps = [":HelloWorldAppLibrary"],
)
objc_library(
name = "HelloWorldAppLibrary",
srcs = [
"AppDelegate.m",
"ViewController.m",
"main.m",
],
hdrs = [
"AppDelegate.h",
"ViewController.h",
],
data = [
"Base.lproj/LaunchScreen.storyboard",
"Base.lproj/Main.storyboard",
],
sdk_frameworks = [
"UIKit",
],
deps = [],
)
objc_library
kuralı, AppDelegate
ve
ViewController
dersler, main.m
ve uygulamanın resimli taslakları. İlgili içeriği oluşturmak için kullanılan
şablonlu uygulama yalnızca UIKit
SDK'sına bağlıdır.
ios_application
kuralı HelloWorldAppLibrary
Objective-C kitaplığını kullanır
iOS cihazınıza yüklenmek üzere bir iOS uygulaması oluşturmak için oluşturulan bir web sitesini ziyaret edin.
Uygulamayı derlemek için bir terminalde aşağıdaki komutu kullanın:
bazel build -c opt --config=ios_arm64 <$APPLICATION_PATH>:HelloWorldApp'
Örneğin HelloWorldApp
uygulamasını
mediapipe/examples/ios/helloworld
için aşağıdaki komutu kullanın:
bazel build -c opt --config=ios_arm64 mediapipe/examples/ios/helloworld:HelloWorldApp
Ardından XCode'a geri dönün, Window'u açın > Cihazlar ve Simülatörler,
cihazınıza yükleyin ve yukarıdaki komutla oluşturulan .ipa
dosyasını cihazınıza ekleyin.
iOS Framework uygulamalarını kurma ve derleme ile ilgili belgeyi aşağıda bulabilirsiniz.
Cihazınızda uygulamayı açın. Boş olduğu için boş beyaz ekran.
Canlı görüntüleme feed'i için kamerayı kullanma
Bu eğitimde, MPPCameraInputSource
sınıfını kullanarak
çerçeveleri seçin. Bu sınıf, aşağıdaki işlemleri yapmak için AVCaptureSession
API'sini kullanır:
otomatik olarak oluşturulur.
Ancak bu sınıfı kullanmadan önce Info.plist
dosyasını kamerayı destekleyecek şekilde değiştirin
elde etti.
ViewController.m
içine aşağıdaki içe aktarma satırını ekleyin:
#import "mediapipe/objc/MPPCameraInputSource.h"
Nesne oluşturmak için aşağıdaki kodu uygulama bloğuna ekleyin
_cameraSource
:
@implementation ViewController {
// Handles camera access via AVCaptureSession library.
MPPCameraInputSource* _cameraSource;
}
Şu kodu viewDidLoad()
alanına ekleyin:
-(void)viewDidLoad {
[super viewDidLoad];
_cameraSource = [[MPPCameraInputSource alloc] init];
_cameraSource.sessionPreset = AVCaptureSessionPresetHigh;
_cameraSource.cameraPosition = AVCaptureDevicePositionBack;
// The frame's native format is rotated with respect to the portrait orientation.
_cameraSource.orientation = AVCaptureVideoOrientationPortrait;
}
Kod _cameraSource
işlemini başlatır, yakalama oturumu hazır ayarını ayarlar ve
bulun.
_cameraSource
içinden kareleri uygulamamıza almamız gerekiyor
Bunları görüntülemek için ViewController
. MPPCameraInputSource
, şunun bir alt sınıfıdır:
Yetki verilmiş kullanıcıları için bir protokol sağlayan MPPInputSource
MPPInputSourceDelegate
. Bu durumda ViewController
uygulamamız, yetki verilmiş kullanıcı
/ _cameraSource
.
ViewController
arayüzünün tanımını uygun şekilde güncelleyin:
@interface ViewController () <MPPInputSourceDelegate>
Kamera kurulumunu yönetmek ve gelen kareleri işlemek için bir
ana sıradan farklıdır. Aşağıdakini
ViewController
:
// Process camera frames on this queue.
dispatch_queue_t _videoQueue;
viewDidLoad()
içinde, başlatıldıktan sonra aşağıdaki satırı ekleyin
_cameraSource
nesne:
[_cameraSource setDelegate:self queue:_videoQueue];
Kurulumu ayarlamadan önce sırayı başlatmak için aşağıdaki kodu ekleyin
_cameraSource
nesne:
dispatch_queue_attr_t qosAttribute = dispatch_queue_attr_make_with_qos_class(
DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, /*relative_priority=*/0);
_videoQueue = dispatch_queue_create(kVideoQueueLabel, qosAttribute);
Şunun için önceliği QOS_CLASS_USER_INTERACTIVE
olan bir seri sırası kullanacağız:
fotoğraf makinesi çerçeveleri işleniyor.
Dosyanın üst kısmına başlık içe aktarıldıktan sonra, aşağıdaki satırı
arayüzü/uygulaması ViewController
:
static const char* kVideoQueueLabel = "com.google.mediapipe.example.videoQueue";
MPPInputSourceDelegate
protokolündeki herhangi bir yöntemi uygulamadan önce
önce kamera çerçevelerini görüntüleyecek bir yöntem ayarlayın. Mediapipe çerçevesi
MPPLayerRenderer
adlı başka bir yardımcı programı kullanır. Bu
yardımcı programı CVPixelBufferRef
nesnelerini görüntülemek için kullanılabilir.
MPPCameraInputSource
tarafından yetki verilen kullanıcılara sağlanan resimler.
ViewController.m
içine aşağıdaki içe aktarma satırını ekleyin:
#import "mediapipe/objc/MPPLayerRenderer.h"
Ekranın resimlerini görüntülemek için adlı yeni bir UIView
nesnesi eklememiz gerekir.
ViewController
- _liveView
.
Aşağıdaki satırları ViewController
uygulama bloğuna ekleyin:
// Display the camera preview frames.
IBOutlet UIView* _liveView;
// Render frames in a layer.
MPPLayerRenderer* _renderer;
Main.storyboard
menüsüne gidin, nesne kitaplığındanUIView
ViewController
sınıfından View
. Bu görünümden şuna bir referans çıkışı ekleyin:
ViewController
sınıfına eklediğiniz _liveView
nesnesi. Yeniden boyutlandır
ortalanmış olacak ve uygulama ekranının tamamını kaplayacak şekilde
görünür.
ViewController.m
sayfasına dönün ve aşağıdaki kodu viewDidLoad()
içine ekleyin:
_renderer
nesnesini başlatın:
_renderer = [[MPPLayerRenderer alloc] init];
_renderer.layer.frame = _liveView.layer.bounds;
[_liveView.layer addSublayer:_renderer.layer];
_renderer.frameScaleMode = MPPFrameScaleModeFillAndCrop;
Kameradan kare almak için aşağıdaki yöntemi uygulayacağız:
// Must be invoked on _videoQueue.
- (void)processVideoFrame:(CVPixelBufferRef)imageBuffer
timestamp:(CMTime)timestamp
fromSource:(MPPInputSource*)source {
if (source != _cameraSource) {
NSLog(@"Unknown source: %@", source);
return;
}
// Display the captured image on the screen.
CFRetain(imageBuffer);
dispatch_async(dispatch_get_main_queue(), ^{
[_renderer renderPixelBuffer:imageBuffer];
CFRelease(imageBuffer);
});
}
Bu, MPPInputSource
için bir yetki verme yöntemidir. İlk olarak, hesabın doğru
doğru kaynaktan (_cameraSource
) kareler alınıyor. Daha sonra
ana sıradaki _renderer
aracılığıyla kameradan alınan kare.
Şimdi, kareleri görüntülemek için görünüm açılır açılmaz kamerayı başlatmamız gerekiyor.
az sonra görünür. Bunu yapmak için,
viewWillAppear:(BOOL)animated
işlevi:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
Kamerayı çalıştırmaya başlamadan önce, kameraya erişmek için kullanıcının iznini almamız gerekir.
MPPCameraInputSource
, bir işlev sağlar
Kullanıcı aşağıdaki durumda kamera erişimi istemek ve bir işlem yapmak için requestCameraAccessWithCompletionHandler:(void (^_Nullable)(BOOL
granted))handler
yanıt verdi. Şu kodu viewWillAppear:animated
alanına ekleyin:
[_cameraSource requestCameraAccessWithCompletionHandler:^void(BOOL granted) {
if (granted) {
dispatch_async(_videoQueue, ^{
[_cameraSource start];
});
}
}];
Uygulamayı derlemeden önce BUILD
dosyanıza aşağıdaki bağımlılıkları ekleyin.
dosya:
sdk_frameworks = [
"AVFoundation",
"CoreGraphics",
"CoreMedia",
],
deps = [
"//mediapipe/objc:mediapipe_framework_ios",
"//mediapipe/objc:mediapipe_input_sources_ios",
"//mediapipe/objc:mediapipe_layer_renderer",
],
Şimdi uygulamayı iOS cihazınızda derleyip çalıştırın. Burada canlı bir kamera görüntüleme feed'ini etkinleştirin.
Artık kamera çerçevelerini MediaPipe grafiğinde kullanmaya hazırız.
iOS'te bir MediaPipe grafiği kullanma
İlgili bağımlılıkları ekleyin
Şunu içeren bir dosya içeren MediaPipe çerçevesi kodunun bağımlılıklarını
MediaPipe grafiği kullanmak için
iOS API'ye bakalım. Bir MediaPipe grafiğini kullanmak için, bir
kullanmayı planladığımız grafiğe bağımlılığımızı
söyleyebiliriz. Aşağıdakileri ekleyin:
satırı, BUILD
dosyanızdaki data
listesine ekleyin:
"//mediapipe/graphs/edge_detection:mobile_gpu_binary_graph",
Şimdi bağımlılığı, bu grafikte kullanılan hesaplayıcıların deps
alanına ekleyin.
BUILD
dosyasında:
"//mediapipe/graphs/edge_detection:mobile_calculators",
Son olarak, desteği desteklemek için ViewController.m
dosyasını ViewController.mm
olarak yeniden adlandırın
Amaç-C++.
ViewController
uygulamasında grafiği kullanın
ViewController.m
içine aşağıdaki içe aktarma satırını ekleyin:
#import "mediapipe/objc/MPPGraph.h"
Grafiğin adı, giriş akışı ve çıkış akışı:
static NSString* const kGraphName = @"mobile_gpu";
static const char* kInputStream = "input_video";
static const char* kOutputStream = "output_video";
Aşağıdaki özelliği ViewController
arayüzüne ekleyin:
// The MediaPipe graph currently in use. Initialized in viewDidLoad, started in viewWillAppear: and
// sent video frames on _videoQueue.
@property(nonatomic) MPPGraph* mediapipeGraph;
Yukarıdaki yorumda açıklandığı gibi, bu grafiği
Önce viewDidLoad
. Bunu yapmak için grafiği .pbtxt
dosyasından yüklememiz gerekir.
kullanarak aşağıdaki işlevi kullanabilirsiniz:
+ (MPPGraph*)loadGraphFromResource:(NSString*)resource {
// Load the graph config resource.
NSError* configLoadError = nil;
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
if (!resource || resource.length == 0) {
return nil;
}
NSURL* graphURL = [bundle URLForResource:resource withExtension:@"binarypb"];
NSData* data = [NSData dataWithContentsOfURL:graphURL options:0 error:&configLoadError];
if (!data) {
NSLog(@"Failed to load MediaPipe graph config: %@", configLoadError);
return nil;
}
// Parse the graph config resource into mediapipe::CalculatorGraphConfig proto object.
mediapipe::CalculatorGraphConfig config;
config.ParseFromArray(data.bytes, data.length);
// Create MediaPipe graph with mediapipe::CalculatorGraphConfig proto object.
MPPGraph* newGraph = [[MPPGraph alloc] initWithGraphConfig:config];
[newGraph addFrameOutputStream:kOutputStream outputPacketType:MPPPacketTypePixelBuffer];
return newGraph;
}
viewDidLoad
içindeki grafiği şu şekilde başlatmak için bu işlevi kullanın:
self.mediapipeGraph = [[self class] loadGraphFromResource:kGraphName];
Grafik, kamera çerçevelerini işlemenin sonuçlarını
ViewController
Grafiği başlattıktan sonra
mediapipeGraph
nesnesinin yetki verilmiş kullanıcısı olarak ViewController
:
self.mediapipeGraph.delegate = self;
Canlı video feed'indeki kareleri işlerken bellek çakışmasını önlemek için şu satırı ekleyin:
// Set maxFramesInFlight to a small value to avoid memory contention for real-time processing.
self.mediapipeGraph.maxFramesInFlight = 2;
Şimdi, kullanıcı kamerayı kullanma izni verdiğinde grafiği başlatın inceleyebilirsiniz:
[_cameraSource requestCameraAccessWithCompletionHandler:^void(BOOL granted) {
if (granted) {
// Start running self.mediapipeGraph.
NSError* error;
if (![self.mediapipeGraph startWithError:&error]) {
NSLog(@"Failed to start graph: %@", error);
}
else if (![self.mediapipeGraph waitUntilIdleWithError:&error]) {
NSLog(@"Failed to complete graph initial run: %@", error);
}
dispatch_async(_videoQueue, ^{
[_cameraSource start];
});
}
}];
Daha önce, processVideoFrame
içindeki kameradan kareler aldığımızda
işlevinde, _renderer
kullanarak bunları _liveView
içinde görüntüledik. Artık
ve bunun yerine bu kareleri grafiğe gönderip sonuçları
oluşturmanız gerekir. Değiştir
işlevini kullanarak şunları yapabilirsiniz:
- (void)processVideoFrame:(CVPixelBufferRef)imageBuffer
timestamp:(CMTime)timestamp
fromSource:(MPPInputSource*)source {
if (source != _cameraSource) {
NSLog(@"Unknown source: %@", source);
return;
}
[self.mediapipeGraph sendPixelBuffer:imageBuffer
intoStream:kInputStream
packetType:MPPPacketTypePixelBuffer];
}
imageBuffer
öğesini self.mediapipeGraph
adresine tür bir paket olarak göndeririz
MPPPacketTypePixelBuffer
, kInputStream
giriş akışına eklenir.
"input_video".
Grafik, bu giriş paketiyle çalışır ve şu sonucu verir:
kOutputStream
, ör. "çıkış_video". Aşağıdaki temsilciyi uygulayabiliriz
yöntemlerini kullanın:
- (void)mediapipeGraph:(MPPGraph*)graph
didOutputPixelBuffer:(CVPixelBufferRef)pixelBuffer
fromStream:(const std::string&)streamName {
if (streamName == kOutputStream) {
// Display the captured image on the screen.
CVPixelBufferRetain(pixelBuffer);
dispatch_async(dispatch_get_main_queue(), ^{
[_renderer renderPixelBuffer:pixelBuffer];
CVPixelBufferRelease(pixelBuffer);
});
}
}
ViewController
öğesinin arayüz tanımını MPPGraphDelegate
ile güncelleyin:
@interface ViewController () <MPPGraphDelegate, MPPInputSourceDelegate>
Hepsi bu kadar! Uygulamayı iOS cihazınızda derleyip çalıştırın. Burada sonuçlarını görebilirsiniz. Tebrikler!
iOS örneklerinin artık yaygın bir şablon uygulaması kullandığını unutmayın. Bu işlemde
bu eğitim, common şablon uygulamasında kullanılır. helloworld uygulamasında
bağımlılık grafiği için uygun BUILD
dosya bağımlılıklarını