Đây là một ý tưởng. Chúng tôi chia vấn đề này thành nhiều bước:
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.
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 5x
lớ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.
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.
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 4x
diện tích đường viền trung bình.
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
Tiếp theo chúng ta xây dựng một kernel dọc và giã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ẻ.
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ỏ
Dưới đây là tất cả các hạt nhiễu được loại bỏ màu xanh lá cây
Kết quả
Mã
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.