여기 아이디어가 있습니다. 이 문제를 여러 단계로 나눕니다.
평균 직사각형 윤곽 영역을 결정합니다. 그런 다음 임계 값을 지정하고 윤곽의 경계 사각형 영역 을 사용하여 필터링 합니다. 우리가하는 이유는 일반적인 문자가 너무 크지 만 큰 노이즈는 더 큰 직사각형 영역에 걸쳐있을 것이라는 관찰 때문입니다. 그런 다음 평균 면적을 결정합니다.
큰 특이 치 윤곽을 제거합니다. 윤곽을 다시 반복하고 윤곽 5x
을 채워 평균 윤곽 영역보다 큰 경우 큰 윤곽을 제거합니다 . 고정 임계 값 영역을 사용하는 대신이 동적 임계 값을 사용하여 더욱 견고합니다.
수직 커널로 확장하여 문자를 연결하십시오 . 아이디어는 문자가 열로 정렬되어 있다는 관찰을 이용합니다. 수직 커널로 확장하여 텍스트를 서로 연결하므로 노이즈가이 결합 된 윤곽에 포함되지 않습니다.
작은 소음을 제거하십시오 . 유지할 텍스트가 연결되었으므로 윤곽을 찾아 4x
평균 윤곽 영역 보다 작은 윤곽을 제거합니다 .
이미지를 비트 단위로 재구성합니다 . 마스크에 유지할 윤곽선 만 있기 때문에 비트 단위로 텍스트를 보존하고 결과를 얻습니다.
프로세스의 시각화는 다음과 같습니다.
우리는 오츠의 임계 값을 바이너리 이미지를 얻기 위해 다음 윤곽 찾을 평균 형상이 직사각형 영역을 결정합니다. 여기에서 등고선 을 채워 녹색으로 강조 표시된 큰 이상치 등고선을 제거합니다.
우리가 건설 다음 수직 커널 과 팽창 문자를 연결할 수 있습니다. 이 단계는 원하는 모든 텍스트를 연결하여 노이즈를 개별 블롭으로 유지하고 격리합니다.
이제 작은 노이즈를 제거하기 위해 윤곽 영역 을 사용하여 윤곽을 찾고 필터링 합니다.
제거 된 노이즈 입자가 모두 녹색으로 강조 표시되어 있습니다.
결과
암호
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()
참고 : 기존 이미지 처리는 임계 값 지정, 형태 학적 작업 및 윤곽선 필터링 (윤곽선 근사, 면적, 종횡비 또는 얼룩 감지)으로 제한됩니다. 입력 이미지는 문자 텍스트 크기에 따라 달라질 수 있으므로 단일 솔루션을 찾는 것은 매우 어렵습니다. 동적 솔루션을위한 머신 / 딥 러닝으로 자신 만의 분류기를 훈련시키는 것이 좋습니다.