1. введение
В этом уроке мы узнаем, как установить и использовать библиотеку компьютерного зрения OpenCV и применить ее для распознавания лиц в режиме реального времени.
2. Установка
Чтобы использовать библиотеку OpenCV в нашем проекте, нам нужно добавить зависимость opencv Maven в ваш pom.xml :
org.openpnp opencv 3.4.2-0
Для пользователей Gradle нам нужно будет добавить зависимость в наш файл build.gradle :
compile group: 'org.openpnp', name: 'opencv', version: '3.4.2-0'
После добавления библиотеки в наши зависимости мы можем использовать функции, предоставляемые OpenCV.
3. Использование библиотеки
Чтобы начать использовать OpenCV, нам нужно инициализировать библиотеку , что мы можем сделать в нашем методе main :
OpenCV.loadShared();
OpenCV – это класс, который содержит методы, связанные с загрузкой собственных пакетов , требуемых библиотекой OpenCV для различных платформ и архитектур.
Стоит отметить, что документация делает вещи немного по-другому:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME)
Оба этих вызова метода фактически загрузят необходимые собственные библиотеки.
Разница здесь в том, что последнее требует установки собственных библиотек . Первый, однако, может установить библиотеки во временную папку, если они недоступны на данной машине. Из-за этой разницы метод load Shared обычно является лучшим способом .
Теперь, когда мы инициализировали библиотеку, давайте посмотрим, что мы можем с ней сделать.
4. Загрузка изображений
Для начала давайте загрузим образец образа с диска с помощью OpenCV :
public static Mat loadImage(String imagePath) { Imgcodecs imageCodecs = new Imgcodecs(); return imageCodecs.imread(imagePath); }
Этот метод загрузит данное изображение в виде объекта Mat , который является матричным представлением.
Чтобы сохранить ранее загруженное изображение, мы можем использовать метод imwrite() класса Imgcodecs :
public static void saveImage(Mat imageMatrix, String targetPath) { Imgcodecs imgcodecs = new Imgcodecs(); imgcodecs.imwrite(targetPath, imageMatrix); }
5. Каскадный классификатор Хаара
Прежде чем погрузиться в распознавание лиц, давайте разберемся в основных концепциях, которые делают это возможным.
Проще говоря, классификатор-это программа, которая стремится поместить новое наблюдение в группу, зависящую от прошлого опыта. Каскадные классификаторы стремятся сделать это, используя объединение нескольких классификаторов. Каждый последующий классификатор использует выходные данные предыдущего в качестве дополнительной информации, значительно улучшая классификацию.
5.1. Особенности Haar
Распознавание лиц в OpenCV выполняется каскадными классификаторами на основе функций Haar.
Особенности Haar это фильтры, которые используются для обнаружения краев и линий на изображении. Фильтры отображаются в виде квадратов с черно – белыми цветами:
Эти фильтры применяются к изображению несколько раз, пиксель за пикселем, и результат собирается в виде одного значения. Это значение представляет собой разницу между суммой пикселей под черным квадратом и суммой пикселей под белым квадратом.
6. Распознавание лиц
Как правило, каскадный классификатор должен быть предварительно обучен, чтобы иметь возможность обнаруживать что-либо вообще.
Поскольку процесс обучения может быть длительным и потребует большого набора данных, мы собираемся использовать одну из предварительно обученных моделей, предлагаемых OpenCV . Мы поместим этот XML-файл в нашу папку resources для легкого доступа.
Давайте пройдем через процесс обнаружения лица:
Мы попытаемся определить лицо, обведя его красным прямоугольником.
Для начала нам нужно загрузить изображение в формате Mat из нашего исходного пути:
Mat loadedImage = loadImage(sourceImagePath);
Затем мы объявим объект MatOfRect для хранения найденных граней:
MatOfRect facesDetected = new MatOfRect();
Затем нам нужно инициализировать Каскадный классификатор , чтобы выполнить распознавание:
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() );
Выше параметр 1.1 обозначает масштабный коэффициент, который мы хотим использовать, указывая, насколько уменьшается размер изображения при каждом масштабе изображения. Следующий параметр, 3 , is minNeighbors. Это количество соседей, которое должен иметь прямоугольник-кандидат, чтобы сохранить его.
Наконец, мы пройдемся по граням и сохраним результат:
Rect[] facesArray = facesDetected.toArray(); for(Rect face : facesArray) { Imgproc.rectangle(loadedImage, face.tl(), face.br(), new Scalar(0, 0, 255), 3); } saveImage(loadedImage, targetImagePath);
Когда мы вводим исходное изображение, теперь мы должны получить выходное изображение со всеми гранями, отмеченными красным прямоугольником:
7. Доступ к камере С помощью OpenCV
До сих пор мы видели, как выполнять распознавание лиц на загруженных изображениях. Но большую часть времени мы хотим делать это в режиме реального времени. Чтобы сделать это, нам нужно получить доступ к камере.
Однако, чтобы иметь возможность показывать изображение с камеры, нам нужно несколько дополнительных вещей, помимо очевидного — камеры. Чтобы показать изображения, мы будем использовать JavaFX.
Поскольку мы будем использовать ImageView для отображения снимков, сделанных нашей камерой, нам нужен способ перевести OpenCV Mat в JavaFX Изображение :
public Image mat2Img(Mat mat) { MatOfByte bytes = new MatOfByte(); Imgcodecs.imencode("img", mat, bytes); InputStream inputStream = new ByteArrayInputStream(bytes.toArray()); return new Image(inputStream); }
Здесь мы преобразуем наш Mat в байты, а затем преобразуем байты в Изображение объект.
Мы начнем с потоковой передачи вида камеры на сцену JavaFX .
Теперь давайте инициализируем библиотеку с помощью метода load Shared :
OpenCV.loadShared();
Далее мы создадим сцену с Видеозахватом и ImageView для отображения изображения :
VideoCapture capture = new VideoCapture(0); ImageView imageView = new ImageView(); HBox hbox = new HBox(imageView); Scene scene = new Scene(hbox); stage.setScene(scene); stage.show();
Вот, 0 это идентификатор камеры, которую мы хотим использовать. Нам также нужно создать Таймер анимации для обработки настройки изображения:
new AnimationTimer() { @Override public void handle(long l) { imageView.setImage(getCapture()); } }.start();
Наконец, наш метод getCapture обрабатывает преобразование Mat в Изображение :
public Image getCapture() { Mat mat = new Mat(); capture.read(mat); return mat2Img(mat); }
Теперь приложение должно создать окно, а затем транслировать в прямом эфире вид с камеры на экран. Просмотр изображений окно.
8. Распознавание Лиц В Режиме Реального Времени
Наконец, мы можем соединить все точки, чтобы создать приложение, которое обнаруживает лицо в режиме реального времени.
Код из предыдущего раздела отвечает за захват изображения с камеры и отображение его пользователю. Теперь все, что нам нужно сделать, это обработать захваченные изображения, прежде чем показывать их на экране, используя наш класс CascadeClassifier .
Давайте просто изменим наши getCapture способ также выполнять распознавание лиц:
public Image getCaptureWithFaceDetection() { Mat mat = new Mat(); capture.read(mat); Mat haarClassifiedImg = detectFace(mat); return mat2Img(haarClassifiedImg); }
Теперь, если мы запустим наше приложение, лицо должно быть отмечено красным прямоугольником.
Мы также видим недостаток каскадных классификаторов. Если мы слишком сильно повернем лицо в любом направлении, красный прямоугольник исчезнет. Это связано с тем, что мы использовали специальный классификатор, который был обучен только для обнаружения передней части лица .
9. Резюме
В этом уроке мы узнали, как использовать OpenCV в Java.
Мы использовали предварительно обученный каскадный классификатор для обнаружения лиц на изображениях. С помощью JavaFX нам удалось заставить классификаторы обнаруживать лица в режиме реального времени с помощью изображений с камеры.
Как всегда, все примеры кода можно найти на GitHub .