Распознавание OCR на основе нейронной сети

искусственный интеллект Нейронные сети

Оптическое распознавание символов (OCR) Оптическое распознавание, в просторечии, заключается в распознавании текста на картинке, такого как идентификационный номер, имя, адрес и т. д. на удостоверении личности, номер карты на банковской карте и т. д.

Evil

Github repo

EvilЯвляетсяiOSиmacOSПростая структура идентификации под платформой. поддержка черезCocoaPods,CarthageиSwift Package ManagerУстановить. Базовую модель распознавания можно легко перенести на другие платформы.

demo

Основной процесс распознавания OCR

  1. Захватите область, которую нужно выделить, из всего изображенияeg: 从一整张图片中截取身份证所在的矩形区域
  2. Захват текстовой областиeg: 通过一定的算法截取到身份证号码所在的区域
  3. Выполните серию предварительной обработки в текстовой области, чтобы облегчить следующую операцию.eg: 高斯模糊、膨胀等等
  4. Разделить текст, текстовая область разделена на единуюХарактер
  5. поставить синглДобавьте распознавание нейронной сети

Evilиспользовать последнююVisionрамки для достижения.первые 4 шагаApple предоставляет нам хороший системный метод, например:VNDetectTextRectanglesRequest. Так что здесь мы не обсуждаемпервые 4 шагаНекоторые детали реализации, если вы хотите узнать, как использовать API, вы можете увидетьздесь.

Как распознавать отдельные слова с помощью нейронных сетей

Я лично считаю, что с распознаванием небольшого количества печатного текста может справиться модель классификации изображений.Если у вас есть лучшее решение, добро пожаловать в общение. если выCNN调参侠Тогда следующий контент легко понять, но если вы не神经网络Соответствующие базовые знания, следующее содержание может быть немного неясным, потому что, в конце концов, я знаю только мех~. Если у вас раньше не было соответствующих знаний, вы можете узнать о том, что Apple предоставляет нам.Turi Create, вы можете не проектировать сеть самостоятельно.

0x00 Проектная сеть

Во-первых, нам нужно спроектировать сеть CNN для ввода нашего изображения одного слова и позволить ему распознать его.Поскольку наша задача распознавания очень проста, архитектура сети будет очень простой. Ниже приведеныKeras (2.0.6)Код:

model = Sequential()

model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Conv2D(128, (1, 1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

0x01 Сгенерировать обучающие данные

Мы знаем, что для обучения сети нам нужно много необработанных данных, так что, если у нас их нет? Некоторые учебные ресурсы можно найти в Интернете, но что, если мы хотим определить здесь идентификационный номер?

Конечно, это генерируется путем написания скриптов.Например, мы будем генерировать много-много身份证号码区域. Внесите некоторые случайные изменения, чтобы увеличить разнообразие данных.

o_image = Image.open(BACKGROUND)
    draw_brush = ImageDraw.Draw(o_image)

    font_size = random.randint(-5, 5) + 35
    draw_brush.text((10 + random.randint(-10, 10), 15 + random.randint(-2, 2)), LABELS,
                    fill='black',
                    font=ImageFont.truetype(FONT, font_size))

    o_image = ImageEnhance.Color(o_image).enhance(
        random.uniform(0.5, 1.5))  # 着色
    o_image = ImageEnhance.Brightness(o_image).enhance(
        random.uniform(0.5, 1.5))  # 亮度
    o_image = ImageEnhance.Contrast(o_image).enhance(
        random.uniform(0.5, 1.5))  # 对比度
    o_image = ImageEnhance.Sharpness(o_image).enhance(
        random.uniform(0.5, 1.5))  # 旋转
    o_image = o_image.rotate(random.randint(-2, 2))

    o_image.save(output + '/%d.png' % idx)

После того, как у вас есть текстовая область, вам нужно сегментировать текстовую область на отдельные слова, а затем обучить сеть.Поскольку следующая задача универсальна, я просто написал небольшой инструмент под названиемPrepareBot. Конкретный код находится вздесь, Вы можете пойти и посмотреть, если вы заинтересованы.

0x02 Обучить сеть

С данными, с моделью сети очень просто обучить сеть следующим образом:

model.fit_generator(generator=train_data_generator)

Хорошо, вот, давайте понаблюдаем за сходимостью и точностью распознавания сети.Если не очень плохо, то можно поставить вот этоmodelСохраните его и подготовьтесь к будущим задачам идентификации. Обратите внимание, что этот шаг генерируетKeras modelОн кроссплатформенный, то есть его можно использовать для идентификации в Windows, Linux и даже Android.

0x03 Преобразовать сеть

На предыдущих шагах мы создалиKerasсетевая модель, какEvilгде использовать эти модели? Сначала нам нужно использовать инструменты, предоставляемые Applecoremltools, преобразуйте модель keras вCoreModelКонкретное использование примерно следующее

# Prepare model for inference
for k in model.layers:
    if type(k) is keras.layers.Dropout:
        model.layers.remove(k)
        model.save("./temp.model")

core_ml_model = coremltools.converters.keras.convert("./temp.model",
                                                     input_names='image',
                                                     image_input_names='image',
                                                     output_names='output',
                                                     class_labels=list(labels),
                                                     image_scale=1 / 255.)

core_ml_model.author = 'gix.evil'
core_ml_model.license = 'MIT license'
core_ml_model.short_description = 'model to classify chinese IDCard numbers'

core_ml_model.input_description['image'] = 'Grayscale image of card number'
core_ml_model.output_description['output'] = 'Predicted digit'

core_ml_model.save('demo.mlmodel')

спастиdemo.mlmodelрезервное копирование файлов.

0x04 сеть импорта

У нас есть файл модели, как импортироватьEvilЧто с рамкой?

Перетащите прямо в xcode

Существенным недостатком этого метода является то, что он увеличит размер приложения, поэтому мы не рекомендуем использовать этот метод. Но на этот раз это всегда самый простой способ для вас во время нашей отладки.

Загрузка во время выполнения

Этот метод не влияет на размер приложения, но все также заметили, что файл модели нужно загружать во время выполнения, и сложность кода возрастет, но хорошая новость заключается в том, чтоEvilОчень дружеская поддержка для этого. Вам просто нужно сохранить файлы модели на вашем собственном сервере или CDN, а затемinfo.plistНастройте путь загрузки в файлеEvilВы можете автоматически настроить свою сетевую модель.

0x05 использовать сеть

Все готово, как им пользоваться? Просто выполните шаги 1-5, которые мы перечислили ранее, и вызовите их по очереди.EvilПредоставляемый интерфейс подойдет. Например

// 1. Используйте встроенную модель Evil для определения идентификационных номеров

lazy var evil = try? Evil(recognizer: .chineseIDCard)
let image: Recognizable = ....
let cardNumber = self.evil?.recognize(image)
print(cardNumber)

// 2. Используйте пользовательскую модель

let url: URL = ...
let evil = try? Evil(contentsOf: url, name: "demo")
let ciimage = CIImage(cvPixelBuffer: pixelBuffer).oriented(orientation)
            if let numbers = ciimage.preprocessor
                // 透视矫正
                .perspectiveCorrection(boundingBox: observation.boundingBox,
                                       topLeft: observation.topLeft,
                                       topRight: observation.topRight,
                                       bottomLeft: observation.bottomLeft,
                                       bottomRight: observation.bottomRight)
                .mapValue({Value($0.image.oriented(orientation), $0.bounds)})
                // 保证身份证头像朝上
                .correctionByFace()
                // 截取号码区域
                .cropChineseIDCardNumberArea()
                // 预处理 高斯模糊等
                .process()
                // 分割文字
                .divideText()
                // 简单校验
                .value?.map({ $0.image }), numbers.count == 18 {
                if let result = try? self.evil?.prediction(numbers) {
                    if let cardnumber = result?.flatMap({ $0 }).joined() {
                        DispatchQueue.main.async {
                            self.tipLabel.text = cardnumber
                        }
                    }
                }
            }

Суммировать

Хорошая, хорошая реклама здесь, приветствую всех, кто жалуется, добро пожаловатьstar fork, Добро пожаловать вpr, вы можете предоставить свои собственные обученные модели. Впервые пишу статью в Наггетс, спасибо за поддержку.