Objektdeteksjon i et opencv-bilde. OpenCV

I denne artikkelen vil du lære hvordan du lager et Python-skript for å telle antall bøker i et bilde ved hjelp av OpenCV.

Hva skal vi gjøre?

La oss ta en titt på bildet der vi skal se etter bøker:

Vi kan se at det er fire bøker i bildet, i tillegg til distraherende ting som et kaffekrus, en Starbucks-kopp, noen magneter og et godteri.

Målet vårt er å finne fire bøker i et bilde uten å identifisere noe annet objekt som en bok.

Hvilke bibliotek trenger vi?

For å skrive et system for å søke og oppdage bøker i bilder, vil vi bruke OpenCV for datasyn og bildebehandling. Vi må også installere NumPy for at OpenCV skal fungere riktig. Sørg for at du har disse bibliotekene installert!

Finne bøker i bilder ved hjelp av Python og OpenCV

Merk oversettelse Du vil kanskje legge merke til at kildekoden i artikkelen vår er forskjellig fra den opprinnelige koden. Forfatteren brukte sannsynligvis installasjon av de nødvendige bibliotekene gjennom repositories. Vi foreslår å bruke pip, som er mye enklere. For å unngå feil anbefaler vi å bruke versjonen av koden gitt i artikkelen vår.

Åpne fditt, lag en ny fil kalt find_books.py, og la oss komme i gang:

# -*- koding: utf-8 -*- # importer de nødvendige pakkene importer numpy som np import cv2 # last inn bildet, endre fargen til gråtoner og reduser skarpheten bildet = cv2.imread("example.jpg") grå = cv2. cvtColor(bilde, cv2.COLOR_BGR2GRAY) grå = cv2.GaussianBlur(grå, (3, 3), 0) cv2.imwrite("grå.jpg", grå)

La oss starte med å importere OpenCV-biblioteket. Lasting av et bilde fra disk håndteres av cv2.imread-funksjonen. Her laster vi det ganske enkelt fra disk og konverterer deretter fargespekteret fra RGB til gråtoner.

Vi gjør også bildet uskarpt for å redusere høyfrekvent støy og forbedre nøyaktigheten til applikasjonen vår. Etter å ha kjørt koden, skal bildet se slik ut:

Vi lastet inn bildet fra disken, konverterte det til gråtoner og gjorde det litt uskarpt.

La oss nå definere kantene (dvs. konturene) til objekter i bildet:

# kantdeteksjon edged = cv2.Canny(grå, 10, 250) cv2.imwrite("edged.jpg", edged)

Bildet vårt ser nå slik ut:

Vi fant konturene til objektene i bildene. Men som du kan se er noen av konturene ikke lukket - det er hull mellom konturene. For å fjerne hullene mellom de hvite pikslene i bildet, bruker vi "lukk"-operasjonen:

# opprett og bruk en lukkekjerne = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7)) closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel) cv2.imwrite("closed.jpg", lukket)

Nå er plassene i konturene stengt:

Det neste trinnet er å faktisk oppdage konturene til objekter i bildet. For å gjøre dette bruker vi funksjonen cv2.findContours:

# finn konturene i bildet og tell antall bøker cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) total = 0

La oss se på geometrien til boken.

Boken er et rektangel. Et rektangel har fire hjørner. Derfor, hvis vi undersøker omrisset og finner at det har fire hjørner, så kan vi anta at det er en bok og ikke et annet objekt i bildet.

For å sjekke om en sti er en bok eller ikke, må vi gå gjennom hver sti:

# sløyfe konturer for c i cnts: # tilnærmet (glatt) konturen peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0,02 * peri, True) # hvis konturen har 4 toppunkter, anta at det er bok hvis len(ca) == 4: cv2.drawContours(image, , -1, (0, 255, 0), 4) totalt += 1

For hver av konturene beregner vi omkretsen ved å bruke cv2.arcLength og tilnærmer (jevner) deretter konturen ved å bruke cv2.approxPolyDP .

Grunnen til at vi tilnærmer omrisset er at det kanskje ikke er et perfekt rektangel. På grunn av støyen og skyggene på bildet er sannsynligheten lav for at boken vil ha nøyaktig 4 hjørner. Ved å tilnærme konturen løser vi dette problemet.

Til slutt sjekker vi at konturen som tilnærmes faktisk har fire toppunkter. I så fall tegner vi en kontur rundt boken og øker deretter telleren for det totale antallet bøker.

La oss fullføre dette eksemplet ved å vise det resulterende bildet og antall bøker som er funnet:

# vis den resulterende bildeutskriften("Jeg fant (0) bøker i dette bildet." format(total) cv2.imwrite("output.jpg", bilde))

På dette stadiet vil bildet vårt se slik ut:

La oss oppsummere det

I denne artikkelen lærte du hvordan du finner bøker i bilder ved hjelp av enkel bildebehandling og datasynsteknikker ved hjelp av Python og OpenCV.

Vår tilnærming var å:

  1. Last inn et bilde fra disken og konverter det til gråtoner.
  2. Gjør bildet litt uskarpt.
  3. Bruk Canny edge-detektor for å oppdage objekter i bildet.
  4. Lukk eventuelle hull i konturene.
  5. Finn konturene til objektene i bildet.
  6. Bruk konturtilnærming for å finne ut om konturen var et rektangel og derfor en bok.

Du kan laste ned skriptkildekoden og bildet som brukes i denne artikkelen.

Et åpen kildekode datasyn og maskinlæringsbibliotek. Den inkluderer mer enn 2500 algoritmer, som inkluderer både klassiske og moderne algoritmer for datasyn og maskinlæring. Dette biblioteket har grensesnitt på forskjellige språk, inkludert Python (vi bruker det i denne artikkelen), Java, C++ og Matlab.

Installasjon

Installasjonsinstruksjoner på Windows kan sees, og på Linux -.

Importere og vise et bilde

import cv2 image = cv2.imread("./path/to/image.extension") cv2.imshow("Image", image) cv2.waitKey(0) cv2.destroyAllWindows()

Merk Når du leser med metoden ovenfor, er bildet i fargerommet ikke RGB (som alle er vant til), men BGR. Kanskje dette ikke er så viktig i begynnelsen, men så snart du begynner å jobbe med farger, er det verdt å vite om denne funksjonen. Det er 2 løsninger:

  1. Bytt 1. kanal (R - rød) med 3. kanal (B - blå), og så vil den røde fargen være (0,0,255) og ikke (255,0,0).
  2. Endre fargerom til RGB: rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    Og så i koden jobber du ikke lenger med image, men med rgb_image.

Merk For å lukke vinduet der bildet vises, trykk på en hvilken som helst tast. Hvis du bruker lukk vindu-knappen, kan du støte på fryser.

Gjennom hele artikkelen vil følgende kode bli brukt til å vise bilder:

Importer cv2 def viewImage(image, name_of_window): cv2.namedWindow(name_of_window, cv2.WINDOW_NORMAL) cv2.imshow(name_of_window, image) cv2.waitKey(0) cv2.destroyAllWindows()

Beskjæring

Doggie etter innramming

Import cv2 cropped = image viewImage(cropped, "Doggie after cropping")

Hvor bilde er bilde.

Endring av størrelse

Etter å ha endret størrelse med 20 %

Importer cv2 scale_percent = 20 # Prosentandel av original størrelse bredde = int(img.shape * scale_percent / 100) height = int(img.shape * scale_percent / 100) dim = (width, height) resize = cv2.resize(img, dim) , interpolation = cv2.INTER_AREA) viewImage(endret størrelse, "Etter størrelsesjustering med 20%")

Denne funksjonen tar hensyn til sideforholdet til originalbildet. Andre funksjoner for endring av bildestørrelse kan sees.

Sving

Doggie etter å ha snudd 180 grader

Importer cv2 (h, w, d) = image.shape center = (w // 2, h // 2) M = cv2.getRotationMatrix2D(center, 180, 1.0) rotated = cv2.warpAffine(image, M, (w) , h)) viewImage(rotert, "Doggie etter rotasjon 180 grader")

image.shape returnerer høyden, bredden og kanalene. M - rotasjonsmatrise - roterer bildet 180 grader rundt midten. -ve er rotasjonsvinkelen til bildet med klokken, og +ve, henholdsvis mot klokken.

Konvertering til gråtoner og svart-hvitt etter terskel

Doggie i gråtoner

Svart og hvit vovse

Importer cv2 gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ret, threshold_image = cv2.threshold(im, 127, 255, 0) viewImage(gray_image, "Doggie in greyscale") viewImage("threshold_image" )

gray_image er en enkanalsversjon av bildet.

Terskelfunksjonen returnerer et bilde der alle piksler som er mørkere (mindre enn) 127 erstattes med 0, og alle piksler som er lysere (større enn) 127 erstattes med 255.

For klarhetens skyld, et annet eksempel:

Ret, threshold = cv2.threshold(im, 150, 200, 10)

Her erstattes alt som er mørkere enn 150 med 10, og alt som er lysere erstattes med 200.

De resterende terskelfunksjonene er beskrevet.

Uskarphet/glatt

Uskarp vovse

Importer cv2 blurred = cv2.GaussianBlur(image, (51, 51), 0) viewImage(blurred, "Blurred Doggie")

GaussianBlur-funksjonen tar 3 parametere:

  1. Originalt bilde.
  2. En tuppel med 2 positive oddetall. Jo høyere tall, jo større utjevningskraft.
  3. sigmaX Og sigmaY. Hvis disse parameterne er lik 0, vil verdien deres beregnes automatisk.

Tegning av rektangler

Tegn et rektangel rundt hundens ansikt

Import cv2 output = image.copy() cv2.rectangle(output, (2600, 800), (4100, 2400), (0, 255, 255), 10) viewImage(output, "Tegn et rektangel rundt hundens ansikt" )

Denne funksjonen tar 5 parametere:

  1. Selve bildet.
  2. Koordinat for øvre venstre hjørne (x1, y1) .
  3. Koordinaten til nedre høyre hjørne (x2, y2) .
  4. Rektangelfarge (GBR/RGB avhengig av valgt fargemodell).
  5. Linjetykkelsen til rektangelet.

Å tegne linjer

2 hunder atskilt med en linje

Importer cv2 output = image.copy() cv2.line(output, (60, 20), (400, 200), (0, 0, 255), 5) viewImage(output, "2 hunder atskilt med en linje")

Linjefunksjonen tar 5 parametere:

  1. Selve bildet som streken er tegnet på.
  2. Koordinaten til det første punktet (x1, y1) .
  3. Koordinaten til det andre punktet (x2, y2) .
  4. Linjefarge (GBR/RGB avhengig av valgt fargemodell).
  5. Linjetykkelse.

Tekst på bilde

Bilde med tekst

Importer cv2 output = image.copy() cv2.putText(output, "Vi<3 Dogs", (1500, 3600),cv2.FONT_HERSHEY_SIMPLEX, 15, (30, 105, 210), 40) viewImage(output, "Изображение с текстом")

PutText-funksjonen tar 7 parametere:

  1. Direkte bilde.
  2. Tekst til bildet.
  3. Koordinaten nederst til venstre i begynnelsen av teksten (x, y).
  4. Personer oppdaget: 2

    Importer cv2 image_path = "./path/to/photo.extension" face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") image = cv2.imread(image_path) grå = cv2.cvtColor(image, cv2.COLOR_cas facescades) .detectMultiScale(grå, skalaFactor= 1.1, minNeighbors= 5, minSize=(10, 10)) faces_detected = "Ansikter oppdaget: " + format(len(ansikter)) print(ansikter_oppdaget) # Tegn firkanter rundt ansikter for (x, y , w, h) i ansikter: cv2.rectangle(image, (x, y), (x+w, y+h), (255, 255, 0), 2) viewImage(image, faces_detected)

    detectMultiScale er en generell funksjon for både ansikts- og objektgjenkjenning. For at funksjonen skal søke spesifikt etter ansikter, gir vi den den passende kaskaden.

    DetectMultiScale-funksjonen tar 4 parametere:

    1. Det behandlede bildet er i gråtoner.
    2. scaleFactor parameter. Noen ansikter kan være større enn andre fordi de er nærmere enn andre. Denne innstillingen kompenserer for perspektiv.
    3. Gjenkjenningsalgoritmen bruker et skyvevindu under gjenkjenning av objekter. MinNeighbors-parameteren bestemmer antall objekter rundt ansiktet. Det vil si at jo høyere verdien på denne parameteren er, jo flere lignende objekter trenger algoritmen for at den skal identifisere det gjeldende objektet som et ansikt. En verdi som er for liten vil øke antall falske positiver, mens en verdi som er for stor vil gjøre algoritmen mer krevende.
    4. minSize er den direkte størrelsen på disse områdene.

    Konturer - gjenkjenning av objekter

    Objektgjenkjenning utføres ved bruk av fargebildesegmentering. Det er to funksjoner for dette: cv2.findContours og cv2.drawContours.

    Dette papiret beskriver objektgjenkjenning ved hjelp av fargesegmentering. Alt du trenger for det er der.

    Lagrer et bilde

    import cv2 image = cv2.imread("./import/path.extension") cv2.imwrite("./export/path.extension", image)

    Konklusjon

    OpenCV er et utmerket bibliotek med lette algoritmer som kan brukes i 3D-gjengivelse, avansert bilde- og videoredigering, sporing og identifisering av objekter og personer i video, finne identiske bilder fra et sett og mye, mye mer.

    Dette biblioteket er veldig viktig for de som utvikler prosjekter relatert til maskinlæring innen bildefeltet.

Når du løser problemer med datasyn, kan du ikke klare deg uten å bruke spesialisert programvare. Jeg vil gjerne introdusere deg for dette - OpenCV - et åpen kildekodebibliotek i C++. Den har et sett med verktøy for digitalisering av bilder og påfølgende behandling gjennom numeriske algoritmer eller et nevralt nettverk.

Grunnleggende bildebehandlingsalgoritmer: bildetolkning, kamerakalibrering til en standard, eliminering av optiske forvrengninger, likhetsbestemmelse, objektbevegelsesanalyse, objektformbestemmelse og objektsporing, 3D-rekonstruksjon, objektsegmentering, gestgjenkjenning.

Du kan laste ned biblioteket på den offisielle nettsiden http://sourceforge.net/projects/opencvlibrary/

OpenCV bibliotekstruktur

cxcore - kjerne
* inneholder grunnleggende datastrukturer og algoritmer:
- grunnleggende operasjoner på flerdimensjonale numeriske arrays
- matrisealgebra, matematiske funksjoner, tilfeldige tallgeneratorer
- Skrive/gjenopprette datastrukturer til/fra XML
- grunnleggende 2D-grafikkfunksjoner

CV - bildebehandling og datasynsmodul
- grunnleggende operasjoner på bilder (filtrering, geometriske transformasjoner, fargeromstransformasjoner, etc.)
- bildeanalyse (utvalg av karakteristiske trekk, morfologi, søk etter konturer, histogrammer)
- bevegelsesanalyse, objektsporing
- gjenkjenning av gjenstander, spesielt ansikter
- Kamerakalibrering, elementer av romlig strukturrestaurering

Highgui - modul for input/output av bilder og videoer, skaper et brukergrensesnitt
- ta opp video fra kameraer og videofiler, les/skriv statiske bilder.
- funksjoner for å organisere et enkelt brukergrensesnitt (alle demoapplikasjoner bruker HighGUI)

Cvaux - eksperimentelle og eldre funksjoner
- mellomrom. visjon: stereokalibrering, selvkalibrering
- søk etter stereokorrespondanse, klikk i grafer
- finne og beskrive ansiktstrekk

CvCam - videoopptak
- lar deg ta opp video fra digitale videokameraer (støtte har blitt avviklet og denne modulen er ikke tilgjengelig i de nyeste versjonene)


Installerer OpenCV på Linux

Etter å ha lastet ned den nyeste versjonen av OpenCV fra utviklerens nettsted http://sourceforge.net/projects/opencvlibrary/, må du pakke ut arkivet og bygge med CMake versjon 2.6 eller høyere.

CMake-installasjon utføres som standard:

Sudo apt-get install cmake

For å vise OpenCV-vinduer må du installere GTK+ 2.x- og libgtk2.0-dev-bibliotekene

Apt-get install libgtk2.0-dev

Samling av biblioteket:

Tar -xjf OpenCV-2.2.0.tar.bz2 cd OpenCV-2.2.0 cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ./ make make install

For å teste det installerte biblioteket kan du samle eksempler og kjøre noe:

Cd samples/c/ chmod +x build_all.sh ./build_all.sh ./delaunay

Hvis du i stedet for testbildet ser feilen "feil under lasting av delte biblioteker: libopencv_core.so.2.2: kan ikke åpne delt objektfil: Ingen slik fil eller katalog", betyr dette at programmet ikke finner bibliotekene. Du må eksplisitt spesifisere banen til dem:

$ eksport LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Hvis feilen oppstår igjen etter dette:
OpenCV Error: Uspesifisert feil (Funksjonen er ikke implementert. Gjenoppbygg biblioteket med Windows, GTK+ 2.x eller Carbon-støtte. Hvis du er på Ubuntu eller Debian, installer libgtk2.0-dev og pkg-config, og kjør deretter cmake på nytt eller konfigurer skript) i cvNamedWindow, filen /usr/src/OpenCV-2.2.0/modules/highgui/src/window.cpp, linje 274 terminate kalt etter å ha kastet en forekomst av "cv::Exception" what(): /usr /src/OpenCV-2.2.0/modules/highgui/src/window.cpp:274: feil: (-2) Funksjonen er ikke implementert. Bygg opp biblioteket på nytt med Windows, GTK+ 2.x eller Carbon-støtte. Hvis du er på Ubuntu eller Debian, installer libgtk2.0-dev og pkg-config, og kjør deretter cmake på nytt eller konfigurer skriptet i funksjonen cvNamedWindow
Så du glemte å installere GTK+ 2.x: libgtk2.0-dev. Kjør installasjonen (se ovenfor).

Når installasjonen er fullført, vil overskriftsfilene være tilgjengelige i katalogen /usr/local/include/opencv, og bibliotekfilene vil være plassert i /usr/local/lib

La oss bygge programmet med OpenCV:

test.cpp

// // for testing // // robocraft.ru // #include #inkludere #inkludere #inkludere int main(int argc, char* argv) ( IplImage* image=0, *dst=0; // bildenavn char filnavn = "Image0.jpg"; // få bildebildet = cvLoadImage(filnavn, 1); printf ( "[i] bilde: %s\n", filnavn); assert(bilde != 0); // vis bildet cvNamedWindow("bilde"); cvShowImage("bilde", bilde); // vent på tasten som skal trykkes cvWaitKey( 0); // release resources cvReleaseImage(& image); cvReleaseImage(&dst); // slett windows cvDestroyAllWindows(); return 0; )

Makefile

CC:= g++ CFLAGS:= -I/usr/local/include/opencv -L/usr/local/lib OBJEKTER:= BIBLIOTEKTER:= -lopencv_core -lopencv_imgproc -lopencv_highgui .PHONY: alle renser alle: test test: $(CC ) $(CFLAGS) -o test test.cpp $(LIBRARIES) clean: rm -f *.o

Start byggingen med make-kommandoen.


Hei Verden!

OpenCV er installert og klar til bruk. La oss skrive vår første Hello World-applikasjon!

#inkludere #inkludere int main(int argc, char** argv) ( // angi høyden og bredden på bildet int høyde = 620; int width = 440; // angi punktet for visning av teksten CvPoint pt = cvPoint(height/4, width/2); // Lag et 8-bits, 3-kanals bilde IplImage* hw = cvCreateImage(cvSize(height, width), 8, 3); // fyll bildet med svart cvSet(hw, cvScalar(0, 0,0)); // fontinitialisering CvFont-font; cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA); // ved å bruke skriften viser vi tekst på bildet cvPutText(hw, "OpenCV Step By Step ", pt, &font, CV_RGB(150, 0, 150)); // lag et vindu cvNamedWindow("Hello World", 0); // vis bildet i det opprettede vinduet cvShowImage("Hello World", hw); // vent til tasten trykkes cvWaitKey(0); // release resources cvReleaseImage(&hw); cvDestroyWindow("Hello World"); return 0; )

Laster opp et bilde

Dette eksemplet vil være grunnlaget for alle dine OpenCV-programmer. Vi laster bildet inn i miljøet fra filen Image0.jpg

#inkludere #inkludere #inkludere #inkludere IplImage* image = 0; IplImage* src = 0; int main(int argc, char* argv) ( // navnet på bildet er spesifisert av den første parameteren char* filnavn = argc == 2 ? argv : "Image0.jpg"; // få bildebildet = cvLoadImage( filnavn,1); // klone bildet src = cvCloneImage(image); printf("[i] bilde: %s\n", filnavn); assert(src != 0); // vindu for visning av bildet cvNamedWindow ("original",CV_WINDOW_AUTOSIZE); / / vis bildet cvShowImage("original",image); // vis informasjon om bildet til konsollen printf("[i] kanaler: %d\n", image->nKanaler ); printf("[i] pikseldybde: % d bits\n", bilde->dybde); printf("[i] bredde: %d piksler\n", bilde->bredde); printf("[i] ] høyde: %d piksler\n", bilde- >høyde); printf("[i] bildestørrelse: %d bytes\n", bilde->bildestørrelse); printf("[i] breddetrinn: %d byte \n", image->widthStep); // vent til tasten trykkes cvWaitKey(0); // release resources cvReleaseImage(& image); cvReleaseImage(&src); // slett vinduet cvDestroyWindow("original") ; returner 0;)

Støttede bildeformattyper:

  • Windows punktgrafikk - BMP, DIB
  • JPEG-filer - JPEG, JPG, JPE
  • Bærbar nettverksgrafikk - PNG
  • Bærbart bildeformat - PBM, PGM, PPM
  • Solraster - SR, RAS
  • TIFF-filer - TIFF, TIF

For å få tilgang til et bilde kan du ringe følgende:

Bilde->nChannels // antall bildekanaler (RGB, men i OpenCV - BGR) (1-4) bilde->dybde // dybde i biter bilde->bredde // bildebredde i piksler bilde->høyde // bilde høyde i piksler bilde->bildeStørrelse // minne okkupert av bildet (==bilde->høyde*bilde->breddeTrinn) bilde->breddeTrinn // avstand mellom vertikalt tilstøtende bildepunkter (antall byte i én linje av bildet - kan være nødvendig for uavhengig kryssing av alle piksler i bildet)

Laster opp videoer

Å laste inn en video er ikke mye mer komplisert enn å laste opp et bilde, bortsett fra at det vil være en løkke som går gjennom rammene.
Forsinkelsen mellom bilder er satt til 33 millisekunder fordi Denne forsinkelsen gjør at videostrømmen kan behandles med en standard bildefrekvens på 30 bilder per sekund.

#inkludere #inkludere #inkludere #inkludere IplImage* ramme =0; int main(int argc, char* argv) ( // filnavnet er spesifisert av den første parameteren char* filnavn = argc == 2 ? argv : "test.avi"; printf("[i] fil: %s\ n", filnavn ); // vindu for å vise bildet cvNamedWindow("original",CV_WINDOW_AUTOSIZE); // få informasjon om videofilen CvCapture* capture = cvCreateFileCapture(filnavn); while(1)( // få neste bilde frame = cvQueryFrame(capture) ; if(!frame) ( break; ) // her kan du sette inn // en behandlingsprosedyre // vis rammen cvShowImage("original", frame); char c = cvWaitKey(33); if (c == 27) ( // hvis ESC trykkes, exit break; ) ) // frigjør ressurser cvReleaseCapture(&capture); // slett vinduet cvDestroyWindow("original"); return 0; )

For å ta opp video fra et kamera, må du endre koden litt - i stedet for cvCreateFileCapture()-funksjonen, vil cvCreateCameraCapture() bli brukt. Når du trykker på ESC vil avspillingen bli avbrutt og vinduet lukkes, og når du trykker Enter vil gjeldende ramme lagres som en jpg-fil.

#inkludere #inkludere #inkludere #inkludere int main(int argc, char* argv) ( // få et hvilket som helst tilkoblet kamera CvCapture* capture = cvCreateCameraCapture(CV_CAP_ANY); //cvCaptureFromCAM(0); assert(capture); //cvSetCaptureProperty(capture, CV_CAP_WIDTH/AME) /1280); //cvSetCaptureProperty(fangst, CV_CAP_PROP_FRAME_HEIGHT, 480);//960); // finn ut bredden og høyden på rammen dobbel bredde = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH); dobbel høyde = cvGetCaptureProperty(fangst, CV_CAP_PROP_FRAME_HEIGHT); printf("[i] %.0f x %.0f\n", bredde, høyde); IplImage* frame=0; cvNamedWindow("fangst", CV_WINDOW_AUTOSIZE); printf("[i] trykk Enter for å ta bilde og Esc for å avslutte!\n\n"); int teller=0; char filnavn; while(true)( // få frame frame = cvQueryFrame(capture); // show cvShowImage("capture", frame); char c = cvWaitKey(33); if (c == 27) ( // ESC er trykket break; ) else if(c == 13) ( // Skriv inn // lagre rammen til en fil sprintf(filnavn, "Image%d.jpg", teller); printf("[i] capture... %s \n", filnavn); cvSaveImage(filnavn, ramme); teller++; ) ) // frigjør ressurser cvReleaseCapture(&capture); cvDestroyWindow("fangst"); returner 0; )

OpenCV v1.0 viser og lagrer bilder med en minimumskameraoppløsning på 320x240.


Mønstergjenkjenning av objekter

For å gjenkjenne områder i kildebildet ved hjelp av en mal, er det cvMatchTemplate()-funksjonen. Funksjonen overlegger en bildemal på det gjeldende bildet og søker i henhold til den valgte algoritmen etter en korrelasjon mellom dem. Bestemmelse av grensene for det funnet mønsteret i kildebildet utføres av cvMinMaxLoc-funksjonen, og for å normalisere søkealgoritmen, cvNormalize().

// // eksempel cvMatchTemplate() // sammenligne et bilde med en mal // #include #inkludere #inkludere #inkludere IplImage* image = 0; IplImage* templ = 0; int main(int argc, char* argv) ( // navnet på bildet er spesifisert av den første parameteren char* filename = argc >= 2 ? argv : "Image0.jpg"; // få bildebildet = cvLoadImage( filnavn,1); printf( "[i] bilde: %s\n", filnavn); assert(bilde != 0); // mal char* filnavn2 = argc >= 3 ? argv : "øye.jpg"; printf("[i] mal: %s\n", filnavn2); templ = cvLoadImage(filnavn2,1); assert(templ != 0); cvNamedWindow("origianl", CV_WINDOW_AUTOSIZE); cvNamedWindow("mal", CV_WINDOW_AUTOSIZE ); cvNamedWindow("Match" , CV_WINDOW_AUTOSIZE); cvNamedWindow("res", CV_WINDOW_AUTOSIZE); // malstørrelse int width = templ->width; int height = templ->height; // original og mal cvShowImage("origianl" , bilde); cvShowImage(" mal", templ); // bilde for lagring av sammenligningsresultatet // resultatstørrelse: hvis bildet BxH og templ bxh, så resultat = (W-w+1)x(H-h+1 ) IplImage *res = cvCreateImage(cvSize ((image->width-templ->width+1), (image->height-templ->height+1)), IPL_DEPTH_32F, 1); // sammenlign bildet med mal cvMatchTemplate(bilde, templ, res, CV_TM_SQDIFF ); // vis hva vi fikk cvShowImage("res", res); // bestemme den beste posisjonen for sammenligning // (søker etter minimums- og maksimumsverdier i bildet) double minval, maxval; CvPoint minloc, maxloc; cvMinMaxLoc(res, &minval, &maxval, &minloc, &maxloc, 0); // normaliser cvNormalize(res,res,1,0,CV_MINMAX); cvNamedWindow("res norm", CV_WINDOW_AUTOSIZE); cvShowImage("res norm", res); // velg området med et rektangel cvRectangle(image, cvPoint(minloc.x, minloc.y), cvPoint(minloc.x+templ->width-1, minloc.y+templ->height-1), CV_RGB( 255, 0, 0), 1, 8); // vis bildet cvShowImage("Match", bilde); // vent til tasten trykkes cvWaitKey(0); // release resources cvReleaseImage(&image); cvReleaseImage(&templ); cvReleaseImage(&res); cvDestroyAllWindows(); returner 0; )

Hallo! Jeg sto overfor oppgaven med å implementere veiskiltgjenkjenning fra en videostrøm. Siden jeg aldri har vært borti problemer av denne typen før, forutsetter implementeringsprosessen naturligvis en lang foreløpig «røyking» av fora og nådeløs hån mot andres eksempler. Derfor bestemte jeg meg for å samle alt jeg leste på ett sted for fremtidige generasjoner, og i løpet av historien stille Habr noen spørsmål.

Preludier.

Så, etter å ha studert alle verktøyene som kan brukes til å implementere oppgaven, slo jeg meg på Microsoft Visual Studio© 2010-utviklingsmiljøet ved å bruke det fantastiske OpenCV-biblioteket.

Prosessen med å jobbe med OpenCV selv involverer foreløpige danser med en tamburin, som det er ganske detaljerte beskrivelser av:

Den andre akten med å danse med en tamburin.

Som et resultat vendte jeg meg mot treningskaskader. Etter å ha "røykt" i denne retningen, innså jeg at jeg trenger to verktøy: createsampes og haartraining. Men jeg hadde ikke eksen deres, og de nektet å kompilere. På den tiden hadde jeg OpenCV versjon 2.4.4, konfigurert med , og i artikkelen leste jeg først om bruk av Cmake under installasjonen. Til slutt bestemte jeg meg for å laste ned versjon 2.3.1 og installere biblioteket på nytt. Deretter klarte jeg å starte de nødvendige verktøyene via kommandolinjen og spørsmålet dukket opp om hvordan jeg skulle jobbe med dem. Alle i-ene er oversådd med artikler som viser parameterne du trenger for å kjøre createsampes og haartraining med en detaljert beskrivelse av disse parameterne.

Kode fra bunnen av.

Etter å ha forlatt den gamle metoden, ble koden skrevet om for å erstatte trente kaskader.

Kode 2.0

#include "stdafx.h" #include #inkludere #inkludere bruke navneområde cv; int main(int argc, char** argv) ( Matramme, grå; string object_cascade = "haarustupi.xml"; CascadeClassifier haar(object_cascade); VideoCapture cap(0); namedWindow("Video", 1); vektor gjenstander; while (true) (cap >> ramme; cvtColor(ramme, grå, CV_BGR2GRAY); haar.detectMultiScale(grå, objekter, 1.9, 10, 0, Størrelse(50, 50)); for (vektor ::const_iterator r = objekter.begin(); r != objekter.end(); r++) rektangel(ramme, r->tl(), r->br(), Skalar(0, 0, 255)); imshow("Video", ramme); if (waitKey(33) >= 0) break; ) retur (EXIT_SUCCESS); )

Vi legger opp miljøet på samme måte som i forrige prosjekt.

Repetisjon er læringens far.

Det eneste som gjenstår er å trene kaskadene.)
Det er her moroa begynner. Etter det bestemte jeg meg for å skrive om alle disse prøvelsene på Habr og be om råd.
Jeg forberedte 500 bilder som målte 1600x1200. og ett bilde med et skilt som måler 80x80. Ett bilde vil være nok fordi vi oppdager et spesifikt objekt og ikke et stort utvalg av ansikter.

Så, etter å ha forberedt bildene og opprettet neg.dat-filen med strukturen

Negativ/n (1).jpg negativ/n (2).jpg negativ/n (3).jpg negativ/n (4).jpg ... negativ/n (500).jpg

kjør filen opencv_createsamples.exe via CMD med følgende parametere

C:OpenCV2.3.1buildcommonx86opencv_createsamples.exe -vec C:OpenCV2.3.1buildcommonx86positive.vect -bg C:OpenCV2.3.1buildcommonx86neg.dat -img C:OpenCV2.3.1buildcommonx86positive.vect -bg C:OpenCV2.3.1buildcommonx86neg.dat -img C:OpenCV2.3.86buildcom0jpg -hpi0. gcolor 0 -bgthresh 0 -show

parameteren -show viser de opprettede positive bildene, men de, i motsetning til de som er angitt i andre artikler
bilder, det ser slik ut

liten

Det vil si at verktøyet beskjærer bg-bildet til størrelsen på det positive bildet. Å endre parameterne -w og -h gir ikke noe resultat og bakgrunnen er fortsatt nesten usynlig. Hvis noen vet hva som skjer her, del gjerne tankene dine.. Størrelsen på negative bilder ble redusert til 800x600 - samme resultat.

C:OpenCV2.3.1buildcommonx86opencv_haartraining.exe -data C:OpenCV2.3.1buildcommonx86haarustupi -vec C:OpenCV2.3.1buildcommonx86positive.vect -bg C:OpenCV2.3.1buildcommonx86haarustupi -vec C:OpenCV2.3.1buildcommonx86positive.vect -bg C:OpenCV2.3.1posnegcommons -0nnegcommons -0nnegcommons.dat 6 -ndeler 2 -v 20 -t 24 -mem 1536 -modus ALL -nonsym -minhitrate 0,999 -maxfalsealarm 0,5

deretter vil du motta den etterlengtede xml-filen, som kan lastes inn i programmets kildekode.
Som et resultat er kaskaden litt trent og, med et stort antall falske positiver, reagerer på bildet av vikeskiltet som jeg elsker.
Men jeg kan ikke oppnå nøyaktige resultater, virker det for meg, på grunn av det faktum at bakgrunnen i positive bilder er kuttet av. Og bildene blir bare ikke som i manualene. Men det er fortsatt et alternativ for å øke antall treningstrinn og, etter å ha lastet datamaskinen din for hele dagen, vente til kaskaden er mer "utdannet". Dette er hva jeg planlegger å gjøre til andre ideer kommer opp.

Epilog

Slik ble min første HelloHabr-artikkel. Jeg ser frem til dine kommentarer om stilen på presentasjonen av materialet. Og selvfølgelig råd om emnet.
Jeg håper etter rådene mottatt vil det være noe å fortsette historien på.

Vel, i utgangspunktet må du oppdage sirkler. Har du sett cvHoughCircles() ? Har du lov til å bruke denne?

Denne siden har god informasjon om hvordan du oppdager ting ved hjelp av OpenCV. Du kan være interessert i avsnitt 2.5.

Dette er en liten demo jeg nettopp skrev for å oppdage myntene på dette bildet. Håper du kan bruke noe av koden til din fordel.

Inngang :

Utganger :

// kompilert med: g++ circles.cpp -o circles `pkg-config --cflags --libs opencv` #include #inkludere #inkludere #inkludere int main(int argc, char** argv) ( IplImage* img = NULL; if ((img = cvLoadImage(argv))== 0) ( printf("cvLoadImage failed\n"); ) IplImage* grå = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1); CvMemStorage* storage = cvCreateMemStorage(0); cvCvtColor(img, grey, CV_BGR2GRAY); // Dette gjøres for å forhindre at mange falske sirkler blir oppdaget cvSmooth(grå, grå , CV_GAUSSIAN, 7, 7); IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1); IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8,0,0,0;cvC,0,0; 3); CvSeq*-sirkler = cvHoughCircles(grå, lagring, CV_HOUGH_GRADIENT, 1, grå->høyde/3, 250, 100); cvCvtColor(canny, rgbcanny, CV_GRAY2BGR); for (størrelse_t i = 0; i< circles->Total; i++) ( // runde flottørene til en int flyte* p = (float*)cvGetSeqElem(sirkler, i); cv::Point center(cvRound(p), cvRound(p)); int radius = cvRound(p) ; // tegn sirkelsenteret cvCircle(rgbcanny, center, 3, CV_RGB(0,255,0), -1, 8, 0); // tegn sirkelomrisset cvCircle(rgbcanny, center, radius+1, CV_RGB(0, 0.255), 2, 8, 0); printf("x: %d y: %d r: %d\n",center.x,center.y, radius); ) cvNamedWindow("sirkler", 1); cvShowImage("sirkler", rgbcanny); cvSaveImage("out.png", rgbcanny); cvWaitKey(0); returner 0; )

Sirkeldeteksjon er sterkt avhengig av parameterne til cvHoughCircles() . Vær oppmerksom på at jeg også brukte Canny i denne demoen.

Jeg må kode en objektdetektor (ball i dette tilfellet) ved hjelp av OpenCV. Problemet er at hvert google-søk gir meg noe med FACE DETECTION. Så jeg trenger hjelp til hvor jeg skal begynne, hva jeg skal bruke osv.

Litt informasjon:

  • Ballen har ikke en fast farge, den blir nok hvit, men den kan endre seg.
  • Jeg må bruke maskinlæring, trenger ikke være kompleks og robust, foreslår KNN (det er enklere og enklere).
  • Etter alt mitt leting fant jeg ut at det kan være nyttig å beregne et histogram av prøver bare for ballene og trene det med ML, men det viktigste her er at størrelsen på ballen kan og vil endre seg (nærmere og lenger fra kameraet) og Jeg aner ikke hvilken pass ML som skal klassifiseres for meg, jeg mener.. Jeg kan ikke (eller kan jeg?) bare sjekke hver piksel i bildet for alle mulige størrelser (fra si 5x5 til BxH) og håper å finne en positivt resultat.
  • Det kan være en ujevn bakgrunn, som mennesker, tøy bak ballen osv.
  • Som sagt må jeg bruke en ML-algoritme, som betyr ingen Haar- eller Viola-algoritmer.
  • Jeg tenkte også på å bruke konturer for å finne sirklene i Canny"ed-bildet, trenger bare å finne en måte å konvertere konturen til en datastreng for KNN-trening.

    Så... forslag?

    Takk på forhånd. ;)