Pengenalan OpenCV dengan Java

1. Pengenalan

Dalam tutorial ini, kita akan belajar cara memasang dan menggunakan perpustakaan penglihatan komputer OpenCV dan menerapkannya pada pengesanan wajah masa nyata.

2. Pemasangan

Untuk menggunakan perpustakaan OpenCV dalam projek kami, kami perlu menambahkan kebergantungan opencv Maven ke pom.xml kami :

 org.openpnp opencv 3.4.2-0 

Untuk pengguna Gradle, kami perlu menambahkan kebergantungan pada fail build.gradle kami :

compile group: 'org.openpnp', name: 'opencv', version: '3.4.2-0'

Setelah menambahkan perpustakaan ke pergantungan kami, kami dapat menggunakan ciri yang disediakan oleh OpenCV.

3. Menggunakan Perpustakaan

Untuk mula menggunakan OpenCV, kita perlu menginisialisasi perpustakaan , yang dapat kita lakukan dalam kaedah utama kita :

OpenCV.loadShared();

OpenCV adalah kelas yang menyimpan kaedah yang berkaitan dengan memuatkan pakej asli yang diperlukan oleh perpustakaan OpenCV untuk pelbagai platform dan seni bina.

Perlu diperhatikan bahawa dokumentasi melakukan perkara yang sedikit berbeza:

System.loadLibrary(Core.NATIVE_LIBRARY_NAME)

Kedua-dua kaedah panggilan tersebut sebenarnya akan memuatkan perpustakaan asli yang diperlukan.

Perbezaannya di sini ialah yang terakhir memerlukan perpustakaan asli dipasang . Akan tetapi, yang pertama dapat memasang perpustakaan ke folder sementara jika tidak tersedia pada mesin tertentu. Disebabkan perbezaan ini, yang loadShared kaedah biasanya cara terbaik untuk pergi .

Sekarang kita telah memulakan perpustakaan, mari kita lihat apa yang dapat kita lakukan dengannya.

4. Memuatkan Imej

Untuk memulakan, mari memuatkan contoh gambar dari cakera menggunakan OpenCV :

public static Mat loadImage(String imagePath) { Imgcodecs imageCodecs = new Imgcodecs(); return imageCodecs.imread(imagePath); }

Kaedah ini akan memuatkan gambar yang diberikan sebagai objek Mat , yang merupakan representasi matriks.

Untuk menyimpan imej yang dimuatkan sebelum ini, kita boleh menggunakan imwrite () kaedah yang Imgcodecs kelas:

public static void saveImage(Mat imageMatrix, String targetPath) { Imgcodecs imgcodecs = new Imgcodecs(); imgcodecs.imwrite(targetPath, imageMatrix); }

5. Pengelasan Haar Cascade

Sebelum menyelami pengecaman wajah, mari kita fahami konsep teras yang menjadikannya mungkin.

Ringkasnya, pengkelasan adalah program yang bertujuan untuk menempatkan pemerhatian baru ke dalam kumpulan yang bergantung pada pengalaman masa lalu. Pengelas cascading berusaha melakukan ini menggunakan gabungan beberapa pengklasifikasi. Setiap pengelasan berikutnya menggunakan output dari sebelumnya sebagai maklumat tambahan, meningkatkan klasifikasi dengan sangat baik.

5.1. Ciri-ciri Haar

Pengesanan wajah dalam OpenCV dilakukan oleh pengklasifikasi lata berasaskan ciri Haar.

Ciri Haar adalah penapis yang digunakan untuk mengesan tepi dan garis pada gambar. Penapis dilihat sebagai kotak dengan warna hitam dan putih:

Penapis ini diterapkan berkali-kali pada gambar, piksel demi piksel, dan hasilnya dikumpulkan sebagai satu nilai. Nilai ini adalah perbezaan antara jumlah piksel di bawah kotak hitam dan jumlah piksel di bawah kotak putih.

6. Pengesanan Muka

Secara amnya, pengklasifikasi kaskade perlu dilatih terlebih dahulu untuk dapat mengesan apa-apa.

Oleh kerana proses latihan boleh berlangsung lama dan memerlukan set data yang besar, kami akan menggunakan salah satu model pra-latihan yang ditawarkan oleh OpenCV. Kami akan meletakkan fail XML ini di folder sumber kami untuk akses mudah.

Mari ikuti proses mengesan wajah:

Kami akan berusaha mengesan wajah dengan menggariskannya dengan segiempat merah.

Untuk memulakan, kita perlu memuatkan gambar dalam format Mat dari jalan sumber kita:

Mat loadedImage = loadImage(sourceImagePath);

Kemudian, kami akan menyatakan objek MatOfRect untuk menyimpan wajah yang kami dapati:

MatOfRect facesDetected = new MatOfRect();

Seterusnya, kita perlu memulakan CascadeClassifier untuk melakukan pengiktirafan:

CascadeClassifier cascadeClassifier = new 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() );

Di atas, parameter 1.1 menunjukkan faktor skala yang ingin kita gunakan, menentukan berapa ukuran gambar dikurangkan pada setiap skala gambar. Parameter seterusnya, 3 , adalah minNeighbours. Ini adalah jumlah jiran yang seharusnya dimiliki oleh segi empat tepat calon untuk mengekalkannya.

Akhirnya, kita akan melihat muka dan menyimpan hasilnya:

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

Apabila kita memasukkan gambar sumber kita, kita sekarang harus menerima gambar output dengan semua wajah yang ditandai dengan segi empat merah:

7. Mengakses Kamera Menggunakan OpenCV

So far, we've seen how to perform face detection on loaded images. But most of the time, we want to do it in real-time. To be able to do that, we need to access the camera.

However, to be able to show an image from a camera, we need a few additional things, apart from the obvious — a camera. To show the images, we'll use JavaFX.

Since we'll be using an ImageView to display the pictures our camera has taken, we need a way to translate an OpenCV Mat to a JavaFX Image:

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

Here, we are converting our Mat into bytes, and then converting the bytes into an Image object.

We'll start by streaming the camera view to a JavaFX Stage.

Now, let's initialize the library using the loadShared method:

OpenCV.loadShared();

Next, we'll create the stage with a VideoCapture and an ImageView to display the Image:

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

Here, 0 is the ID of the camera we want to use. We also need to create an AnimationTimerto handle setting the image:

new AnimationTimer() { @Override public void handle(long l) { imageView.setImage(getCapture()); } }.start();

Finally, our getCapture method handles converting the Mat to an Image:

public Image getCapture() { Mat mat = new Mat(); capture.read(mat); return mat2Img(mat); }

The application should now create a window and then live-stream the view from the camera to the imageView window.

8. Real-Time Face Detection

Finally, we can connect all the dots to create an application that detects a face in real-time.

The code from the previous section is responsible for grabbing the image from the camera and displaying it to the user. Now, all we have to do is to process the grabbed images before showing them on screen by using our CascadeClassifier class.

Let's simply modify our getCapture method to also perform face detection:

public Image getCaptureWithFaceDetection() { Mat mat = new Mat(); capture.read(mat); Mat haarClassifiedImg = detectFace(mat); return mat2Img(haarClassifiedImg); }

Now, if we run our application, the face should be marked with the red rectangle.

We can also see a disadvantage of the cascade classifiers. If we turn our face too much in any direction, then the red rectangle disappears. This is because we've used a specific classifier that was trained only to detect the front of the face.

9. Ringkasan

Dalam tutorial ini, kami belajar bagaimana menggunakan OpenCV di Java.

Kami menggunakan pengklasifikasi lata yang telah dilatih untuk mengesan wajah pada gambar. Dengan bantuan JavaFX, kami berjaya membuat pengeluar mengesan wajah dalam masa nyata dengan gambar dari kamera.

Seperti biasa, semua contoh kod boleh didapati di GitHub.