[Разработка под iOS, Разработка мобильных приложений, Swift] Распознание блоков текста в IOS-приложении с помощью Vision
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Работая над приложением, связанным с финансовыми операциями, возникла необходимость распознать и выделить суммы на чеках. Начиная с 13-ой версии в IOS-разработке появился нативный фреймворк Vision, который позволяет распознавать различные объекты на изображениях, без задействования сторонних сервисов.
В данной статье представлен личный опыт разработки приложения, использующего Vision. Что такое Vision
Из документации Apple: "Vision применяет алгоритмы "компьютерного зрения" для выполнения множества задач с входными изображениями и видео. Фреймворк Vision выполняет распознание лиц, обнаружение текста, распознавание штрих-кодов, регистрацию изображений. Vision также позволяет использовать пользовательские модели CoreML для таких задач, как классификация или обнаружение объектов."
Анализируя документацию Apple, можно предположить, что Vision - это один из этапов подготовки таких продуктов как Apple glasses или шлем смешанной реальности. Забегая вперед, следует подчеркнуть, что данный фреймворк потребляет изрядное количество ресурсов. Обработка статичного изображения может занимать десятки секунд, следовательно, работа с видео в реальном времени будет предельно ресурсоемким процессом, над оптимизацией которого инженерам Apple еще предстоит поработать.
В рамках поставленной задачи, необходимо было решить следующую проблему: распознание блоков текста с помощью Vision.РазработкаПроект построен на UIKit, который в данной статье детально рассматриваться не будет. Основное внимание уделяется блокам кода, связанным с фреймворком Vision. Приведенные листинги снабжены комментариями, позволяющими разработчикам детальнее понять принцип работы с фреймворком.
В MainViewController, который будет взаимодействовать с фреймворком Vision, нужно объявить две переменные:
//Recognition queue
let textRecognitionWorkQueue = DispatchQueue(label: "TextRecognitionQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem)
//Request for text recognition
var textRecognitionRequest: VNRecognizeTextRequest?
- Очередь для задач Vision не вызывает никаких затруднений у разработчиков. Именно в ней будут выполняться все задачи фреймворка.
- Объявляется переменная типа VNRecognizeTextRequet. Инициализируется объект из ViewDidLoad (или из init), так как он должен быть активен на протяжении всей жизни ViewController. Этот объект отвечает за работу с Vision, поэтому необходимо разобрать его инициализацию подробнее:
//Set textRecognitionRequest from ViewDidLoad
func setTextRequest() {
textRecognitionRequest = VNRecognizeTextRequest { request, error in
guard let observations = request.results as? [VNRecognizedTextObservation] else {
return
}
var detectedText = ""
self.textBlocks.removeAll()
for observation in observations {
guard let topCandidate = observation.topCandidates(1).first else { continue }
detectedText += "\(topCandidate.string)\n"
//Text block specific for this project
if let recognizedBlock = self.getRecognizedDoubleBlock(topCandidate: topCandidate.string, observationBox: observation.boundingBox) {
self.textBlocks.append(recognizedBlock)
}
}
DispatchQueue.main.async {
self.textView.text = detectedText
self.removeLoader()
self.drawRecognizedBlocks()
}
}
//Individual recognition request settings
textRecognitionRequest!.minimumTextHeight = 0.011 // Lower = better quality
textRecognitionRequest!.recognitionLevel = .accurate
}
Настройки объекта textRecognitionRequest. Описание всех доступных настроек можно найти в документации. Наиболее важным является параметр minimumTextHeight. Именно этот параметр отвечает за сочетание быстродействия и точности распознания текста. Для каждого проекта необходимо найти индивидуальное значение данного параметра, оно зависит от того, какие данные будет обрабатывать приложение.
Так как основной поставленной задачей являлось считывание текста с квитанций, для вычисления значения параметра minimumTextHeight в приложение были добавлены различные типы квитанций в различном состоянии (в том числе и основательно помятые). В результате тестирования было определено значение равное 0.011. В случае распознания текста с квитанций, это значение лучшим образом сочетает в себе быстродействие и точность. Однако нужно отметить, что текст с одного изображения распознается в среднем за пять секунд. Подобной скорости недостаточно для обработки информации в реальном времени и ее следует значительно оптимизировать инженерам Apple.
На основе представленного кода можно сделать вывод, что после операции распознания, объект типа VNRecognizeTextRequet получает блоки текста. Именно с ними и ведется дальнейшая работа, в зависимости от функций приложения. В рассматриваемом примере, каждый распознанный фрагмент текста был внесен в текстовое поле. Так как особенностью задействованного приложения является выделение суммы на квитанции, следовательно, сохранялись только блоки текста, которые можно преобразовать в тип Double. Помимо распознанного текстового значения сохраняются и координаты блока текста на изображении.
Представленный ниже метод отвечает за запуск работы запроса на распознание:
//Call text recognition request handler
func recognizeImage(cgImage: CGImage) {
textRecognitionWorkQueue.async {
let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
do {
try requestHandler.perform([self.textRecognitionRequest!])
} catch {
DispatchQueue.main.async {
self.removeLoader()
print(error)
}
}
}
}
В метод передается объект CGImage, в котором необходимо распознать текст. Вся работа по распознанию ведется в созданной для этого очереди. Создается объект VNImageRequestHandler, в который передается распознаваемый объект CGImage. В блоке do/try/catch запускается работа инициализированного объекта типа VNRecognizeTextRequet.
Описанные выше функции отвечают за распознание текста в приложении. Однако стоит еще остановится на методах, связанных с выделением нужных блоков текста.
func drawRecognizedBlocks() {
guard let image = invoiceImage?.image else { return }
//transform from documentation
let imageTransform = CGAffineTransform.identity.scaledBy(x: 1, y: -1).translatedBy(x: 0, y: -image.size.height).scaledBy(x: image.size.width, y: image.size.height)
//drawing rects on cgimage
UIGraphicsBeginImageContextWithOptions(image.size, false, 1.0)
let context = UIGraphicsGetCurrentContext()!
image.draw(in: CGRect(origin: .zero, size: image.size))
context.setStrokeColor(CGColor(srgbRed: 1, green: 0, blue: 0, alpha: 1))
context.setLineWidth(4)
for index in 0 ..< textBlocks.count {
let optimizedRect = textBlocks[index].recognizedRect.applying(imageTransform)
context.addRect(optimizedRect)
textBlocks[index].imageRect = optimizedRect
}
context.strokePath()
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
invoiceImage?.image = result
}
В данной статье рисование на изображении не рассматривается, так как при работе с разделом рисование у разработчиков не возникает никаких трудностей. При этом, стоит обратить внимание на особенности работы с координатами распознанных блоков текста. Для сохранения необходимых данных была использована следующая структура:
struct RecognizedTextBlock {
let doubleValue: Double
let recognizedRect: CGRect
var imageRect: CGRect = .zero
}
При распознании блоков текста фреймворк Vision вычисляет ряд важных параметров в объекте VNRecognizedTextObservation. Для нужд рассматриваемого проекта необходимо было получить только значение типа Double и его координаты на изображении, сохраняемые в константе recognizedRect.
Для выделения блока текста на изображении, следует применить трансформацию к координатам из константы recognizedRect. Полученные координаты так же сохраняются в объекте RecognizedTextBlock в переменной imageRect, необходимой для обработки нажатий на выделенные блоки текста.
После сохранения точных координат выделяемых блоков на изображении, обработку нажатий на выделенные области можно осуществить несколькими способами:
- Добавить необходимое количество невидимых кнопок на изображение, при помощи трансформации сохраненного объекта imageRect;
- При каждом нажатии на изображение проверять массив блоков текста и искать совпадение координат нажатия с сохраненным объектом imageRect и др.
Чтобы не перегружать ViewController дополнительными элементами, был использован второй способ.
//UIImageView tap listener
@objc func onImageViewTap(sender: UITapGestureRecognizer) {
guard let invoiceImage = invoiceImage, let image = invoiceImage.image else {
return
}
//get tap coordinates on image
let tapX = sender.location(in: invoiceImage).x
let tapY = sender.location(in: invoiceImage).y
let xRatio = image.size.width / invoiceImage.bounds.width
let yRatio = image.size.height / invoiceImage.bounds.height
let imageXPoint = tapX * xRatio
let imageYPoint = tapY * yRatio
//detecting if one of text blocks tapped
for block in textBlocks {
if block.imageRect.contains(CGPoint(x: imageXPoint, y: imageYPoint)) {
showTapAlert(doubleValue: block.doubleValue)
break
}
}
}
Использование представленного метода позволяет вычислить координаты нажатия на объект ImageView с сохранением его пропорций и поиска полученных координат в массиве сохранных распознанных блоков текста.ВыводыПредставленная статья позволяет разработчикам IOS-приложений ознакомиться с фреймворком Vision, прежде всего с его функцией распознания текста. Тестовое приложение, полученное в результате работы с распознанием текста в Vision, является ключом к пониманию работы с такими возможностями фреймворка как распознание лиц, текста, штрих-кодов и др.
Cкриншоты полученного приложения для распознавания цифровых значений на различных изображениях представлены ниже:
Приложение распознающее блоки текста с помощью VisionДля ознакомления проект можно скачать из репозитория.
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка мобильных приложений, Разработка под Android, Смартфоны] Пользователи начали жаловаться на проблемы с камерами Pixel
- [Программирование, C++, Работа с 3D-графикой, Разработка игр, CGI (графика)] Vulkan. Руководство разработчика. Swap chain (перевод)
- [Разработка веб-сайтов, Разработка мобильных приложений, Законодательство в IT] К 2023 году около 200 госуслуг в РФ переведут в электронный формат
- [Разработка под iOS, Разработка под Android, Монетизация мобильных приложений, Законодательство в IT, Игры и игровые приставки] Epic Games попыталась ограничить работу магазинов приложений в Северной Дакоте
- [Разработка мобильных приложений, Дизайн мобильных приложений, Управление продуктом, Изучение языков, Визуальное программирование] Запуск топ-приложения в одиночку, бесплатно и без кодинга (ну почти)
- [Разработка мобильных приложений, Разработка игр, Разработка под Android, Unity, Прототипирование] Опыт разработки первой мобильной игры на Unity или как полностью перевернуть свою жизнь
- [Информационная безопасность, Разработка под iOS, Серверное администрирование] Apple начала направлять трафик безопасного просмотра в Safari на свои серверы вместо Google
- [Информационная безопасность, Разработка мобильных приложений, IT-компании] ЦБ сообщил банкам о новом типе атаки на счета юридических лиц через мобильное приложение
- [Разработка мобильных приложений, Проектирование и рефакторинг, Разработка под Android, Kotlin] Разработка на Android: как найти подходящую абстракцию для работы со строками (перевод)
- [Разработка мобильных приложений, Dart, Flutter] 1 год с Flutter в продакшне (перевод)
Теги для поиска: #_razrabotka_pod_ios (Разработка под iOS), #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_swift, #_vision, #_frejmfork (фреймфорк), #_iosrazrabotka (ios-разработка), #_tutorial, #_urok (урок), #_raspoznavanie_teksta (распознавание текста), #_raspoznavanie_izobrazhenij (распознавание изображений), #_swift, #_mobilnye_prilozhenija (мобильные приложения), #_mobilnaja_razrabotka (мобильная разработка), #_razrabotka_pod_ios (
Разработка под iOS
), #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_swift
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:11
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Работая над приложением, связанным с финансовыми операциями, возникла необходимость распознать и выделить суммы на чеках. Начиная с 13-ой версии в IOS-разработке появился нативный фреймворк Vision, который позволяет распознавать различные объекты на изображениях, без задействования сторонних сервисов. В данной статье представлен личный опыт разработки приложения, использующего Vision. Что такое Vision Из документации Apple: "Vision применяет алгоритмы "компьютерного зрения" для выполнения множества задач с входными изображениями и видео. Фреймворк Vision выполняет распознание лиц, обнаружение текста, распознавание штрих-кодов, регистрацию изображений. Vision также позволяет использовать пользовательские модели CoreML для таких задач, как классификация или обнаружение объектов." Анализируя документацию Apple, можно предположить, что Vision - это один из этапов подготовки таких продуктов как Apple glasses или шлем смешанной реальности. Забегая вперед, следует подчеркнуть, что данный фреймворк потребляет изрядное количество ресурсов. Обработка статичного изображения может занимать десятки секунд, следовательно, работа с видео в реальном времени будет предельно ресурсоемким процессом, над оптимизацией которого инженерам Apple еще предстоит поработать. В рамках поставленной задачи, необходимо было решить следующую проблему: распознание блоков текста с помощью Vision.РазработкаПроект построен на UIKit, который в данной статье детально рассматриваться не будет. Основное внимание уделяется блокам кода, связанным с фреймворком Vision. Приведенные листинги снабжены комментариями, позволяющими разработчикам детальнее понять принцип работы с фреймворком. В MainViewController, который будет взаимодействовать с фреймворком Vision, нужно объявить две переменные: //Recognition queue
let textRecognitionWorkQueue = DispatchQueue(label: "TextRecognitionQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem) //Request for text recognition var textRecognitionRequest: VNRecognizeTextRequest?
//Set textRecognitionRequest from ViewDidLoad
func setTextRequest() { textRecognitionRequest = VNRecognizeTextRequest { request, error in guard let observations = request.results as? [VNRecognizedTextObservation] else { return } var detectedText = "" self.textBlocks.removeAll() for observation in observations { guard let topCandidate = observation.topCandidates(1).first else { continue } detectedText += "\(topCandidate.string)\n" //Text block specific for this project if let recognizedBlock = self.getRecognizedDoubleBlock(topCandidate: topCandidate.string, observationBox: observation.boundingBox) { self.textBlocks.append(recognizedBlock) } } DispatchQueue.main.async { self.textView.text = detectedText self.removeLoader() self.drawRecognizedBlocks() } } //Individual recognition request settings textRecognitionRequest!.minimumTextHeight = 0.011 // Lower = better quality textRecognitionRequest!.recognitionLevel = .accurate } Так как основной поставленной задачей являлось считывание текста с квитанций, для вычисления значения параметра minimumTextHeight в приложение были добавлены различные типы квитанций в различном состоянии (в том числе и основательно помятые). В результате тестирования было определено значение равное 0.011. В случае распознания текста с квитанций, это значение лучшим образом сочетает в себе быстродействие и точность. Однако нужно отметить, что текст с одного изображения распознается в среднем за пять секунд. Подобной скорости недостаточно для обработки информации в реальном времени и ее следует значительно оптимизировать инженерам Apple. На основе представленного кода можно сделать вывод, что после операции распознания, объект типа VNRecognizeTextRequet получает блоки текста. Именно с ними и ведется дальнейшая работа, в зависимости от функций приложения. В рассматриваемом примере, каждый распознанный фрагмент текста был внесен в текстовое поле. Так как особенностью задействованного приложения является выделение суммы на квитанции, следовательно, сохранялись только блоки текста, которые можно преобразовать в тип Double. Помимо распознанного текстового значения сохраняются и координаты блока текста на изображении. Представленный ниже метод отвечает за запуск работы запроса на распознание: //Call text recognition request handler
func recognizeImage(cgImage: CGImage) { textRecognitionWorkQueue.async { let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:]) do { try requestHandler.perform([self.textRecognitionRequest!]) } catch { DispatchQueue.main.async { self.removeLoader() print(error) } } } } Описанные выше функции отвечают за распознание текста в приложении. Однако стоит еще остановится на методах, связанных с выделением нужных блоков текста. func drawRecognizedBlocks() {
guard let image = invoiceImage?.image else { return } //transform from documentation let imageTransform = CGAffineTransform.identity.scaledBy(x: 1, y: -1).translatedBy(x: 0, y: -image.size.height).scaledBy(x: image.size.width, y: image.size.height) //drawing rects on cgimage UIGraphicsBeginImageContextWithOptions(image.size, false, 1.0) let context = UIGraphicsGetCurrentContext()! image.draw(in: CGRect(origin: .zero, size: image.size)) context.setStrokeColor(CGColor(srgbRed: 1, green: 0, blue: 0, alpha: 1)) context.setLineWidth(4) for index in 0 ..< textBlocks.count { let optimizedRect = textBlocks[index].recognizedRect.applying(imageTransform) context.addRect(optimizedRect) textBlocks[index].imageRect = optimizedRect } context.strokePath() let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() invoiceImage?.image = result } struct RecognizedTextBlock {
let doubleValue: Double let recognizedRect: CGRect var imageRect: CGRect = .zero } Для выделения блока текста на изображении, следует применить трансформацию к координатам из константы recognizedRect. Полученные координаты так же сохраняются в объекте RecognizedTextBlock в переменной imageRect, необходимой для обработки нажатий на выделенные блоки текста. После сохранения точных координат выделяемых блоков на изображении, обработку нажатий на выделенные области можно осуществить несколькими способами:
//UIImageView tap listener
@objc func onImageViewTap(sender: UITapGestureRecognizer) { guard let invoiceImage = invoiceImage, let image = invoiceImage.image else { return } //get tap coordinates on image let tapX = sender.location(in: invoiceImage).x let tapY = sender.location(in: invoiceImage).y let xRatio = image.size.width / invoiceImage.bounds.width let yRatio = image.size.height / invoiceImage.bounds.height let imageXPoint = tapX * xRatio let imageYPoint = tapY * yRatio //detecting if one of text blocks tapped for block in textBlocks { if block.imageRect.contains(CGPoint(x: imageXPoint, y: imageYPoint)) { showTapAlert(doubleValue: block.doubleValue) break } } } Cкриншоты полученного приложения для распознавания цифровых значений на различных изображениях представлены ниже: Приложение распознающее блоки текста с помощью VisionДля ознакомления проект можно скачать из репозитория. =========== Источник: habr.com =========== Похожие новости:
Разработка под iOS ), #_razrabotka_mobilnyh_prilozhenij ( Разработка мобильных приложений ), #_swift |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:11
Часовой пояс: UTC + 5