İşte bir fikir. Bu sorunu birkaç adıma ayırıyoruz:
Ortalama dikdörtgen kontur alanını belirleyin. Daha sonra konturları buluruz ve konturun sınırlayıcı dikdörtgen alanını kullanarak filtreleriz . Bunu yapmamızın nedeni, tipik bir karakterin sadece o kadar büyük olacağı, büyük gürültü ise daha büyük bir dikdörtgen alana yayılacağı gözlemidir. Daha sonra ortalama alanı belirleriz.
Büyük aykırı konturları çıkarın. Konturları tekrar tekrarlıyoruz ve 5x
konturu doldurarak ortalama kontur alanından daha büyükse büyük konturları çıkarıyoruz. Sabit bir eşik alanı kullanmak yerine, daha fazla sağlamlık için bu dinamik eşiği kullanıyoruz.
Karakterleri bağlamak için dikey bir çekirdekle genişletin . Fikir, karakterlerin sütunlar halinde hizalandığı gözleminden yararlanmaktır. Dikey bir çekirdekle dilatasyon yaparak metni birleştiririz, böylece gürültü bu kombine konturda yer almaz.
Küçük gürültüyü giderin . Saklanacak metin bağlandığına göre, konturları buluyoruz ve 4x
ortalama kontur alanından daha küçük konturları kaldırıyoruz .
Bitsel ve görüntüyü yeniden oluşturmak için . Sadece maskemizi korumak için konturlar istediğimizden, bitsel olarak ve metni korumak ve sonucumuzu almak için.
İşte sürecin bir görselleştirmesi:
Biz Otsu 'eşik ikili bir görüntü elde etmek için daha sonra hatlarını bulmak ortalama dikdörtgen kontur alanı belirlemek için. Buradan konturları doldurarak yeşil renkle vurgulanmış büyük aykırı konturları kaldırıyoruz
Daha sonra karakterleri bağlamak için dikey bir çekirdek ve dilate yapıyoruz . Bu adım, gürültüyü tek tek lekelere ayırmak için istenen tüm metni bağlar.
Şimdi küçük gürültüyü gidermek için kontur alanını kullanarak konturlar ve filtreler buluyoruz
İşte yeşil ile vurgulanan tüm çıkarılan gürültü parçacıkları
Sonuç
kod
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()
Not: Geleneksel görüntü işleme eşikleme, morfolojik işlemler ve kontur filtreleme (kontur yaklaşımı, alan, en boy oranı veya damla algılama) ile sınırlıdır. Giriş görüntüleri karakter metni boyutuna göre değişebileceğinden, tekil bir çözüm bulmak oldukça zordur. Dinamik bir çözüm için kendi sınıflandırıcıyı makine / derin öğrenme ile eğitmek isteyebilirsiniz.