Многие люди не желают, чтобы кто-то посторонний смог воспользоваться их телефоном. Для таких пользователей разработчики придумывают всё новые способы блокировки мобильных устройств. Сначала информация телефона защищалась ПИН-кодом, потом появился графический ключ, далее — сканер отпечатков пальцев, и наконец — разблокировка по лицу. Компания Xiaomi решила не отставать от нового стандарта и поэтому с обновлением прошивки добавила данную функцию на многие свои устройства, которые изначально её не поддерживали. Подробнее узнать о технологии можно будет в данном обзоре.
Главные отличия технологии Xiaomi от Apple
Несмотря на то, что впервые функция появилась в телефоне Samsung, популярность она приобрела именно благодаря Apple. Американский гигант сумел усовершенствовать механизм технологии, сделав его практически идеальным.
Так ли все хорошо в сканере лица от Xiaomi? Преподнесла ли китайская компания пользователю аналогичную опцию, стоящую в разы дешевле? Попытаемся разобраться.
Apple — Face ID
Помимо обычной фронтальной камеры, для распознавания лица понадобятся специальные датчики. Они обрабатывают около 30 тысяч точек на лице, в результате чего информация о владельце запоминается максимально точно.
Специальные нейроны проникают на определенную глубину, и за счет этого качество распознавания намного возрастает. Пользователь может отрастить бороду, надеть шапку и очки – и сканер обязательно его узнает. При недостатке освещения никаких проблем также не возникнет. Находясь в темной комнате или в сумерках, владелец может не волноваться и спокойно пользоваться своим телефоном.
Xiaomi — Face Unlock
Здесь, к сожалению, разблокировка по лицу имеет некоторые минусы. В качестве распознавателя задействована лишь селфи-камера. Ситуация чуть лучше с флагманом Mi 9 и Mi 8, где инфракрасные датчики присутствуют.
Если в кадр попадает достаточное количество света, а никаких изменений во внешности нет – Face Unlock сработает также хорошо, как и на iPhone. А вот растительность, головные уборы, очки и шарфы – уже помеха. В прошлых моделях Xiaomi разблокировка происходила и по фотографии, но в MIUI 11 и MIUI 10 этот недостаток успешно исправлен.
Небольшие выводы. Если вы не часто используете пароль в виде лица, а приобрести дорогой iPhone X нет возможности – присмотритесь к Mi 8. Весь базовый функционал Face ID вы получите без проблем. Нужна постоянная и точная разблокировка без малейшей ошибки? Тогда поможет лишь продукция от Apple.
Триангуляция Делоне для построения маски
Перейдем к практической части. Попробуем построить простейшую маску на лице по полученным landmarks. Ожидаемым результатом будет маска вида:
рис 6. Маска, визуализирующая алгоритм триангуляции Делоне
Триангуляция Делоне — триангуляция для множества точек S на плоскости, при которой для любого треугольника все точки из S за исключением точек, являющихся его вершинами, лежат вне окружности, описанной вокруг треугольника. Впервые описана в 1934 году советским математиком Борисом Делоне.
рис 7. Пример триангуляции Делоне. Из каждой точки порождается окружность, проходящая через две ближайшие в метрике Евклида
Модели Xiaomi с поддержкой разблокировки по лицу
Официально функция разблокировки с помощью лица присутствует лишь на определенных моделях. Чаще всего это либо флагманы, либо телефоны среднего ценового сегмента.
Речь идет именно о заводской поддержке, но никто не исключает кастомные прошивки. К тому же, с выходом новых версий Миюай функция может добавляться для некоторых телефонов.
А пока рассмотрим смартфоны, которые уже с завода имеют в себе фронтальную разблокировку:
- Mi Mix 3;
- Mi Mix 2/2S;
- Все модели Redmi 5;
- Вся серия Black Shark и Pocophone;
- Вся линейка Mi 8;
- Вся линейка Mi 9, Mi 10, Redmi K30 и Redmi K20;
- Redmi 6 и 6A, Redmi Note 6;
- Серия Android One;
- Redmi Note 7, Note 7 Pro, Redmi 7, Redmi 7A;
- Вся линейка CC9. В том числе CC9 Pro (Mi Note 10);
- Redmi Note 8, Redmi Note 8 Pro, Redmi 8, Redmi Note 8T, Redmi 8A и Redmi Note 9 Pro (Max).
Все остальные модели, не указанные в вышеприведенном списке, не имеют функции распознавания лиц. Если это не так — укажите свою модель в комментариях поправим список.
Кстати, первым телефоном Сяоми с Face ID должен был стать Mi Note 3. Увы, флагман так и не получил нужное программное обеспечение от производителей.
В каких регионах работает Face ID
К огромному сожалению, данная функция еще не представлена на территории Европы (частично есть в России). На данный момент она работает следующих странах:
- Индия;
- Индонезия;
- Гонконг;
- Тайвань;
- Малайзия;
- Сингапур;
- Частично Европа.
Как настроить разблокировку по лицу на Xiaomi
И, наконец, приступаем к самой практике. Активировать разблокировку по лицу очень просто. Я опишу подробную инструкцию включая переход на один из вышеперечисленных регионов с использованием Redmi 5+.
- Переходим в «Настройки», листаем немного в низ и нажимаем на «Расширенные настройки».
- Далее «Регион» и выбираем любой подходящий из списка, первым будет Индия, его и выбираем. Будьте готовы, что после выбора нового региона система автоматически изменит конфигурации некоторых приложений + добавит локальные (в моем случае загрузило 5+ приложений: Amazon, Mi Store, Netflix и другие).
- Теперь опускаемся до пункта «Система и устройство». Заходим в раздел «Блокировка и защита».
- На новой странице видим вкладки, отвечающие за добавление отпечатка пальца, блокировку экрана и т. д. Посередине располагается надпись «Добавление данных лица». Кликаем по ней.
Если же у вас не стоит альтернативная защита — система потребует ее добавить. Это может быть цифробуквенная маркировка, графический ключ или отпечаток.
После появляется предупреждение, что защита с помощью лица – не самый безопасный вариант. Соглашаемся, и начинается сканирование. Смотрите прямо во фронтальную камеру, чтобы в объектив попало все лицо. Позаботьтесь о достаточном количестве света. Когда снимок получится, внимательно проверьте его и нажмите на большую кнопку «Готово». Вот мы и включили распознавание лица на Xiaomi.
Практическая реализация алгоритма
Реализуем алгоритм триангуляции Делоне для нашего лица в камере.
Шаг 1. Внутри вы увидите обертку, которая принимает массив точек в двухмерном пространстве и возвращает массив треугольников.
public final class Triangle { public var vertex1: Vertex public var vertex2: Vertex public var vertex3: Vertex public init(vertex1: Vertex, vertex2: Vertex, vertex3: Vertex) { self.vertex1 = vertex1 self.vertex2 = vertex2 self.vertex3 = vertex3 } }
А vertex это wrapper для CGPoint, дополнительно содержащий номер конкретного landmark.
public final class Vertex { public let point: CGPoint // Идентификатор точки. От 0 до 67. Всего 68 значений для dlib. Либо 65 для vision public let identifier: Int public init(point: CGPoint, id: Int) { self.point = point self.identifier = id } }
Шаг 2. Перейдем к отрисовке полигонов на лице. Включаем камеру и показываем изображение с камеры на экране:
final class ViewController: UIViewController { private var session: AVCaptureSession? private let faceDetection = VNDetectFaceRectanglesRequest() private let faceLandmarks = VNDetectFaceLandmarksRequest() private let faceLandmarksDetectionRequest = VNSequenceRequestHandler() private let faceDetectionRequest = VNSequenceRequestHandler() private lazy var previewLayer: AVCaptureVideoPreviewLayer? = { guard let session = self.session else { return nil } var previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.videoGravity = .resizeAspectFill return previewLayer }() private lazy var triangleView: TriangleView = { TriangleView(frame: view.bounds) }() private var frontCamera: AVCaptureDevice? = { AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .front) }() override func viewDidLoad() { super.viewDidLoad() sessionPrepare() session?.startRunning() guard let previewLayer = previewLayer else { return } view.layer.addSublayer(previewLayer) view.insertSubview(triangleView, at: Int.max) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() previewLayer?.frame = view.frame } private func sessionPrepare() { session = AVCaptureSession() guard let session = session, let captureDevice = frontCamera else { return } do { let deviceInput = try AVCaptureDeviceInput(device: captureDevice) session.beginConfiguration() if session.canAddInput(deviceInput) { session.addInput(deviceInput) } let output = AVCaptureVideoDataOutput() output.videoSettings = [ String(kCVPixelBufferPixelFormatTypeKey): Int(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) ] output.alwaysDiscardsLateVideoFrames = true if session.canAddOutput(output) { session.addOutput(output) } session.commitConfiguration() let queue = DispatchQueue(label: «output.queue») output.setSampleBufferDelegate(self, queue: queue) print(«setup delegate») } catch { print(«can’t setup session») } } }
Шаг 3. Далее получаем кадры с камеры
рис 8. Пример полученного кадра с камеры
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } guard let attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate) as? [String: Any] else { return } let ciImage = CIImage(cvImageBuffer: pixelBuffer, options: attachments) // leftMirrored for front camera let ciImageWithOrientation = ciImage.oriented(forExifOrientation: Int32(UIImageOrientation.leftMirrored.rawValue)) detectFace(on: ciImageWithOrientation) } }
Шаг 4. Ищем лица на кадре
fileprivate func detectFace(on image: CIImage) { try? faceDetectionRequest.perform([faceDetection], on: image) if let results = faceDetection.results as? [VNFaceObservation] { if !results.isEmpty { faceLandmarks.inputFaceObservations = results detectLandmarks(on: image) } } }
Шаг 5. Ищем landmarks на лице
рис 9. Пример найденных landmarks на лице
private func detectLandmarks(on image: CIImage) { try? faceLandmarksDetectionRequest.perform([faceLandmarks], on: image) guard let landmarksResults = faceLandmarks.results as? [VNFaceObservation] else { return } for observation in landmarksResults { if let boundingBox = faceLandmarks.inputFaceObservations?.first?.boundingBox { let faceBoundingBox = boundingBox.scaled(to: UIScreen.main.bounds.size) var maparr = [Vertex]() for (index, element) in convertPointsForFace(observation.landmarks?.allPoints, faceBoundingBox).enumerated() { let point = CGPoint(x: (Double(UIScreen.main.bounds.size.width — element.point.x)), y: (Double(UIScreen.main.bounds.size.height — element.point.y))) maparr.append(Vertex(point: point, id: index)) } triangleView.recalculate(vertexes: maparr) } } } private func convertPointsForFace(_ landmark: VNFaceLandmarkRegion2D?, _ boundingBox: CGRect) -> [Vertex] { guard let points = landmark?.normalizedPoints else { return [] } let faceLandmarkPoints = points.map { (point: CGPoint) -> Vertex in let pointX = point.x * boundingBox.width + boundingBox.origin.x let pointY = point.y * boundingBox.height + boundingBox.origin.y return Vertex(point: CGPoint(x: Double(pointX), y: Double(pointY)), id: 0) } return faceLandmarkPoints }
Шаг 6. Далее поверх рисуем нашу маску. Берем полученные треугольники из алгоритма Делоне и рисуем в виде layers.
рис 10. Финальный результат — простейшая маска поверх лица
Полная реализация алгоритма триангуляции Делоне на Swift здесь.
И пара советов по оптимизации для искушенных. Рисовать новые layers каждый раз — дорогая операция. Постоянно вычислять координаты треугольников по алгоритму Делоне тоже дорого. Поэтому берем лицо в высоком разрешении и хорошем качестве, которое смотрит в камеру, и прогоняем один раз алгоритм триангуляции Делоне на этой фотографии. Полученные треугольники сохраняем в текстовый файл, а дальше используем эту треугольники и меняем у них координаты.