text 인식률을 높이기위해 전처리과정이 필수적이다. 이번 포스트에서는 다양한 전처리기법을 시도해보고자 한다.

Adaptive Threshold

Global Threshold는 문턱 값을 하나의 이미지 전체에 적용시키는 반면 Adaptive Threshold는 이미지의 구역구역마다 threshold를 실행 시켜줌. 따라서 빛의 밝기에 따라 사진의 명암이 달라져도 객체를 잘 인식할 수 있다.

ret, global_th = cv2.threshold(src=img, thresh=127, maxval=255, type=cv2.THRESH_BINARY) # 이미지 전체에 global 하게 적용되는 th=127
thr1 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # cv2.ADAPTIVE_THRESH_GAUSSIAN_C가 픽셀마다 th 찾아줌.
thr2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) 

image

image

image

Gaussain Blur

Gaussian blur를 적용하면 히스토그램에서 확실한 봉우리를 만들고, 여기에 Otsu 알고리즘을 적용하여 문턱값을 구한 후 thresholding을 적용하면 보다 나은 Denoising이 된다.

def thresholding(img_file):
  img = cv2.imread(img_file, 0) # gray scale

  # global threshold
  ret, thr1 = cv2.threshold(img, 127,255,cv2.THRESH_BINARY)
  # Otsu binarization
  ret, thr2 = cv2.threshold(img, 0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
  # Gaussian blur + Otsu
  blur = cv2.GaussianBlur(img, (3,3), 0)  # kernel 커질수록 노이즈는 사라지지만 그만큼 정보손실 큼. (kernel size : 홀수)
  ret, thr3 = cv2.threshold(blur, 0,255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

  titles = ['original noisy','Histogram','Global Thresholding',
            'original noisy', 'Histogram', 'Otsu Thresholding',
            'Gaussian-filtered','Histogram', 'Otsu Thresholding']

  images = [img, 0, thr1, img, 0, thr2, blur, 0, thr3]

  plt.figure(figsize=(15,10))
  for i in range(3):
    plt.subplot(3,3, i*3+1), plt.imshow(images[i*3], 'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])

    plt.subplot(3,3, i*3+2), plt.hist(images[i*3].ravel(), 256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])

    plt.subplot(3,3, i*3+3), plt.imshow(images[i*3+2], 'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
  
  plt.show()

thresholding(img_file)

image

Gaussain blur + Otsu binaryzation

따라서 이후에서는 가우시안 필터링과 binaryzation성능이 좋았던 Otsu 방법을 사용하기로 한다.

def image_smoothening(img,_ThredholdCount=0):
  ret1, th1 = cv2.threshold(img, G_BINARY_THREHOLD+(G_BINARY_THREHOLD_ALPHA*_ThredholdCount), 255, cv2.THRESH_BINARY)
  ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
  blur = cv2.GaussianBlur(th2, (1, 1), 0)  # kernel size 크게 잡지 않도록 주의
  ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

  titles = ['Global','Otsu','Otsu > Gaussain_Blur','Otsu > Gaussian_Blur > Otsu']
  images = [th1,th2,blur,th3]
  plt.figure(figsize=(15,10))
  for i in range(4):
    plt.subplot(2,2, i+1), plt.imshow(images[i], 'gray')
    plt.title(titles[i]), plt.xticks([]), plt.yticks([])

  plt.show()


img = cv2.imread(img_file, 0) # gray scale 불러와야함.
image_smoothening(img)

image

전처리 후 Bounding Box

이후에서는 운전면허 샘플이미지를 사용하여 테스트해보고자 한다.

'''
1. Gaussian Filter
2. Otsu Adaptive Threshold
'''
blur = cv2.GaussianBlur(img, (1, 1), 0)  # kernel size 크게 잡지 않도록 주의
ret1, th1 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # gray scale을 받음에 주의
cv2_imshow(th1)

image

for idx, b in enumerate(boxes_num.splitlines()):
    '''
    숫자를 가리는 알고리즘 
    '''
    if idx != 0:  # head를 제외하고 split
        b = b.split()
        if len(b) ==12:  # 객체가 있는것만 뽑아서
            # if ('-' in b[11]) and ('.' not in b[11]) :
            # if ('-' in b[11]) and (len(b[11]) >13):
            if '-' in b[11] :
                x,y,w,h = int(b[6]),int(b[7]),int(b[8]),int(b[9])
                cv2.rectangle(img, (x,y),(x+w,y+h),(255,0,0), -1)   # 좌상단, 우하단
                cv2.putText(img, b[11], (x,y+25), cv2.FONT_HERSHEY_COMPLEX, fontScale=0.5, color=(0,0,255), thickness=1)

cv2_imshow(img)

image