Как мне удалить шум из этого порогового изображения в OpenCV? - PullRequest
1 голос
/ 14 апреля 2020

Я хотел бы удалить все, что не является частью букв и цифр на изображении. Входное изображение выглядит так:

thresholded image

Я пытался применить обнаружение неровных краев, но оно чувствительно к шуму, и контуры шума довольно большой. По этой причине морфологические операции также оказались безуспешными. Я попробовал cv2.MORPH_CLOSE, но шумовые зоны стали больше.

Мой код здесь, но на данный момент он абсолютно бесполезен при удалении шума:

import imutils

input=cv2.imread("n4.jpg")
resized = imutils.resize(input, width=700)
cv2.imshow("resized",resized)

blur = cv2.GaussianBlur(resized,(7,7),0)
cv2.imshow("blur",blur)

gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
threshINV  = cv2.threshold(gray, 140, 255, cv2.THRESH_BINARY_INV)[1]
cv2.imshow("thresh",threshINV)

e = cv2.Canny(threshINV,20,50)
cv2.imshow("e",e)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4,4))
close = cv2.morphologyEx(threshINV, cv2.MORPH_CLOSE, kernel)
cv2.imshow("close",close)


edged = cv2.Canny(gray, 20, 50)
dilat = cv2.dilate(edged, None, iterations=1)
cv2.imshow("test",dilat)
cv2.waitKey(0)
cv2.destroyAllWindows()

Я смотрел на этот пример и на этот другой пример , однако они не будут работать из-за размера шума и того факта, что контуры, которые я хотел бы сохранить, не имеют определенной формы.

Я также посмотрел на это method , но, опять же, я не думаю, что это сработает, поскольку нет общего контура для сглаживания.

1 Ответ

1 голос
/ 14 апреля 2020

Изображение, которое вы разместили, очень сложное.
Решение, которое я публикую, слишком специфично c для изображения, которое вы опубликовали.
Я пытался сделать его как можно более общим, но я не Не ожидайте, что он будет очень хорошо работать на других изображениях.
Вы можете использовать это для получения идей для большего количества вариантов для удаления шума.

Решение в основном основано на поиске подключенных компонентов и удалении более мелких компонентов, которые считаются шумом.

Я использовал pytesseract OCR для проверки того, достаточно ли чистый результат для OCR.

Вот код (пожалуйста, прочитайте комментарии):

import numpy as np
import scipy.signal
import cv2
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"  # For Windows OS

# Read input image
input = cv2.imread("n4.jpg")

# Convert to Grayscale.
gray = cv2.cvtColor(input, cv2.COLOR_BGR2GRAY)

# Convert to binary and invert polarity
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# Find connected components (clusters)
nlabel, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=8)


# Remove small clusters: With both width<=10 and height<=10 (clean small size noise).
for i in range(nlabel):
    if (stats[i, cv2.CC_STAT_WIDTH] <= 10) and (stats[i, cv2.CC_STAT_HEIGHT] <= 10):
        thresh[labels == i] = 0

#Use closing with very large horizontal kernel
mask = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((1, 150)))

# Find connected components (clusters) on mask
nlabel, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)

# Find label with maximum area
# https://stackoverflow.com/questions/47520487/how-to-use-python-opencv-to-find-largest-connected-component-in-a-single-channel
largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])

# Set to zero all clusters that are not the largest cluster.
thresh[labels != largest_label] = 0

# Use closing with horizontal kernel of 15 (connecting components of digits)
mask = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((1, 15)))

# Find connected components (clusters) on mask again
nlabel, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)

# Remove small clusters: With both width<=30 and height<=30
for i in range(nlabel):
    if (stats[i, cv2.CC_STAT_WIDTH] <= 30) and (stats[i, cv2.CC_STAT_HEIGHT] <= 30):
        thresh[labels == i] = 0

# Use closing with horizontal kernel of 15, this time on thresh
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((1, 15)))

# Use median filter with 3x5 mask (using OpenCV medianBlur with k=5 is removes important details).
thresh = scipy.signal.medfilt(thresh, (3,5))

# Inverse polarity
thresh = 255 - thresh

# Apply OCR
data = pytesseract.image_to_string(thresh, config="-c tessedit"
                                                  "_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-/"
                                                  " --psm 6"
                                                  " ")

print(data)

# Show image for testing
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

thresh (чистое изображение):
enter image description here

Результат распознавания: EXPO22016/01-2019

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...