Використання YOLO або інших методів розпізнавання зображень для ідентифікації всього буквено-цифрового тексту, присутнього на зображеннях


12

У мене є діаграма декількох зображень, усі з яких містять мітки як буквено-цифрові символи, а не лише текстову мітку. Я хочу, щоб моя модель YOLO ідентифікувала всі числа та буквено-цифрові символи, присутні в ній.

Як я можу навчити свою модель YOLO робити те саме. Набір даних можна знайти тут. https://drive.google.com/open?id=1iEkGcreFaBIJqUdAADDXJbUrSj99bvoi

Наприклад: див. Обмежувальні поля. Я хочу, щоб YOLO виявив, де знаходиться текст. Однак наразі не потрібно ідентифікувати текст всередині нього.

введіть тут опис зображення

Те ж саме потрібно зробити і для цього типу зображень введіть тут опис зображення введіть тут опис зображення

Зображення можна завантажити тут

Це те, що я намагався використовувати opencv, але це не працює для всіх зображень у наборі даних.

import cv2
import numpy as np
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Users\HPO2KOR\AppData\Local\Tesseract-OCR\tesseract.exe"

image = cv2.imread(r'C:\Users\HPO2KOR\Desktop\Work\venv\Patent\PARTICULATE DETECTOR\PD4.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
clean = thresh.copy()

horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,30))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

cnts = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 100:
        cv2.drawContours(clean, [c], -1, 0, 3)
    elif area > 1000:
        cv2.drawContours(clean, [c], -1, 0, -1)
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    x,y,w,h = cv2.boundingRect(c)
    if len(approx) == 4:
        cv2.rectangle(clean, (x, y), (x + w, y + h), 0, -1)

open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
opening = cv2.morphologyEx(clean, cv2.MORPH_OPEN, open_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,2))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=4)
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = cv2.contourArea(c)
    if area > 500:
        ROI = image[y:y+h, x:x+w]
        ROI = cv2.GaussianBlur(ROI, (3,3), 0)
        data = pytesseract.image_to_string(ROI, lang='eng',config='--psm 6')
        if data.isalnum():
            cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
            print(data)

cv2.imwrite('image.png', image)
cv2.imwrite('clean.png', clean)
cv2.imwrite('close.png', close)
cv2.imwrite('opening.png', opening)
cv2.waitKey()

Чи є якась модель чи якась техніка opencv чи якась попередньо підготовлена ​​модель, яка може зробити те саме для мене? Мені просто потрібні обмежувальні поля навколо всіх буквено-цифрових символів, присутніх на зображеннях. Після цього мені потрібно визначити, що в ньому присутнє. Однак друга частина наразі не важлива.


Чи відповідає це на ваше запитання? OpenCV! _Src.empty () у помилці функції "cvtColor"
Аміт Ядав


це працює не для всіх зображень
Pulkit Bhatnagar,

Відповіді:


7

Можливий підхід - використовувати детектор тексту глибокого навчання EAST (Ефективний та точний сценарій тексту) на основі документа Zhou et al. У 2017 році, EAST: Ефективний та точний детектор тексту сцени . Спочатку модель була навчена виявляти текст у природних зображеннях сцени, але можливо застосувати його на зображеннях діаграм. EAST досить надійний і здатний виявляти розмитий або відбивний текст. Ось модифікована версія впровадження EAST Адріана Розберок. Замість того, щоб застосувати текстовий детектор безпосередньо до зображення, ми можемо спробувати видалити стільки нетекстових об’єктів на зображенні, перш ніж виконувати пошук тексту. Ідея полягає у видаленні горизонтальних ліній, вертикальних ліній та нетекстових контурів (криві, діагоналі, круглі фігури) перед застосуванням виявлення. Ось результати з вашими зображеннями:

Введіть ->нетекстові контури для видалення зеленим кольором

Результат

Інші зображення

Переглянуту frozen_east_text_detection.pbмодель, необхідну для виявлення тексту, можна знайти тут . Хоча модель ловить більшу частину тексту, результати не на 100% точні та мають випадкові помилкові позитиви, ймовірно, через те, як вона була навчена зображенням природних сцен. Для отримання більш точних результатів вам, мабуть, доведеться навчити власну власну модель. Але якщо ви хочете гідного нестандартного рішення, то це повинно вам працювати. Ознайомтеся з повідомленням у блозі Adrian's OpenCV Text Detection (EAST text detector) для отримання більш повного пояснення детектора тексту EAST.

Код

from imutils.object_detection import non_max_suppression
import numpy as np
import cv2

def EAST_text_detector(original, image, confidence=0.25):
    # Set the new width and height and determine the changed ratio
    (h, W) = image.shape[:2]
    (newW, newH) = (640, 640)
    rW = W / float(newW)
    rH = h / float(newH)

    # Resize the image and grab the new image dimensions
    image = cv2.resize(image, (newW, newH))
    (h, W) = image.shape[:2]

    # Define the two output layer names for the EAST detector model that
    # we are interested -- the first is the output probabilities and the
    # second can be used to derive the bounding box coordinates of text
    layerNames = [
        "feature_fusion/Conv_7/Sigmoid",
        "feature_fusion/concat_3"]

    net = cv2.dnn.readNet('frozen_east_text_detection.pb')

    # Construct a blob from the image and then perform a forward pass of
    # the model to obtain the two output layer sets
    blob = cv2.dnn.blobFromImage(image, 1.0, (W, h), (123.68, 116.78, 103.94), swapRB=True, crop=False)
    net.setInput(blob)
    (scores, geometry) = net.forward(layerNames)

    # Grab the number of rows and columns from the scores volume, then
    # initialize our set of bounding box rectangles and corresponding
    # confidence scores
    (numRows, numCols) = scores.shape[2:4]
    rects = []
    confidences = []

    # Loop over the number of rows
    for y in range(0, numRows):
        # Extract the scores (probabilities), followed by the geometrical
        # data used to derive potential bounding box coordinates that
        # surround text
        scoresData = scores[0, 0, y]
        xData0 = geometry[0, 0, y]
        xData1 = geometry[0, 1, y]
        xData2 = geometry[0, 2, y]
        xData3 = geometry[0, 3, y]
        anglesData = geometry[0, 4, y]

        # Loop over the number of columns
        for x in range(0, numCols):
            # If our score does not have sufficient probability, ignore it
            if scoresData[x] < confidence:
                continue

            # Compute the offset factor as our resulting feature maps will
            # be 4x smaller than the input image
            (offsetX, offsetY) = (x * 4.0, y * 4.0)

            # Extract the rotation angle for the prediction and then
            # compute the sin and cosine
            angle = anglesData[x]
            cos = np.cos(angle)
            sin = np.sin(angle)

            # Use the geometry volume to derive the width and height of
            # the bounding box
            h = xData0[x] + xData2[x]
            w = xData1[x] + xData3[x]

            # Compute both the starting and ending (x, y)-coordinates for
            # the text prediction bounding box
            endX = int(offsetX + (cos * xData1[x]) + (sin * xData2[x]))
            endY = int(offsetY - (sin * xData1[x]) + (cos * xData2[x]))
            startX = int(endX - w)
            startY = int(endY - h)

            # Add the bounding box coordinates and probability score to
            # our respective lists
            rects.append((startX, startY, endX, endY))
            confidences.append(scoresData[x])

    # Apply non-maxima suppression to suppress weak, overlapping bounding
    # boxes
    boxes = non_max_suppression(np.array(rects), probs=confidences)

    # Loop over the bounding boxes
    for (startX, startY, endX, endY) in boxes:
        # Scale the bounding box coordinates based on the respective
        # ratios
        startX = int(startX * rW)
        startY = int(startY * rH)
        endX = int(endX * rW)
        endY = int(endY * rH)

        # Draw the bounding box on the image
        cv2.rectangle(original, (startX, startY), (endX, endY), (36, 255, 12), 2)
    return original

# Convert to grayscale and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
clean = thresh.copy()

# Remove horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

# Remove vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,30))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(clean, [c], -1, 0, 3)

# Remove non-text contours (curves, diagonals, circlar shapes)
cnts = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area > 1500:
        cv2.drawContours(clean, [c], -1, 0, -1)
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    x,y,w,h = cv2.boundingRect(c)
    if len(approx) == 4:
        cv2.rectangle(clean, (x, y), (x + w, y + h), 0, -1)

# Bitwise-and with original image to remove contours
filtered = cv2.bitwise_and(image, image, mask=clean)
filtered[clean==0] = (255,255,255)

# Perform EAST text detection
result = EAST_text_detector(image, filtered)

cv2.imshow('filtered', filtered)
cv2.imshow('result', result)
cv2.waitKey()

Дуже повна відповідь. Скільки годин зусиль?
karlphillip

Близько години та ще 30 хвилин, щоб написати це
Натанці

До сьогоднішнього дня я все ще дивуюся кількості людей, які за кілька днів з’являються надзвичайно подібними питаннями з резюме. Це майже схоже на те, що хлопці з того ж класу обробки зображень шукають допомоги, щоб закінчити домашнє завдання або просто шукають когось, щоб зробити для них домашнє завдання. Це справді химерний «збіг».
karlphillip

2
@karlphillip Можливо, це питання виглядає знайомим, оскільки ОП опублікувало його близько тижня тому. Він дуже хоче відповідь CTRL + C, CTRL + V, яка висвітлює всі його випадки прямо з коробки, тому, я думаю, ви можете знову побачити це саме запитання через пару тижнів!
eldesgraciado

3
@eldesgraciado Я щойно зрозумів, що ОП розмістило подібне запитання кілька тижнів тому. Досі навіть не усвідомлював, що це та сама людина! Мені також було цікаво, чому питання виглядало дуже знайомо
Натанчі

6

Для зручності я хотів би додати пакет keras_ocr . Його можна легко встановити за допомогою pip, і базується на текстовому детекторі CRAFT, який трохи новіший, ніж детектор EAST, якщо я не помиляюся.

Поруч із виявленням це вже робить і деякий OCR! Результати, як показано нижче, бачать це як альтернативу, можливо, простішу у виконанні, ніж прийняту відповідь.введіть тут опис зображення


Привіт переможе, чи працює це принаймні на 70% моїх зображень?
Pulkit Bhatnagar

Ви не включили мітки у свій набір даних. Тому я не можу реально сказати, на скільки% зображень воно працює, якщо у мене немає способу перевірити, чи спрацювало воно, порівнявши його з міткою. Однак це пакет піп, тож він повинен бути досить легким, щоб запустити його на свій набір даних і переконатися самі:
Віктор Сонк,

4

Те, що ви описуєте, виглядає як OCR ( оптичне розпізнавання символів ). Один двигун OCR, про який я знаю, - це tesseract , хоча є і цей від IBM та інших.

Оскільки YOLO спочатку був навчений дуже іншим завданням, його використання для локалізації тексту, ймовірно, вимагатиме перекваліфікувати його з нуля. Можна спробувати використати існуючі пакети (адаптовані до вашої конкретної настройки) для основної істини (хоча варто пам’ятати, що модель, як правило, була б максимально такою ж доброю, як основна істина). Або, можливо, простіше, генеруйте синтетичні дані для тренувань (тобто додайте текст у вибрані вами позиції до існуючих малюнків, а потім тренуйтеся їх локалізувати).

Крім того, якщо всі ваші цільові зображення структуровані аналогічно вище, ви можете спробувати створити основну істину, використовуючи класичну евристику резюме, як ви робили вище, щоб розділити / сегментувати символи, після чого класифікувати за допомогою CNN, навченого на MNIST або подібного, щоб визначити якщо дана крапка містить символ.

У випадку, коли ви вирішили обрати YOLO - у python існують реалізовані варіанти, наприклад, я мав певний досвід роботи з цим - повинен бути досить простим, щоб налаштувати навчання з власною основою правди.

Нарешті, якщо використання YOLO або CNN не є ціллю само по собі, а скоріше лише рішенням, будь-яка з вищевказаних "основних правд" може бути використана безпосередньо як рішення, а не для навчання моделі.

Сподіваюся, я правильно зрозумів ваше запитання


Якщо ви можете дати той самий код, оскільки це питання містить щедрість
Pulkit Bhatnagar,

завдання полягає в тому, щоб в кінцевому підсумку отримати текст, але я спершу намагаюся ідентифікувати всі буквено-цифрові символи в ньому, потім використовую OCR для того ж ідентифікованого
Pulkit Bhatnagar,

Жодне із запропонованих мною справді не є справжнім рішенням, і алгоритмічний код не вважається коротким чи простим, я думаю, тому я залишу це на рівні ідей :-). ps дякую за підсумки!
Юрій Фельдман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.