Làm sạch hình ảnh cho OCR


9

Tôi đã cố gắng xóa hình ảnh cho OCR: (các dòng)

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

Tôi cần phải loại bỏ những dòng này để đôi khi xử lý thêm hình ảnh và tôi đang đến khá gần nhưng rất nhiều thời gian ngưỡng lấy đi quá nhiều từ văn bản:

    copy = img.copy()
    blur = cv2.GaussianBlur(copy, (9,9), 0)
    thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,30)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    dilate = cv2.dilate(thresh, kernel, iterations=2)

    cnts = cv2.findContours(dilate, 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 > 300:
            x,y,w,h = cv2.boundingRect(c)
            cv2.rectangle(copy, (x, y), (x + w, y + h), (36,255,12), 3)

Chỉnh sửa: Ngoài ra, sử dụng số không đổi sẽ không hoạt động trong trường hợp phông chữ thay đổi. Có một cách chung để làm điều này?


2
Một số trong những dòng này, hoặc các đoạn của chúng, có các đặc điểm giống như văn bản pháp lý và sẽ khó thoát khỏi chúng mà không làm hỏng văn bản hợp lệ. Nếu điều này được áp dụng, bạn có thể tập trung vào sự thật rằng chúng dài hơn các ký tự và hơi bị cô lập. Vì vậy, bước đầu tiên có thể là ước tính kích thước và độ gần của các ký tự.
Yves Daoust

@YvesDaoust Làm thế nào một người sẽ đi tìm sự gần gũi của các nhân vật? (vì việc lọc hoàn toàn về kích thước bị lẫn lộn với các ký tự rất nhiều lần)
K41F4r

1
Bạn có thể tìm thấy, cho mỗi blob, khoảng cách đến hàng xóm gần nhất của nó. Sau đó, bằng cách phân tích biểu đồ khoảng cách, bạn sẽ tìm thấy một ngưỡng giữa "đóng" và "tách rời" (giống như chế độ phân phối) hoặc giữa "bao quanh" và "bị cô lập".
Yves Daoust

Trong trường hợp có nhiều dòng nhỏ gần nhau, hàng xóm gần nhất của họ có phải là dòng nhỏ khác không? Việc tính toán khoảng cách trung bình cho tất cả các đốm màu khác có quá tốn kém không?
K41F4r

"Không phải người hàng xóm gần nhất của họ sẽ là dòng nhỏ khác?": phản đối tốt, Danh dự của bạn. Trong thực tế, một loạt các phân đoạn ngắn gần không khác với văn bản hợp pháp, mặc dù trong một sự sắp xếp hoàn toàn không thể. Bạn có thể phải tập hợp lại các mảnh vỡ của dòng. Tôi không chắc chắn rằng khoảng cách trung bình cho tất cả sẽ giải cứu bạn.
Yves Daoust

Câu trả lời:


14

Đây là một ý tưởng. Chúng tôi chia vấn đề này thành nhiều bước:

  1. Xác định diện tích đường viền hình chữ nhật trung bình. Chúng tôi ngưỡng sau đó tìm đường viền và bộ lọc bằng cách sử dụng vùng hình chữ nhật giới hạn của đường viền. Lý do chúng tôi làm điều này là do quan sát rằng bất kỳ nhân vật điển hình nào sẽ chỉ quá lớn trong khi tiếng ồn lớn sẽ bao trùm một khu vực hình chữ nhật lớn hơn. Sau đó chúng tôi xác định diện tích trung bình.

  2. Loại bỏ các đường viền ngoại lệ lớn. Chúng tôi lặp lại qua các đường viền một lần nữa và loại bỏ các đường viền lớn nếu chúng 5xlớn hơn diện tích đường viền trung bình bằng cách điền vào đường viền. Thay vì sử dụng vùng ngưỡng cố định, chúng tôi sử dụng ngưỡng động này để mạnh mẽ hơn.

  3. Pha loãng với một hạt nhân dọc để kết nối các ký tự . Ý tưởng là tận dụng sự quan sát rằng các ký tự được căn chỉnh trong các cột. Bằng cách giãn nở với một hạt nhân dọc, chúng tôi kết nối văn bản lại với nhau để tiếng ồn sẽ không được bao gồm trong đường viền kết hợp này.

  4. Loại bỏ tiếng ồn nhỏ . Bây giờ văn bản cần giữ được kết nối, chúng tôi tìm các đường viền và loại bỏ bất kỳ đường viền nào nhỏ hơn 4xdiện tích đường viền trung bình.

  5. Bitwise - và để xây dựng lại hình ảnh . Vì chúng tôi chỉ có các đường viền mong muốn để giữ mặt nạ của chúng tôi, chúng tôi bit bit - và để giữ văn bản và nhận được kết quả của chúng tôi.


Đây là một hình dung của quá trình:

Chúng tôi ngưỡng của Otsu để có được hình ảnh nhị phân sau đó tìm các đường viền để xác định vùng đường viền hình chữ nhật trung bình. Từ đây, chúng tôi loại bỏ các đường viền ngoại lệ lớn được tô sáng bằng màu xanh lá cây bằng cách điền vào các đường viền

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

Tiếp theo chúng ta xây dựng một kernel dọcgiãn ra để kết nối các ký tự. Bước này kết nối tất cả các văn bản mong muốn để giữ và cách ly tiếng ồn thành các đốm màu riêng lẻ.

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

Bây giờ chúng tôi tìm đường viền và bộ lọc bằng cách sử dụng vùng đường viền để loại bỏ nhiễu nhỏ

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

Dưới đây là tất cả các hạt nhiễu được loại bỏ màu xanh lá cây

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

Kết quả

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

import cv2

# Load image, 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]

# Determine average contour area
average_area = [] 
cnts = cv2.findContours(thresh, 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 = w * h
    average_area.append(area)

average = sum(average_area) / len(average_area)

# Remove large lines if contour area is 5x bigger then average contour area
cnts = cv2.findContours(thresh, 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 = w * h
    if area > average * 5:  
        cv2.drawContours(thresh, [c], -1, (0,0,0), -1)

# Dilate with vertical kernel to connect characters
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)

# Remove small noise if contour area is smaller than 4x average
cnts = cv2.findContours(dilate, 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 < average * 4:
        cv2.drawContours(dilate, [c], -1, (0,0,0), -1)

# Bitwise mask with input image
result = cv2.bitwise_and(image, image, mask=dilate)
result[dilate==0] = (255,255,255)

cv2.imshow('result', result)
cv2.imshow('dilate', dilate)
cv2.imshow('thresh', thresh)
cv2.waitKey()

Lưu ý: Xử lý hình ảnh truyền thống bị giới hạn ở ngưỡng, hoạt động hình thái và lọc đường viền (xấp xỉ đường viền, diện tích, tỷ lệ khung hình hoặc phát hiện blob). Vì hình ảnh đầu vào có thể thay đổi dựa trên kích thước văn bản ký tự, nên việc tìm một giải pháp đơn lẻ là khá khó khăn. Bạn có thể muốn xem xét đào tạo phân loại của riêng bạn với máy / học sâu cho một giải pháp năng động.


1
Trong trường hợp phông chữ lớn hơn, điều này cũng sẽ xóa văn bản?
K41F4r

Có thể, vì vậy bạn sẽ phải điều chỉnh giá trị vùng ngưỡng. Đối với cách tiếp cận năng động hơn, một ý tưởng là xác định vùng ký tự trung bình, sau đó sử dụng đó làm ngưỡng
nathancy

Có vẻ như quá cụ thể với ví dụ, sử dụng diện tích trung bình vẫn sẽ xóa văn bản rất nhiều thời gian làm xấu đi kết quả cho OCR
K41F4r

Bạn có một hình ảnh đầu vào ví dụ khác mà bạn có thể thêm vào bài viết không?
nathancy

1
Tìm một giải pháp hoạt động trong mọi tình huống bằng các kỹ thuật xử lý ảnh truyền thống là khá khó khăn. Bạn có thể muốn xem xét đào tạo phân loại của riêng bạn bằng cách học sâu. Chúc may mắn!
nathancy
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.