OpenCV ve Swift Kullanarak Nesne Algılama

Yayınlanan: 2022-03-11

Swift bir süredir bizimle ve yinelemeleriyle modern nesne yönelimli programlama dilinin tüm özelliklerini bize getirdi. Bunlar, seçenekleri, jenerikleri, tanımlama gruplarını, yöntemleri, uzantıları ve protokolleri destekleyen yapıları ve daha fazlasını içerir. Ancak uygulamanız C++ kullanılarak yazılmış bir kitaplığa dayanıyorsa, artık Swift'e güvenemezsiniz. Neyse ki Objective-C++ bize yardım etmek için burada.

Girişinden bu yana Swift, Objective-C ile harika bir birlikte çalışabilirliğe sahipti ve Swift ile C++ arasında köprü oluşturmak için Objective-C'yi kullanacağız. Objective-C++, C++ koduyla bağlantı kurma yeteneğine sahip Objective-C'den başka bir şey değildir ve bunu kullanarak, bu blog gönderisinde, OpenCV kullanarak görüntünün içindeki Toptal logosunu tanıyacak basit bir uygulama oluşturacağız. O logoyu tespit ettiğimizde Toptal ana sayfasını açacağız.

OpenCV web sayfasında belirtildiği gibi:

"OpenCV, hesaplama verimliliği için ve gerçek zamanlı uygulamalara güçlü bir şekilde odaklanarak tasarlandı. Optimize edilmiş C/C++ ile yazılmış kitaplık, çok çekirdekli işlemenin avantajlarından yararlanabilir."

Hızlı ve güvenilir bir bilgisayar vizyonu geliştirmek istiyorsanız bu harika bir çözümdür.

OpenCV Objective-C++ Wrapper'ı Oluşturma

Bu dersimizde Toptal logosunu bir görsel içinde eşleştirecek ve Toptal web sayfasını açacak bir uygulama tasarlayacağız. Başlamak için yeni bir Xcode projesi oluşturun ve pod init kullanarak CocoaPod'ları kurun. OpenCV'yi Podfile pod 'OpenCV ekleyin ve Terminal'de pod install çalıştırın. use_frameworks emin olun! Podfile içindeki ifade.

Şimdi, Xcode projesinde OpenCV'ye sahip olduğumuzda, onu Swift ile bağlamamız gerekiyor. İşte ilgili adımların kısa bir özeti:

Adım 1: Yeni bir Objective-C sınıfı OpenCVWrapper . Xcode size “ Bir Objective-C köprüleme başlığı yapılandırmak ister misiniz? ” “ Köprüleme başlığı oluştur ”u seçin. Köprüleme başlığı, Objective-C sınıflarını içe aktardığınız yerdir ve ardından Swift içinde görünürler.

Adım 2: Objective-C içinde C++ kullanmak için dosya uzantısını OpenCVWrapper.m OpenCVWrapper.mm . Bunu, Xcode'un proje gezgini içindeki dosyayı yeniden adlandırarak yapabilirsiniz. Uzantı olarak .mm eklemek, dosya türünü Objective-C'den Objective-C++'a değiştirecektir.

Adım 3: Aşağıdaki içe aktarmayı kullanarak OpenCVWrapper.mm aktarın. Verilen içe #import "OpenCVWrapper.h" üzerine yazmak önemlidir çünkü bu şekilde iyi bilinen bir BOOL çakışmasından kaçınırız. OpenCV, Objective-C BOOL NO değeriyle çakışmaya neden olan NO değerine sahip enum içerir. Bu tür enum kullanan sınıflara ihtiyacınız yoksa, bu en basit yoldur. Aksi takdirde, OpenCV'yi içe aktarmadan önce BOOL tanımını kaldırmanız gerekir.

 #ifdef __cplusplus #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h> #import <opencv2/videoio/cap_ios.h> #endif

Adım 4: Köprüleme başlığınıza #import "OpenCVWrapper.h" ekleyin.

OpenCVWrapper.mm açın ve özel mülkleri bildireceğimiz özel bir arayüz oluşturun:

 @interface OpenCVWrapper() <CvVideoCameraDelegate> @property (strong, nonatomic) CvVideoCamera *videoCamera; @property (assign, nonatomic) cv::Mat logoSample; @end

CvVideoCamera oluşturmak için, ona UIImageView iletmemiz gerekiyor ve bunu gösterge başlatıcımız aracılığıyla yapacağız.

 - (instancetype)initWithParentView:(UIImageView *)parentView delegate:(id<OpenCVWrapperDelegate>)delegate { if (self = [super init]) { self.delegate = delegate; parentView.contentMode = UIViewContentModeScaleAspectFill; self.videoCamera = [[CvVideoCamera alloc] initWithParentView:parentView]; self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh; self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; self.videoCamera.defaultFPS = 30; self.videoCamera.grayscaleMode = [NSNumber numberWithInt:0].boolValue; self.videoCamera.delegate = self; // Convert UIImage to Mat and store greyscale version UIImage *templateImage = [UIImage imageNamed:@"toptal"]; cv::Mat templateMat; UIImageToMat(templateImage, templateMat); cv::Mat grayscaleMat; cv::cvtColor(templateMat, grayscaleMat, CV_RGB2GRAY); self.logoSample = grayscaleMat; [self.videoCamera start]; } return self; }

Bunun içinde, videoyu verilen parentView içinde işleyen ve temsilci aracılığıyla analiz için bize cv::Mat görüntüsü gönderen CvVideoCamera yapılandırıyoruz.

processImage processImage: method CvVideoCameraDelegate protokolündendir ve bunun içinde şablon eşleştirme yapacağız.

 - (void)processImage:(cv::Mat&)image { cv::Mat gimg; // Convert incoming img to greyscale to match template cv::cvtColor(image, gimg, CV_BGR2GRAY); // Get matching cv::Mat res(image.rows-self.logoSample.rows+1, self.logoSample.cols-self.logoSample.cols+1, CV_32FC1); cv::matchTemplate(gimg, self.logoSample, res, CV_TM_CCOEFF_NORMED); cv::threshold(res, res, 0.5, 1., CV_THRESH_TOZERO); double minval, maxval, threshold = 0.9; cv::Point minloc, maxloc; cv::minMaxLoc(res, &minval, &maxval, &minloc, &maxloc); // Call delegate if match is good enough if (maxval >= threshold) { // Draw a rectangle for confirmation cv::rectangle(image, maxloc, cv::Point(maxloc.x + self.logoSample.cols, maxloc.y + self.logoSample.rows), CV_RGB(0,255,0), 2); cv::floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(.1), cv::Scalar(1.)); [self.delegate openCVWrapperDidMatchImage:self]; } }

İlk olarak, verilen resmi gri tonlamalı resme dönüştürüyoruz çünkü init yönteminin içinde Toptal logo şablon eşleştirme resmimizi gri tonlamaya dönüştürdük. Bir sonraki adım, ölçekleme ve açılar konusunda bize yardımcı olacak belirli bir eşiğe sahip eşleşmeleri kontrol etmektir. Açıları kontrol etmemiz gerekiyor çünkü hala logoyu tespit etmek istediğimiz çeşitli açılardan bir fotoğraf çekebiliyorsunuz. Verilen eşiğe ulaştıktan sonra delege çağıracağız ve Toptal'ın web sayfasını açacağız.

Info.plist'inize NSCameraUsageDescription eklemeyi unutmayın, aksi takdirde uygulamanız [self.videoCamera start]; .

Şimdi Sonunda Hızlı

Şimdiye kadar Objective-C++'a odaklandık çünkü tüm mantık onun içinde yapıldı. Swift kodumuz oldukça basit olacak:

  1. ViewController.swift içinde, CvVideoCamera içerik oluşturacağı UIImageView oluşturun.
  2. Bir OpenCVWrapper örneği oluşturun ve UIImageView örneğini ona iletin.
  3. Logoyu algıladığımızda Toptal'ın web sayfasını açmak için OpenCVWrapperDelegate protokolünü uygulayın.
 class ViewController: UIViewController { var wrapper: OpenCVWrapper! @IBOutlet var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. wrapper = OpenCVWrapper.init(parentView: imageView, delegate: self) } } extension ViewController: OpenCVWrapperDelegate { //MARK: - OpenCVWrapperDelegate func openCVWrapperDidMatchImage(_ wrapper: OpenCVWrapper) { UIApplication.shared.open(URL.init(string: "https://toptal.com")!, options: [:], completionHandler: nil) } }

OpenCV Swift İş Başında

Bu yazıda, C++ kodunu Swift ile nasıl entegre edebileceğinizi ve C++ kodunu Swift ile köprülemek için burada bulunan sarmalayıcı sınıfları nasıl oluşturabileceğinizi gösterdik. Artık Toptal Logosunu kameradan algıladığımızda Toptal'ın ana sayfasını açıyoruz.

OpenCV Swift ile Toptal'ın Logosunu Tespit Etme

Gelecekteki güncellemeler için, bir arka plan dizisinde CV şablonu eşleştirmesini çalıştırmak isteyebilirsiniz. Bu şekilde ana ileti dizisini engellemezsiniz ve kullanıcı arayüzü yanıt vermeye devam eder. Bu basit bir OpenCV örneği olduğu için şablon eşleştirme çok başarılı olmayabilir, ancak bu makalenin amacı size onu nasıl kullanmaya başlayabileceğinizi göstermekti.

OpenCV'yi ve iOS'taki daha karmaşık kullanımlarını öğrenmekle hala ilgileniyorsanız, iPhone'un arka kamerasını kullanarak görüntü algılama konusunda size yol gösteren iOS'ta MSER Kullanarak Gerçek Zamanlı Nesne Algılama'yı öneririm .