Menggunakan YOLO atau teknik pengenalan gambar lainnya untuk mengidentifikasi semua teks alfanumerik yang ada dalam gambar

12

Saya memiliki beberapa diagram gambar, yang semuanya berisi label sebagai karakter alfanumerik, bukan hanya label teks itu sendiri. Saya ingin model YOLO saya mengidentifikasi semua angka & karakter alfanumerik yang ada di dalamnya.

Bagaimana saya bisa melatih model YOLO saya untuk melakukan hal yang sama. Dataset dapat ditemukan di sini. https://drive.google.com/open?id=1iEkGcreFaBIJqUdAADDXJbUrSj99bvoi

Misalnya: lihat kotak pembatas. Saya ingin YOLO mendeteksi di mana pun teks berada. Namun saat ini tidak perlu mengidentifikasi teks di dalamnya.

masukkan deskripsi gambar di sini

Juga hal yang sama perlu dilakukan untuk jenis gambar ini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Gambar dapat diunduh di sini

Ini adalah apa yang saya coba gunakan opencv tetapi tidak bekerja untuk semua gambar dalam dataset.

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()

Apakah ada model atau teknik operasi apa pun atau model pra-terlatih yang dapat melakukan hal yang sama untuk saya? Saya hanya perlu kotak pembatas di sekitar semua karakter alfanumerik yang ada dalam gambar. Setelah itu saya perlu mengidentifikasi apa yang ada di dalamnya. Namun bagian kedua tidak penting saat ini.

Pulkit Bhatnagar
sumber
Apakah ini menjawab pertanyaan Anda? OpenCV! _Src.empty () dalam fungsi 'cvtColor' error
Amit Yadav
itu tidak berfungsi untuk semua gambar
Pulkit Bhatnagar

Jawaban:

7

Sebuah pendekatan yang mungkin adalah dengan menggunakan pendeteksi teks pembelajaran yang dalam EAST (Efficient and Accurate Scene Text) berdasarkan makalah Zhou et al. 2017, EAST: Sebuah Detektor Teks Adegan yang Efisien dan Akurat . Model ini awalnya dilatih untuk mendeteksi teks dalam gambar pemandangan alam tetapi dimungkinkan untuk menerapkannya pada gambar diagram. EAST cukup kuat dan mampu mendeteksi teks yang kabur atau reflektif. Ini adalah versi modifikasi dari implementasi EAST dari Adrian Rosebrock. Alih-alih menerapkan detektor teks langsung pada gambar, kita dapat mencoba untuk menghapus objek non-teks pada gambar sebelum melakukan deteksi teks. Idenya adalah untuk menghapus garis horizontal, garis vertikal, dan kontur non-teks (kurva, diagonal, bentuk lingkaran) sebelum menerapkan deteksi. Inilah hasil dengan beberapa gambar Anda:

Masukkan ->kontur non-teks untuk dihapus berwarna hijau

Hasil

Gambar lainnya

Yang pra-pelatihan frozen_east_text_detection.pb yang diperlukan untuk melakukan deteksi teks dapat ditemukan di sini . Meskipun model menangkap sebagian besar teks, hasilnya tidak 100% akurat dan kadang-kadang positif palsu mungkin karena bagaimana ia dilatih pada gambar pemandangan alam. Untuk mendapatkan hasil yang lebih akurat, Anda mungkin harus melatih model khusus Anda sendiri. Tetapi jika Anda ingin solusi out-of-the-box yang layak maka ini akan bekerja untuk Anda. Lihat posting blog Deteksi Teks OpenCV Adrian (detektor teks EAST) untuk penjelasan yang lebih komprehensif tentang detektor teks EAST.

Kode

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()
nathancy
sumber
Jawabannya sangat lengkap. Berapa jam usaha?
karlphillip
Sekitar satu jam dan 30 menit untuk menuliskannya
nathancy
Sampai hari ini saya masih terkejut dengan jumlah orang yang muncul dengan pertanyaan CV yang sangat mirip dalam hitungan hari. Itu hampir terlihat seperti orang-orang dari kelas pemrosesan gambar yang sama mencari bantuan untuk menyelesaikan pekerjaan rumah mereka atau hanya mencari seseorang untuk mengerjakan pekerjaan rumah untuk mereka. Itu adalah "kebetulan" yang sangat aneh.
karlphillip
2
@karlphillip Mungkin pertanyaan ini terlihat familier karena OP mempostingnya sekitar seminggu yang lalu. Dia sangat menginginkan jawaban CTRL + C, CTRL + V yang mencakup semua kasingnya, jadi, saya kira Anda mungkin akan melihat pertanyaan yang sama lagi dalam beberapa minggu!
eldesgraciado
3
@eldesgraciado Saya baru menyadari bahwa OP memposting pertanyaan serupa beberapa minggu yang lalu. Bahkan tidak menyadari kalau itu adalah orang yang sama sampai sekarang! Saya juga bertanya-tanya mengapa pertanyaan itu tampak sangat akrab
nathancy
6

Demi kenyamanan saya ingin menambahkan paket keras_ocr . Ini dapat dengan mudah diinstal dengan pip, dan didasarkan pada detektor teks CRAFT, yang sedikit lebih baru daripada detektor EAST jika saya tidak salah.

Di samping deteksi itu sudah melakukan beberapa OCR juga! Hasilnya seperti yang terlihat di bawah, lihat ini sebagai alternatif, mungkin lebih mudah diterapkan, daripada jawaban yang diterima.masukkan deskripsi gambar di sini

Victor Sonck
sumber
Hai pemenang, apakah itu berfungsi untuk setidaknya 70% dari gambar saya?
Pulkit Bhatnagar
Anda belum memasukkan label ke dalam dataset Anda. Jadi saya tidak dapat benar-benar memberi tahu Anda berapa% dari gambar yang berfungsi, jika saya tidak memiliki cara untuk memverifikasi apakah itu berfungsi dengan membandingkannya dengan label. Namun, ini adalah paket pip, jadi seharusnya cukup mudah bagi Anda untuk menjalankannya pada dataset Anda dan lihat sendiri :)
Victor Sonck
4

Apa yang Anda gambarkan tampaknya OCR ( Pengenalan karakter optis ). Salah satu mesin OCR yang saya tahu adalah tesseract , meskipun ada juga yang ini dari IBM dan lainnya.

Karena YOLO pada awalnya dilatih untuk tugas yang sangat berbeda, untuk menggunakannya untuk melokalisasi teks kemungkinan akan perlu melatihnya dari awal. Seseorang dapat mencoba menggunakan paket yang ada (disesuaikan dengan pengaturan spesifik Anda) untuk kebenaran dasar (walaupun perlu diingat bahwa model tersebut umumnya hanya paling baik dan sesuai dengan kebenaran dasar). Atau, mungkin lebih mudah, menghasilkan data sintetis untuk pelatihan (yaitu menambahkan teks di posisi yang Anda pilih ke gambar yang ada kemudian melatih untuk melokalisasikannya).

Atau, jika semua gambar target Anda terstruktur mirip dengan yang di atas, orang dapat mencoba untuk membuat kebenaran tanah menggunakan heuristik CV klasik seperti yang Anda lakukan di atas untuk memisahkan / membagi simbol, diikuti dengan klasifikasi menggunakan CNN yang dilatih tentang MNIST atau serupa untuk menentukan jika gumpalan yang diberikan berisi simbol.

Untuk kasus Anda memilih YOLO - ada implementasi yang ada dalam python, misalnya saya punya pengalaman dengan ini - harus cukup mudah untuk mengatur pelatihan dengan kebenaran dasar Anda sendiri.

Akhirnya, jika menggunakan YOLO atau CNN bukan tujuan itu sendiri melainkan hanya solusinya, salah satu dari "kebenaran dasar" di atas dapat digunakan secara langsung sebagai solusi, dan bukan untuk melatih model.

Semoga saya mengerti pertanyaan Anda dengan benar

Yuri Feldman
sumber
Jika Anda dapat memberikan kode yang sama, karena pertanyaan ini berisi hadiah
Pulkit Bhatnagar
tugasnya adalah untuk mendapatkan teks tetapi saya pertama-tama mencoba mengidentifikasi semua karakter alfanumerik di dalamnya kemudian menggunakan OCR untuk hal yang sama yang diidentifikasi
Pulkit Bhatnagar
Tidak ada yang saya usulkan benar-benar solusi out-of-the-box, dan kode algoritmik tidak akan pendek atau sederhana saya pikir, jadi saya akan meninggalkannya di level ide :-). ps terima kasih atas upvote!
Yuri Feldman