В Африке и некоторых частях мира некоторые предприятия по-прежнему хранят большие объемы своих данных в физических файлах, а не в цифровом формате. Это значительно препятствует прогрессу в этих компаниях, потому что ценная информация, которая может помочь им принимать прогрессивные решения, заперта в этих файлах.

Только представьте, какие инсайты будут раскрыты, если эти данные оцифровать и проанализировать. К счастью, именно этим мы и займемся в этой статье. Мы создадим веб-приложение, которое будет брать изображение, содержащее текст, а затем извлекать текст из изображения с помощью классной библиотеки под названием Pytessaract.

Настраивать

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

​
   # create env
   conda create --name textman
​
   # activate it
   conda activate textman
​

NB: для пользователей Windows обратитесь к этой статье, чтобы установить tesseract https://medium.com/quantrium-tech/installing-and-using-tesseract-4-on-windows-10-4f7930313f82

# on Ubuntu install tesseract first 
sudo apt install tesseract-ocr
sudo apt install libtesseract-dev
​
​
# and then install pytesseract
pip install pytesseract
pip install fastapi[all]
pip install opencv-python

Теперь давайте создадим каталог с именем textman и добавим следующие файлы и папки.

.
├── app.py
├── README.md
├── requirements.txt
├── templates
│   └── index.html
​

Создайте приложение

Давайте теперь добавим содержимое в файл app.py

from fastapi import FastAPI, Request, File, UploadFile
from starlette.requests import Request
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import numpy as np
import io
import cv2
import pytesseract
​
​
app = FastAPI()
templates = Jinja2Templates(directory="templates")
​
@app.get("/")
def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})
​
​
def read_img(img):
 text = pytesseract.image_to_string(img)
 return(text)
​
#  , file: bytes = File(...)
​
@app.post("/extract_text") 
async def extract_text(request: Request):
    label = ""
    if request.method == "POST":
        form = await request.form()
        # file = form["upload_file"].file
        contents = await form["upload_file"].read()
        image_stream = io.BytesIO(contents)
        image_stream.seek(0)
        file_bytes = np.asarray(bytearray(image_stream.read()), dtype=np.uint8)
        frame = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
        label =  read_img(frame)
       
        # return {"label": label}
   
    return templates.TemplateResponse("index.html", {"request": request, "label": label})
​
​

Во-первых, мы импортировали наши библиотеки, создали приложение и указали каталог нашего шаблона, чтобы FastAPI мог прочитать наш index.hml. Затем мы создали домашний маршрут, который отображает наш файл index.html. Мы также создали функцию (read_img()), которая принимает изображение и извлекает из него текст всего одной строкой кода. Круто, да? Я знаю! Наконец, мы создали почтовые маршруты, которые получают наш файл изображения из формы, которую мы создадим в файле index.html, а затем используем OpenCV для преобразования изображения в правильный формат для Pytesseract.

Наша разметка теперь будет выглядеть следующим образом:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300&display=swap"
      rel="stylesheet"
    />
    <link
      href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
      rel="stylesheet"
    />
    <title>Image To Text</title>
    <style>
      body {
        content: "By boadzie Daniel";
        margin: 0;
        min-height: 100vh;
        background-color: #ffffff;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80' width='80' height='80'%3E%3Cpath fill='%2335323a' fill-opacity='0.17' d='M14 16H9v-2h5V9.87a4 4 0 1 1 2 0V14h5v2h-5v15.95A10 10 0 0 0 23.66 27l-3.46-2 8.2-2.2-2.9 5a12 12 0 0 1-21 0l-2.89-5 8.2 2.2-3.47 2A10 10 0 0 0 14 31.95V16zm40 40h-5v-2h5v-4.13a4 4 0 1 1 2 0V54h5v2h-5v15.95A10 10 0 0 0 63.66 67l-3.47-2 8.2-2.2-2.88 5a12 12 0 0 1-21.02 0l-2.88-5 8.2 2.2-3.47 2A10 10 0 0 0 54 71.95V56zm-39 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm40-40a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM15 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm40 40a2 2 0 1 0 0-4 2 2 0 0 0 0 4z'%3E%3C/path%3E%3C/svg%3E");
        font-family: "Montserrat", sans-serif;
        font-weight: 700px;
        text-align: center;
        display: flex;
        align-items: center;
        justify-content: center;
      }
    </style>
  </head>
  <body>
    <section class="container text-gray-500 mx-auto px-4 py-4 flex flex-col">
      <div>
        <h3 class="text-6xl font-bold">Textman</h3>
        <p class="mt-2 italic text-2xl text-left lg:text-center font-semibold">
          Upload a picture and have the text extracted from it.
        </p>
      </div>
      <form method="post" action="/extract_text" enctype="multipart/form-data">
        <div
          class="flex w-full h-40 items-center justify-center bg-grey-lighter"
        >
          <label
            class="w-64 flex flex-col items-center px-4 py-4 bg-green-600 text-white rounded-lg shadow-lg tracking-wide uppercase border border-blue cursorpointer hover:bg-blue hover:text-white"
          >
            <svg
              class="w-8 h-8"
              fill="#fff"
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 20
20"
            >
              <path
                d="M16.88 9.1A4 4 0 0 1 16 17H5a5 5
0 0 1-1-9.9V7a3 3 0 0 1 4.52-2.59A4.98 4.98 0 0 1 17
8c0 .38-.04.74-.12 1.1zM11 11h3l-4-4-4 4h3v3h2v-3z"
              />
            </svg>
            <span class="mt-2 text-base leading-normal">Select a file</span>
            <input type="file" name="upload_file" class="hidden" />
          </label>
        </div>
        <div>
          <input
            class="text-center w-30 text-white bg-blue-500 hover:bg-blue-400 border-0 py-1 px-2 focus:outline-none hover:bg-red-600 rounded text-lg"
            type="submit"
            value="Extract text"
          />
        </div>
      </form>
      {% if label %}
      <div
        class="w-1/2 mr-auto ml-auto rounded-lg mt-4 bg-gray-600 text-white py-4 px-4"
      >
        <p class="text-lg">{{label}}</p>
      </div>
      {% endif %}
    </section>
  </body>
</html>
​

Мы используем Tailwindcss; крутая CSS-библиотека, ориентированная на утилиты, и мы также используем Heropatterns для классного фона.

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

Единственное, что нам осталось, это запустить наше приложение. Для этого добавьте следующее в app.py

# app.py 
# import uvicorn at the top of app.py
import uvicorn
​
# then add the following to the bottom of app.py
if __name__ == "__main__":
    uvicorn.run("app:app", host="127.0.0.1", port=8000, reload=True)

Наконец, запустите приложение с;

python app.py

Если все пойдет хорошо, вы должны увидеть следующее;

Всего за несколько строк кода мы создали потрясающий экстрактор текста. Как это круто? Код этого приложения доступен здесь.

Вывод

Машинное обучение имеет множество приложений для промышленности. Извлечение текста — лишь одно из преимуществ, которые могут изменить бизнес и упростить жизнь. Я надеюсь, что эта статья побудит вас попробовать эти крутые технологии и, возможно, изменить жизнь. Спасибо за чтение!