Introduktion til OpenCV med Java

1. Introduktion

I denne vejledning vil vi lære at installere og bruge OpenCV-computersynsbiblioteket og anvende det til realtids ansigtsgenkendelse.

2. Installation

For at bruge OpenCV-biblioteket i vores projekt skal vi tilføje opencv Maven afhængighed af vores pom.xml:

 org.openpnp opencv 3.4.2-0 

For Gradle-brugere skal vi tilføje afhængigheden af ​​vores build.gradle fil:

kompilere gruppe: 'org.openpnp', navn: 'opencv', version: '3.4.2-0'

Efter at have tilføjet biblioteket til vores afhængigheder kan vi bruge de funktioner, der leveres af OpenCV.

3. Brug af biblioteket

For at begynde at bruge OpenCV, vi har brug for at initialisere biblioteket, som vi kan gøre i vores vigtigste metode:

OpenCV.loadShared ();

OpenCV er en klasse, der indeholder metoder relateret til indlæsning af native-pakker krævet af OpenCV-biblioteket til forskellige platforme og arkitekturer.

Det er værd at bemærke, at dokumentationen gør tingene lidt anderledes:

System.loadLibrary (Core.NATIVE_LIBRARY_NAME)

Begge disse metodeopkald vil faktisk indlæse de krævede oprindelige biblioteker.

Forskellen her er, at sidstnævnte kræver, at de oprindelige biblioteker installeres. Førstnævnte kan dog installere bibliotekerne i en midlertidig mappe, hvis de ikke er tilgængelige på en given maskine. På grund af denne forskel det loadShared metoden er normalt den bedste vej at gå.

Nu hvor vi har initialiseret biblioteket, skal vi se, hvad vi kan gøre med det.

4. Indlæser billeder

At begynde, lad os indlæse prøvebilledet fra disken ved hjælp af OpenCV:

offentlig statisk Mat loadImage (String imagePath) {Imgcodecs imageCodecs = nye Imgcodecs (); returner imageCodecs.imread (imagePath); }

Denne metode vil indlæse det givne billede som en Måtte objekt, som er en matrixrepræsentation.

For at gemme det tidligere indlæste billede kan vi bruge imwrite () metode til Imgcodecs klasse:

offentlig statisk tomrummet saveImage (Mat imageMatrix, String targetPath) {Imgcodecs imgcodecs = nye Imgcodecs (); imgcodecs.imwrite (targetPath, imageMatrix); }

5. Haar Cascade Classifier

Før vi dykker ned i ansigtsgenkendelse, lad os forstå de centrale begreber, der gør dette muligt.

Kort fortalt, en klassifikator er et program, der søger at placere en ny observation ind i en gruppe, der er afhængig af tidligere erfaringer. Cascading klassifikatorer søger at gøre dette ved hjælp af en sammenkædning af flere klassifikatorer. Hver efterfølgende klassifikator bruger output fra det foregående som yderligere information, hvilket forbedrer klassificeringen meget.

5.1. Haar Funktioner

Ansigtsgenkendelse i OpenCV udføres af Haar-funktionsbaserede kaskadeklassifikatorer.

Haar-funktioner er filtre, der bruges til at registrere kanter og linjer på billedet. Filtrene ses som firkanter med sorte og hvide farver:

Disse filtre anvendes flere gange på et billede, pixel for pixel, og resultatet indsamles som en enkelt værdi. Denne værdi er forskellen mellem summen af ​​pixels under den sorte firkant og summen af ​​pixels under den hvide firkant.

6. Ansigtsregistrering

Generelt, kaskadeklassifikatoren skal være foruddannet for overhovedet at kunne opdage noget.

Da træningsprocessen kan være lang og ville kræve et stort datasæt, vil vi bruge en af ​​de foruddannede modeller, der tilbydes af OpenCV. Vi placerer denne XML-fil i vores ressourcer mappe for nem adgang.

Lad os gå igennem processen med at opdage et ansigt:

Vi forsøger at opdage ansigtet ved at skitsere det med et rødt rektangel.

For at komme i gang skal vi indlæse billedet Måtte format fra vores kildesti:

Mat loadedImage = loadImage (sourceImagePath);

Derefter erklærer vi en MatOfRect modsætter sig at gemme de ansigter, vi finder:

MatOfRect facesDetected = ny MatOfRect ();

Dernæst skal vi initialisere CascadeClassifier at gøre anerkendelsen:

CascadeClassifier cascadeClassifier = ny CascadeClassifier (); int minFaceSize = Math.round (loadedImage.rows () * 0.1f); cascadeClassifier.load ("./ src / main / resources / haarcascades / haarcascade_frontalface_alt.xml"); cascadeClassifier.detectMultiScale (loadedImage, facesDetected, 1.1, 3, Objdetect.CASCADE_SCALE_IMAGE, new Size (minFaceSize, minFaceSize), new Size ());

Ovenstående angiver parameter 1.1 den skaleringsfaktor, vi vil bruge, idet det angives, hvor meget billedstørrelsen reduceres på hver billedskala. Den næste parameter, 3, er minNaboer. Dette er antallet af naboer, som et kandidatrektangel skal have for at bevare det.

Endelig løber vi gennem ansigterne og gemmer resultatet:

Rect [] facesArray = facesDetected.toArray (); for (Rect face: facesArray) {Imgproc.rectangle (loadedImage, face.tl (), face.br (), ny Scalar (0, 0, 255), 3); } saveImage (loadedImage, targetImagePath);

Når vi indtaster vores kildebillede, skal vi nu modtage outputbilledet med alle ansigter markeret med et rødt rektangel:

7. Adgang til kameraet ved hjælp af OpenCV

Indtil videre har vi set, hvordan man udfører ansigtsgenkendelse på indlæste billeder. Men det meste af tiden vil vi gøre det i realtid. For at være i stand til det skal vi have adgang til kameraet.

Men for at kunne vise et billede fra et kamera har vi brug for et par ekstra ting bortset fra det åbenlyse - et kamera. For at vise billederne bruger vi JavaFX.

Da vi bruger en ImageView for at vise de billeder, vores kamera har taget, har vi brug for en måde at oversæt en OpenCV Måtte til en JavaFX Billede:

public Image mat2Img (Mat mat) {MatOfByte bytes = new MatOfByte (); Imgcodecs.imencode ("img", mat, bytes); InputStream inputStream = ny ByteArrayInputStream (bytes.toArray ()); returner nyt billede (inputStream); }

Her konverterer vi vores Måtte til bytes og derefter konvertere bytes til et Billede objekt.

Vi starter med at streame kameravisningen til en JavaFX Scene.

Lad os nu initialisere biblioteket ved hjælp af loadShared metode:

OpenCV.loadShared ();

Derefter skal vi skabe scenen med en VideoCapture og en ImageView for at vise Billede:

VideoCapture capture = ny VideoCapture (0); ImageView imageView = nyt ImageView (); HBox hbox = ny HBox (imageView); Scene scene = ny scene (hbox); stage.setScene (scene); stage.show ();

Her, 0 er id'et på det kamera, vi vil bruge. Det har vi også brug for oprette en AnimationTimerat håndtere indstilling af billedet:

nyt AnimationTimer () {@Override offentligt ugyldigt håndtag (langt l) {imageView.setImage (getCapture ()); } }.Start();

Endelig vores getCapture metodehåndtag konvertere Måtte til en Billede:

offentligt billede getCapture () {Mat mat = new Mat (); capture.read (mat); retur mat2Img (mat); }

Applikationen skal nu oprette et vindue og derefter live-stream udsigten fra kameraet til imageView vindue.

8. Ansigtsregistrering i realtid

Endelig kan vi forbinde alle prikkerne for at oprette en applikation, der registrerer et ansigt i realtid.

Koden fra det foregående afsnit er ansvarlig for at få fat i billedet fra kameraet og vise det for brugeren. Nu er alt, hvad vi skal gøre, at behandle de gribede billeder, før vi viser dem på skærmen ved hjælp af vores CascadeClassifier klasse.

Lad os bare ændre vores getCapture metode til også at udføre ansigtsgenkendelse:

offentligt billede getCaptureWithFaceDetection () {Mat mat = new Mat (); capture.read (mat); Mat haarClassifiedImg = detectFace (mat); returnere mat2Img (haarClassifiedImg); }

Hvis vi kører vores applikation, skal ansigtet nu markeres med det røde rektangel.

Vi kan også se en ulempe ved kaskadeklassifikatorerne. Hvis vi vender ansigtet for meget i nogen retning, forsvinder det røde rektangel. Dette er fordi Vi har brugt en bestemt klassifikator, der kun blev trænet til at opdage forsiden af ​​ansigtet.

9. Resume

I denne vejledning lærte vi, hvordan man bruger OpenCV i Java.

Vi brugte en foruddannet kaskadeklassifikator til at opdage ansigter på billederne. Ved hjælp af JavaFX lykkedes det os at få klassifikatorerne til at registrere ansigterne i realtid med billeder fra et kamera.

Som altid kan alle kodeeksempler findes på GitHub.