I løpet av de siste årene har den gjennomsnittlige ytelsen på mobiltelefonen økt betydelig. Det være seg for ren CPU-hestekrefter eller RAM-kapasitet, det er nå lettere å gjøre beregningstunge oppgaver på mobil maskinvare. Selv om disse mobile teknologiene går i riktig retning, er det fortsatt mye å gjøre på mobile plattformer, spesielt med advent av utvidet virkelighet, virtuell virkelighet og kunstig intelligens.
En stor utfordring i datasyn er å oppdage objekter av interesse for bilder. Det menneskelige øye og hjerne gjør en eksepsjonell jobb, og replikere dette i maskiner er fortsatt en drøm. I løpet av de siste tiårene har det blitt utviklet tilnærminger for å etterligne dette i maskiner, og det blir bedre.
I denne opplæringen vil vi utforske en algoritme som brukes til å oppdage klatter i bilder. Vi vil også bruke algoritmen, fra open source-biblioteket, OpenCV, til å implementere en prototype iPhone-applikasjon som bruker bakkameraet til å skaffe bilder og oppdage gjenstander i dem.
OpenCV er et open source-bibliotek som gir implementeringer av store datasyn og maskinlæringsalgoritmer. Hvis du vil implementere et program for å oppdage ansikter, spillekort på et pokerbord, eller til og med et enkelt program for å legge til effekter på et vilkårlig bilde, er OpenCV et godt valg.
OpenCV er skrevet i C / C ++, og har wrapper-biblioteker for alle større plattformer. Dette gjør det spesielt enkelt å bruke i iOS-miljø . Å bruke den i en Objective-C iOS-applikasjon , last ned OpenCV iOS Framework fra det offisielle nettstedet . Forsikre deg om at du bruker versjon 2.4.11 av OpenCV for iOS (som denne artikkelen antar at du bruker), da den siste versjonen, 3.0, har noen kompatibilitetsbrudd i hvordan headerfilene er organisert. Detaljert informasjon om hvordan du installerer den dokumentert på hjemmesiden sin .
MSER , forkortelse for Maximally Stable Extreme Regions, er en av de mange metodene som er tilgjengelige for blob-deteksjon i bilder. Med enkle ord identifiserer algoritmen sammenhengende sett med piksler hvis ytre grense pikselintensitet er høyere (ved en gitt terskel) enn den indre grense pikselintensiteten. Slike regioner sies å være maksimalt stabile hvis de ikke endrer seg mye over en varierende mengde intensiteter.
Selv om en rekke andre blobdeteksjonsalgoritmer eksisterer, ble MSER valgt her fordi den har en ganske lett kjøretidskompleksitet på O (n log (log (n))) hvor n er det totale antall piksler på bildet. Algoritmen er også robust for uskarphet og skalering, noe som er fordelaktig når det gjelder behandling av bilder hentet gjennom sanntidskilder, for eksempel kameraet til en mobiltelefon.
For formålet med denne veiledningen vil vi designe applikasjon for å oppdage logoen til ApeeScape. Symbolet har skarpe hjørner, og det kan føre til at man tenker på hvor effektive hjørnedeteksjonsalgoritmer kan være for å oppdage ApeeScapes logo. Tross alt er en slik algoritme både enkel å bruke og forstå. Selv om hjørnebaserte metoder kan ha høy suksessrate når det gjelder å oppdage objekter som er tydelig atskilt fra bakgrunnen (for eksempel sorte gjenstander på hvit bakgrunn), ville det være vanskelig å oppnå sanntidsregistrering av ApeeScapes logo på bilder fra den virkelige verden, der algoritmen hele tiden ville oppdage hundrevis av hjørner.
For hver bilderamme applikasjonen får gjennom kameraet, konverteres den først til gråtoner. Gråtonebilder har bare en fargekanal, men logoen vil være synlig. Dette gjør det enklere for algoritmen å håndtere bildet og reduserer mengden data algoritmen må behandle betydelig for liten eller ingen ekstra gevinst.
Deretter vil vi bruke OpenCVs implementering av algoritmen til å trekke ut alle MSER-er. Deretter vil hver MSER normaliseres ved å transformere sitt minste avgrensningsrektangel til et kvadrat. Dette trinnet er viktig fordi logoen kan hentes fra forskjellige vinkler og avstander, og dette vil øke toleransen for perspektivforvrengning.
Videre beregnes et antall egenskaper for hver MSER:
For å oppdage ApeeScapes logo i et bilde, blir egenskapene til alle MSER-ene sammenlignet med allerede innlærte ApeeScape-logo-egenskaper. For formålet med denne opplæringen ble maksimalt tillatte forskjeller for hver eiendom valgt empirisk.
Til slutt blir den mest like regionen valgt som resultat.
Å bruke OpenCV fra iOS er enkelt. Hvis du ikke har gjort det ennå, er det en rask oversikt over trinnene som er involvert i å konfigurere Xcode for å lage en iOS-applikasjon og bruke OpenCV i den:
Opprett et nytt prosjektnavn 'SuperCool Logo Detector.' La Objective-C være valgt som språk.
Legg til en ny prefiksoverskrift (.pch) -fil og gi den navnet PrefixHeader.pch
Gå inn i prosjektet 'SuperCool Logo Detector' Build Target, og finn 'Prefix Headers' -innstillingen i kategorien Build Settings. Du finner den i delen LLVM Language, eller bruk søkefunksjonen.
Legg til “PrefixHeader.pch” i innstillingen for prefiksoverskrifter
På dette punktet, hvis du ikke har installert OpenCV for iOS 2.4.11, gjør det nå.
Dra og slipp det nedlastede rammeverket inn i prosjektet. Sjekk 'Koblede rammeverk og biblioteker' i målinnstillingene dine. (Det skal legges til automatisk, men bedre for å være trygg.)
I tillegg knytter du følgende rammer:
Åpne “PrefixHeader.pch” og legg til følgende tre linjer:
#ifdef __cplusplus #include #endif”
Endre utvidelser av automatisk opprettede kodefiler fra “ .m ”til“ .mm ”. OpenCV er skrevet i C ++ og med * .mm sier du at du vil bruke Objective-C ++.
Importer “opencv2 / highgui / cap_ios.h” i ViewController.h og endre ViewController for å overholde protokollen CvVideoCameraDelegate:
#import
Åpne Main.storyboard og sett en UIImageView på den opprinnelige visningskontrolleren.
Gjør et utsalgssted til ViewController.mm med navnet “imageView”
Lag et variabelt “CvVideoCamera * kamera;” i ViewController.h eller ViewController.mm, og initialiser den med en referanse til bakkameraet:
camera = [[CvVideoCamera alloc] initWithParentView: _imageView]; camera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; camera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; camera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; camera.defaultFPS = 30; camera.grayscaleMode = NO; camera.delegate = self;
Hvis du bygger prosjektet nå, vil Xcode advare deg om at du ikke implementerte “processImage” -metoden fra CvVideoCameraDelegate. For nå, og for enkelhets skyld, vil vi bare skaffe bildene fra kameraet og legge dem over med en enkel tekst:
[camera start];
Nå, hvis du kjører applikasjonen, vil den be deg om tillatelse til å få tilgang til kameraet. Og så bør du se video fra kameraet.
Legg til følgende to linjer i 'processImage' -metoden:
const char* str = [@'ApeeScape' cStringUsingEncoding: NSUTF8StringEncoding]; cv::putText(image, str, cv::Point(100, 100), CV_FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 0, 255));
Det er ganske mye det. Nå har du et veldig enkelt program som tegner teksten 'ApeeScape' på bilder fra kameraet. Vi kan nå bygge vår mållogo som oppdager applikasjon av denne enklere. For kortfattethet vil vi i denne artikkelen bare diskutere en håndfull kodesegmenter som er avgjørende for å forstå hvordan applikasjonen fungerer generelt. Koden på GitHub har ganske mange kommentarer for å forklare hva hvert segment gjør.
Siden applikasjonen bare har ett formål, å oppdage ApeeScapes logo, så snart den er lansert, blir MSER-funksjoner hentet fra det gitte malbildet, og verdiene lagres i minnet:
cv::Mat logo = [ImageUtils cvMatFromUIImage: templateImage]; //get gray image cv::Mat gray; cvtColor(logo, gray, CV_BGRA2GRAY); //mser with maximum area is std::vector 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 normalizedMser = [ImageUtils maxMser: &normalizedImage]; //remember the template self.logoTemplate = [[MSERManager sharedInstance] extractFeature: &normalizedMser]; //store the feature [self storeTemplate];
Applikasjonen har bare en skjerm med en Start / Stop-knapp, og all nødvendig informasjon, som FPS og antall oppdagede MSERer, blir automatisk tegnet på bildet. Så lenge applikasjonen ikke stoppes, blir følgende prosessbildemetode påkalt for hver bilderamme i kameraet:
-(void)processImage:(cv::Mat &)image { cv::Mat gray; cvtColor(image, gray, CV_BGRA2GRAY); std::vector msers; [[MSERManager sharedInstance] detectRegions: gray intoVector: msers]; if (msers.size() == 0) { return; }; std::vector *bestMser = nil; double bestPoint = 10.0; std::for_each(msers.begin(), msers.end(), [&] (std::vector &mser) { MSERFeature *feature = [[MSERManager sharedInstance] extractFeature: &mser]; if(feature != nil) { if([[MLManager sharedInstance] isApeeScapeLogo: 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]; }
Denne metoden skaper i hovedsak en gråtonekopi av det originale bildet. Den identifiserer alle MSER-er og trekker ut relevante funksjoner, scorer hver MSER for likhet med malen og plukker den beste. Til slutt tegner den en grønn grense rundt den beste MSER og overlapper bildet med metainformasjon.
Nedenfor er definisjonene av noen viktige klasser og metodene deres i denne applikasjonen. Formålene deres er beskrevet i kommentarene.
/* 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
/* 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 &) vector; /* Extracts feature from the mser. For some MSERs feature can be NULL !!! */ - (MSERFeature *) extractFeature: (std::vector *) mser; @end
/* 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) isApeeScapeLogo: (MSERFeature *) feature; @end
Etter at alt er koblet sammen, med dette programmet, bør du kunne bruke kameraet på iOS-enheten din til å oppdage ApeeScapes logo fra forskjellige vinkler og retninger.
I denne artikkelen har vi vist hvor enkelt det er å oppdage enkle objekter fra et bilde ved hjelp av OpenCV. Hele koden er tilgjengelig på GitHub . Gaffel og send push-forespørsler, da bidrag er velkomne.
Som det gjelder for maskinlæringsproblemer, kan suksessgraden for logodeteksjonen i denne applikasjonen økes ved å bruke et annet sett med funksjoner og en annen metode for objektklassifisering. Imidlertid håper jeg at denne artikkelen vil hjelpe deg i gang med gjenkjenning av objekter ved hjelp av MSER og applikasjoner av datasynteknikker generelt.