Samouczek OpenCV: wykrywanie obiektów w czasie rzeczywistym za pomocą MSER w iOS

Opublikowany: 2022-03-11

W ciągu ostatnich kilku lat średnia wydajność telefonu komórkowego znacznie wzrosła. Czy to ze względu na samą moc procesora, czy pojemność pamięci RAM, teraz łatwiej jest wykonywać zadania wymagające dużych obliczeń na sprzęcie mobilnym. Chociaż te technologie mobilne zmierzają we właściwym kierunku, wciąż jest wiele do zrobienia na platformach mobilnych, zwłaszcza w obliczu pojawienia się rzeczywistości rozszerzonej, rzeczywistości wirtualnej i sztucznej inteligencji.

Głównym wyzwaniem w wizji komputerowej jest wykrywanie obiektów zainteresowania na obrazach. Ludzkie oko i mózg wykonują wyjątkową pracę, a powielanie tego w maszynach to wciąż marzenie. W ostatnich dziesięcioleciach opracowano metody naśladowania tego w maszynach i jest to coraz lepsze.

W tym samouczku omówimy algorytm używany do wykrywania plam na obrazach. Wykorzystamy również algorytm z biblioteki OpenCV o otwartym kodzie źródłowym, aby zaimplementować prototypową aplikację na iPhone'a, która wykorzystuje tylną kamerę do pozyskiwania obrazów i wykrywania w nich obiektów.

Samouczek OpenCV

OpenCV to biblioteka typu open source, która zapewnia implementacje głównych algorytmów wizji komputerowej i uczenia maszynowego. Jeśli chcesz zaimplementować aplikację do wykrywania twarzy, gry w karty na stole pokerowym, a nawet prostą aplikację do dodawania efektów do dowolnego obrazu, to OpenCV jest doskonałym wyborem.

OpenCV jest napisany w C/C++ i posiada biblioteki opakowujące dla wszystkich głównych platform. Dzięki temu jest szczególnie łatwy w użyciu w środowisku iOS. Aby używać go w aplikacji Objective-C iOS, pobierz OpenCV iOS Framework z oficjalnej strony internetowej. Upewnij się, że używasz wersji 2.4.11 OpenCV dla iOS (której używasz w tym artykule), ponieważ najnowsza wersja, 3.0, ma pewne zmiany w organizacji plików nagłówkowych, które naruszają kompatybilność. Szczegółowe informacje o tym, jak go zainstalować, są udokumentowane na jego stronie internetowej.

MSER

MSER, skrót od Maximally Stable Extremal Regions, jest jedną z wielu dostępnych metod wykrywania blobów w obrazach. Mówiąc prościej, algorytm identyfikuje sąsiednie zestawy pikseli, których intensywności pikseli zewnętrznej granicy są wyższe (o dany próg) niż intensywności pikseli wewnętrznej granicy. Mówi się, że takie regiony są maksymalnie stabilne, jeśli nie zmieniają się zbytnio w różnym natężeniu.

Chociaż istnieje wiele innych algorytmów wykrywania blobów, wybrano tutaj MSER, ponieważ ma on dość niewielką złożoność w czasie wykonywania wynoszącą O(n log(log(n))), gdzie n jest całkowitą liczbą pikseli na obrazie. Algorytm jest również odporny na rozmycie i skalowanie, co jest korzystne w przypadku przetwarzania obrazów uzyskanych ze źródeł czasu rzeczywistego, takich jak aparat telefonu komórkowego.

Na potrzeby tego samouczka zaprojektujemy aplikację do wykrywania logo Toptal. Symbol ma ostre rogi, co może skłaniać do myślenia o tym, jak skuteczne mogą być algorytmy wykrywania rogów w wykrywaniu logo Toptal. W końcu taki algorytm jest zarówno prosty w użyciu, jak i zrozumiały. Chociaż metody oparte na narożnikach mogą mieć wysoki wskaźnik sukcesu, jeśli chodzi o wykrywanie obiektów wyraźnie oddzielonych od tła (takich jak czarne obiekty na białym tle), trudno byłoby osiągnąć wykrywanie w czasie rzeczywistym logo Toptal w świecie rzeczywistym obrazy, w których algorytm nieustannie wykrywałby setki narożników.

Strategia

uczenie maszynowe i opencv

Każda klatka obrazu, którą aplikacja pobiera za pomocą aparatu, jest najpierw konwertowana do skali szarości. Obrazy w skali szarości mają tylko jeden kanał koloru, ale logo będzie jednak widoczne. Ułatwia to algorytmowi radzenie sobie z obrazem i znacznie zmniejsza ilość danych, które algorytm musi przetwarzać, przy niewielkim lub zerowym zysku.

Następnie użyjemy implementacji OpenCV algorytmu do wyodrębnienia wszystkich MSER. Następnie każdy MSER zostanie znormalizowany poprzez przekształcenie jego minimalnego prostokąta ograniczającego w kwadrat. Ten krok jest ważny, ponieważ logo może być pozyskiwane z różnych kątów i odległości, a to zwiększy tolerancję zniekształceń perspektywy.

Ponadto dla każdego MSER obliczana jest pewna liczba właściwości:

  • Liczba otworów
  • Stosunek powierzchni MSER do powierzchni jego wypukłego kadłuba
  • Stosunek pola MSER do pola jego prostokąta o minimalnej powierzchni
  • Stosunek długości szkieletu MSER do powierzchni MSER
  • Stosunek powierzchni MSER do powierzchni jej największego konturu

aplikacje ios i uczenie maszynowe

Aby wykryć logo Toptal na obrazie, właściwości wszystkich MSER są porównywane z już poznanymi właściwościami logo Toptal. Na potrzeby tego samouczka maksymalne dozwolone różnice dla każdej właściwości zostały wybrane empirycznie.

Na koniec jako wynik wybierany jest najbardziej podobny region.

Aplikacja na iOS

Korzystanie z OpenCV z iOS jest łatwe. Jeśli jeszcze tego nie zrobiłeś, oto krótki opis kroków związanych z konfiguracją Xcode w celu utworzenia aplikacji na iOS i użycia w niej OpenCV:

  1. Utwórz nową nazwę projektu „SuperCool Logo Detector”. Jako język pozostaw wybrany Cel-C.

  2. Dodaj nowy plik nagłówka prefiksu (.pch) i nazwij go PrefixHeader.pch

  3. Przejdź do projektu „SuperCool Logo Detector” Build Target i na karcie Build Settings znajdź ustawienie „Prefix Headers”. Możesz go znaleźć w sekcji Język LLVM lub skorzystać z funkcji wyszukiwania.

  4. Dodaj „PrefixHeader.pch” do ustawienia nagłówków przedrostków

  5. W tym momencie, jeśli nie zainstalowałeś OpenCV dla iOS 2.4.11, zrób to teraz.

  6. Przeciągnij i upuść pobrany framework do projektu. Sprawdź „Połączone struktury i biblioteki” w ustawieniach docelowych. (Powinno być dodawane automatycznie, ale lepiej być bezpiecznym.)

  7. Dodatkowo połącz następujące frameworki:

    • Fundacja AV
    • ZasobyBiblioteka
    • CoreMedia
  8. Otwórz „PrefixHeader.pch” i dodaj następujące 3 linie:

     #ifdef __cplusplus #include <opencv2/opencv.hpp> #endif”
  9. Zmień rozszerzenia automatycznie tworzonych plików kodu z „ .m” na „ .mm”. OpenCV jest napisany w C++ iz *.mm mówisz, że będziesz używać Objective-C++.

  10. Zaimportuj „opencv2/highgui/cap_ios.h” w ViewController.hi zmień ViewController, aby był zgodny z protokołem CvVideoCameraDelegate:

     #import <opencv2/highgui/cap_ios.h>
  11. Otwórz Main.storyboard i umieść UIImageView na początkowym kontrolerze widoku.

  12. Stwórz ujście do ViewController.mm o nazwie „imageView”

  13. Utwórz zmienną „CvVideoCamera *camera;” w ViewController.h lub ViewController.mm i zainicjuj go z odniesieniem do tylnej kamery:

     camera = [[CvVideoCamera alloc] initWithParentView: _imageView]; camera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; camera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; camera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; camera.defaultFPS = 30; camera.grayscaleMode = NO; camera.delegate = self;
  14. Jeśli teraz zbudujesz projekt, Xcode ostrzeże Cię, że nie zaimplementowałeś metody „processImage” z CvVideoCameraDelegate. Na razie, dla uproszczenia, po prostu pobierzemy obrazy z aparatu i nałożymy na nie prosty tekst:

    • Dodaj pojedynczą linię do „viewDidAppear”:
     [camera start];
    • Teraz, jeśli uruchomisz aplikację, poprosi Cię o pozwolenie na dostęp do kamery. A potem powinieneś zobaczyć wideo z kamery.

    • W metodzie „processImage” dodaj następujące dwie linie:

     const char* str = [@"Toptal" cStringUsingEncoding: NSUTF8StringEncoding]; cv::putText(image, str, cv::Point(100, 100), CV_FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 0, 255));

To prawie wszystko. Teraz masz bardzo prostą aplikację, która rysuje tekst „Toptal” na obrazach z aparatu. Możemy teraz zbudować naszą aplikację do wykrywania logo docelowego z tej prostszej. Dla zwięzłości, w tym artykule omówimy tylko kilka segmentów kodu, które mają kluczowe znaczenie dla ogólnego zrozumienia działania aplikacji. Kod na GitHub zawiera sporo komentarzy wyjaśniających, co robi każdy segment.

Ponieważ aplikacja ma tylko jeden cel, wykrywanie logo Toptal, zaraz po uruchomieniu, funkcje MSER są wyodrębniane z danego obrazu szablonu, a wartości są przechowywane w pamięci:

 cv::Mat logo = [ImageUtils cvMatFromUIImage: templateImage]; //get gray image cv::Mat gray; cvtColor(logo, gray, CV_BGRA2GRAY); //mser with maximum area is std::vector<cv::Point> maxMser = [ImageUtils maxMser: &gray]; //get 4 vertices of the maxMSER minrect cv::RotatedRect rect = cv::minAreaRect(maxMser); cv::Point2f points[4]; rect.points(points); //normalize image cv::Mat M = [GeometryUtil getPerspectiveMatrix: points toSize: rect.size]; cv::Mat normalizedImage = [GeometryUtil normalizeImage: &gray withTranformationMatrix: &M withSize: rect.size.width]; //get maxMser from normalized image std::vector<cv::Point> normalizedMser = [ImageUtils maxMser: &normalizedImage]; //remember the template self.logoTemplate = [[MSERManager sharedInstance] extractFeature: &normalizedMser]; //store the feature [self storeTemplate];

Aplikacja posiada tylko jeden ekran z przyciskiem Start/Stop, a wszystkie niezbędne informacje, takie jak FPS i liczba wykrytych MSERów, są rysowane automatycznie na obrazie. Dopóki aplikacja nie zostanie zatrzymana, dla każdej klatki obrazu w aparacie wywoływana jest następująca metoda processImage:

 -(void)processImage:(cv::Mat &)image { cv::Mat gray; cvtColor(image, gray, CV_BGRA2GRAY); std::vector<std::vector<cv::Point>> msers; [[MSERManager sharedInstance] detectRegions: gray intoVector: msers]; if (msers.size() == 0) { return; }; std::vector<cv::Point> *bestMser = nil; double bestPoint = 10.0; std::for_each(msers.begin(), msers.end(), [&] (std::vector<cv::Point> &mser) { MSERFeature *feature = [[MSERManager sharedInstance] extractFeature: &mser]; if(feature != nil) { if([[MLManager sharedInstance] isToptalLogo: feature] ) { double tmp = [[MLManager sharedInstance] distance: feature ]; if ( bestPoint > tmp ) { bestPoint = tmp; bestMser = &mser; } } } }); if (bestMser) { NSLog(@"minDist: %f", bestPoint); cv::Rect bound = cv::boundingRect(*bestMser); cv::rectangle(image, bound, GREEN, 3); } else { cv::rectangle(image, cv::Rect(0, 0, W, H), RED, 3); } // Omitted debug code [FPS draw: image]; }

Ta metoda zasadniczo tworzy kopię oryginalnego obrazu w skali szarości. Identyfikuje wszystkie MSER i wyodrębnia ich istotne cechy, ocenia każdy MSER pod kątem podobieństwa do szablonu i wybiera najlepszy. Na koniec rysuje zieloną granicę wokół najlepszego MSER i nakłada na obraz metainformacje.

Poniżej znajdują się definicje kilku ważnych klas i ich metod w tej aplikacji. Ich cele są opisane w komentarzach.

GeometriaUtil.h

 /* This static class provides perspective transformation function */ @interface GeometryUtil : NSObject /* Return perspective transformation matrix for given points to square with origin [0,0] and with size (size.width, size.width) */ + (cv::Mat) getPerspectiveMatrix: (cv::Point2f[]) points toSize: (cv::Size2f) size; /* Returns new perspecivly transformed image with given size */ + (cv::Mat) normalizeImage: (cv::Mat *) image withTranformationMatrix: (cv::Mat *) M withSize: (float) size; @end

MSERManager.h

 /* Singelton class providing function related to msers */ @interface MSERManager : NSObject + (MSERManager *) sharedInstance; /* Extracts all msers into provided vector */ - (void) detectRegions: (cv::Mat &) gray intoVector: (std::vector<std::vector<cv::Point>> &) vector; /* Extracts feature from the mser. For some MSERs feature can be NULL !!! */ - (MSERFeature *) extractFeature: (std::vector<cv::Point> *) mser; @end

MLManager.h

 /* This singleton class wraps object recognition function */ @interface MLManager : NSObject + (MLManager *) sharedInstance; /* Stores feature from the biggest MSER in the templateImage */ - (void) learn: (UIImage *) templateImage; /* Sum of the differences between logo feature and given feature */ - (double) distance: (MSERFeature *) feature; /* Returns true if the given feature is similar to the one learned from the template */ - (BOOL) isToptalLogo: (MSERFeature *) feature; @end

Po połączeniu wszystkiego razem, dzięki tej aplikacji powinieneś być w stanie użyć aparatu urządzenia z systemem iOS, aby wykryć logo Toptal pod różnymi kątami i orientacjami.

Wykrywanie obrazu (logo Toptal) w pionie.

Wykrywanie obrazu (logo Toptal) po przekątnej na koszuli.

Aplikacje rzeczywistości rozszerzonej zaczynają się od zrozumienia obrazów i właśnie w ten sposób możesz to zrobić.
Ćwierkać

Wniosek

W tym artykule pokazaliśmy, jak łatwo wykrywać proste obiekty z obrazu za pomocą OpenCV. Cały kod jest dostępny na GitHub. Zapraszam do rozwidlenia i wysyłania żądań push, ponieważ wkłady są mile widziane.

Podobnie jak w przypadku wszelkich problemów z uczeniem maszynowym, wskaźnik sukcesu wykrywania logo w tej aplikacji można zwiększyć, stosując inny zestaw funkcji i inną metodę klasyfikacji obiektów. Mam jednak nadzieję, że ten artykuł pomoże Ci w rozpoczęciu pracy z wykrywaniem obiektów za pomocą MSER i ogólnie z zastosowaniem technik widzenia komputerowego.

Dalsza lektura

  • J. Matasa, O. Chuma, M. Urbana i T. Pajdla. „Solidna szeroka linia bazowa stereo z maksymalnie stabilnych regionów ekstremalnych”.
  • Neumanna, Łukasza; Matas, Jiri (2011). „Metoda lokalizacji i rozpoznawania tekstu w rzeczywistych obrazach”
Powiązane: Wstępny samouczek programowania robotów