Sử dụng YOLO hoặc các kỹ thuật nhận dạng hình ảnh khác để xác định tất cả văn bản chữ và số có trong hình ảnh


12

Tôi có nhiều sơ đồ hình ảnh, tất cả đều chứa nhãn dưới dạng ký tự chữ và số thay vì chỉ nhãn văn bản. Tôi muốn mô hình YOLO của mình xác định tất cả các số và ký tự chữ và số có trong nó.

Làm cách nào tôi có thể đào tạo mô hình YOLO của mình để làm điều tương tự. Các dữ liệu có thể được tìm thấy ở đây. https://drive.google.com/open?id=1iEkGcreFaBIJqUdAADDXJbUrSj99bvoi

Ví dụ: xem các hộp giới hạn. Tôi muốn YOLO phát hiện bất cứ nơi nào có văn bản. Tuy nhiên hiện tại không cần thiết phải xác định văn bản bên trong nó.

nhập mô tả hình ảnh ở đây

Cũng cần phải thực hiện tương tự cho các loại hình ảnh nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Các hình ảnh có thể được tải về ở đây

Đây là những gì tôi đã thử sử dụng opencv nhưng nó không hoạt động cho tất cả các hình ảnh trong bộ dữ liệu.

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

Có bất kỳ mô hình hoặc bất kỳ kỹ thuật opencv hoặc một số mô hình được đào tạo trước có thể làm điều tương tự cho tôi? Tôi chỉ cần các hộp giới hạn xung quanh tất cả các ký tự chữ và số có trong hình ảnh. Sau đó tôi cần xác định những gì hiện diện trong đó. Tuy nhiên, phần thứ hai hiện tại không quan trọng.


Điều này có trả lời câu hỏi của bạn không? Lỗi OpenCV! _Src.empty () trong hàm 'cvtColor'
Amit Yadav


điều đó không hiệu quả với tất cả các hình ảnh
Pulkit Bhatnagar

Câu trả lời:


7

Một cách tiếp cận khả thi là sử dụng trình phát hiện văn bản học sâu EAST (Văn bản cảnh chính xác và hiệu quả) dựa trên bài báo năm 2017 của Zhou và cộng sự, EAST: Trình phát hiện văn bản cảnh hiệu quả và chính xác . Mô hình ban đầu được đào tạo để phát hiện văn bản trong hình ảnh cảnh thiên nhiên nhưng có thể áp dụng nó trên hình ảnh sơ đồ. EAST khá mạnh mẽ và có khả năng phát hiện văn bản bị mờ hoặc phản chiếu. Đây là một phiên bản sửa đổi của việc thực hiện EAST của Adrian Rosebrock. Thay vì áp dụng trình phát hiện văn bản trực tiếp trên hình ảnh, chúng ta có thể cố gắng loại bỏ càng nhiều đối tượng không phải là văn bản trên ảnh trước khi thực hiện phát hiện văn bản. Ý tưởng là loại bỏ các đường ngang, đường dọc và đường viền phi văn bản (đường cong, đường chéo, hình tròn) trước khi áp dụng phát hiện. Đây là kết quả với một số hình ảnh của bạn:

Nhập ->các đường viền phi văn bản để xóa màu xanh lục

Kết quả

Hình ảnh khác

frozen_east_text_detection.pbMô hình được sàng lọc cần thiết để thực hiện phát hiện văn bản có thể được tìm thấy ở đây . Mặc dù mô hình bắt được hầu hết các văn bản, kết quả không chính xác 100% và đôi khi có kết quả dương tính giả có thể do cách nó được đào tạo trên hình ảnh cảnh thiên nhiên. Để có được kết quả chính xác hơn, có lẽ bạn sẽ phải huấn luyện mô hình tùy chỉnh của riêng mình. Nhưng nếu bạn muốn có một giải pháp vượt trội thì việc này sẽ hiệu quả với bạn. Kiểm tra bài đăng trên blog Phát hiện văn bản OpenCV (Trình phát hiện văn bản EAST) của Adrian để có giải thích toàn diện hơn về trình phát hiện văn bản 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()

Câu trả lời rất đầy đủ. Bao nhiêu giờ nỗ lực?
karlphillip

Khoảng một giờ và 30 phút nữa để viết nó lên
nathancy

Cho đến ngày nay tôi vẫn ngạc nhiên về số lượng người xuất hiện với những câu hỏi CV cực kỳ giống nhau trong vài ngày. Nó gần giống như những kẻ từ cùng một lớp xử lý hình ảnh đang tìm kiếm sự giúp đỡ để hoàn thành bài tập về nhà của họ hoặc chỉ tìm ai đó để làm bài tập về nhà cho họ. Đó là một "sự trùng hợp" thực sự kỳ quái.
karlphillip

2
@karlphillip Có lẽ câu hỏi này có vẻ quen thuộc vì OP đã đăng nó khoảng một tuần trước. Anh ấy rất muốn có câu trả lời CTRL + C, CTRL + V bao gồm tất cả các trường hợp của anh ấy ngay lập tức, vì vậy, tôi đoán bạn có thể gặp lại câu hỏi này trong vài tuần nữa!
eldesgraciado

3
@eldesgraciado Tôi mới nhận ra rằng OP đã đăng một câu hỏi tương tự vài tuần trước. Thậm chí không nhận ra đó là cùng một người cho đến bây giờ! Tôi cũng đã tự hỏi tại sao các câu hỏi có vẻ rất quen thuộc
nathancy

6

Để thuận tiện, tôi muốn thêm gói keras_ nob . Nó có thể dễ dàng được cài đặt với pip và dựa trên trình phát hiện văn bản CRAFT, mới hơn một chút so với trình phát hiện EAST nếu tôi không sai.

Bên cạnh phát hiện nó cũng đã thực hiện một số OCR! Các kết quả như được thấy dưới đây, xem đây là một giải pháp thay thế, có thể dễ thực hiện hơn là câu trả lời được chấp nhận.nhập mô tả hình ảnh ở đây


Chào người chiến thắng, nó có hoạt động với ít nhất 70% hình ảnh của tôi không?
Pulkit Bhatnagar

Bạn chưa bao gồm nhãn trong tập dữ liệu của bạn. Vì vậy, tôi thực sự không thể cho bạn biết bao nhiêu% hình ảnh nó hoạt động, nếu tôi không có cách nào để xác minh nếu nó hoạt động bằng cách so sánh nó với nhãn. Tuy nhiên, đó là gói pip, vì vậy nó đủ dễ để bạn chạy nó trên tập dữ liệu của mình và tự mình xem :)
Victor Sonck

4

Những gì bạn đang mô tả dường như là OCR (Nhận dạng ký tự quang học ). Một công cụ OCR mà tôi biết là tesseract , mặc dù cũng có công cụ này của IBM và các công cụ khác.

Vì YOLO ban đầu được đào tạo cho một nhiệm vụ rất khác, để sử dụng nó để bản địa hóa văn bản có thể sẽ cần phải đào tạo lại từ đầu. Người ta có thể cố gắng sử dụng các gói hiện có (phù hợp với cài đặt cụ thể của bạn) cho sự thật nền tảng (mặc dù đáng để nhớ rằng mô hình nói chung sẽ chỉ tốt nhất là sự thật nền tảng). Hoặc, có lẽ dễ dàng hơn, tạo dữ liệu tổng hợp để đào tạo (nghĩa là thêm văn bản vào các vị trí bạn chọn vào các bản vẽ hiện có sau đó đào tạo để bản địa hóa nó).

Ngoài ra, nếu tất cả các hình ảnh mục tiêu của bạn có cấu trúc tương tự như trên, người ta có thể cố gắng tạo sự thật nền tảng bằng cách sử dụng các heuristic CV cổ điển như bạn đã làm ở trên để phân tách / phân tách các ký hiệu, tiếp theo là phân loại bằng CNN được đào tạo trên MNIST hoặc tương tự để xác định nếu một blob nhất định có chứa một biểu tượng.

Đối với trường hợp bạn chọn tham gia YOLO - có các triển khai hiện có trong python, ví dụ: tôi đã có một số kinh nghiệm với cái này - nên khá đơn giản để thiết lập đào tạo với sự thật nền tảng của riêng bạn.

Cuối cùng, nếu sử dụng YOLO hoặc CNN, bản thân nó không phải là mục tiêu mà chỉ là giải pháp, bất kỳ "sự thật nền tảng" nào ở trên cũng có thể được sử dụng trực tiếp như một giải pháp và không phải để đào tạo một mô hình.

Hy vọng tôi hiểu chính xác câu hỏi của bạn


Nếu bạn có thể đưa ra mã giống nhau, vì câu hỏi này có chứa tiền thưởng
Pulkit Bhatnagar

Nhiệm vụ cuối cùng là lấy văn bản nhưng trước tiên tôi cố gắng xác định tất cả các ký tự chữ và số trong đó sau đó sử dụng OCR cho cùng một lần được xác định
Pulkit Bhatnagar

Không có gì tôi đề xuất thực sự là một giải pháp vượt trội, và mã thuật toán sẽ không ngắn hoặc đơn giản, vì vậy tôi sẽ để nó ở mức độ ý tưởng :-). cảm ơn vì đã nâng cấp!
Yuri Feldman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.