본문 바로가기

DeepLearning/OCR_

[KR_OCR] 한국어 데이터셋(AI HUB)

반응형

기본적인 CRNN의 구조에 대한 파악이 끝난 후에

한국어 인식을 위한 한국어 데이터 셋을 사용하기 위한 준비.

 

Korea Sign Datasets

OCR 인식을 위한 한국 표지판 데이터 셋을 다운

- 어노테이션이 포함된 파일로 다운로드한다

- 데이터 다운로드 링크 : http://www.aihub.or.kr

 

AI 오픈 이노베이션 허브

AI 챗봇,안면인식 등 지능형 서비스 구현에 활용할 수 있는 지식베이스와 기계학습용 이미지 데이터를 제공합니다.

www.aihub.or.kr

>> 위의 주소로 들어가서 관광 카테고리에 가면 한국 표지판 데이터를 다운로드할 수 있다.

 

>> 다운로드한 뒤 압축을 푼 상태에서 'data/K-sign/' 경로 아래로 데이터를 넣는다

    ( 위 경로 아래에는 크롤링 데이터 / 고해상도 / 중 해상도 / 저해상도 각각의 파일에 이미지와 어노테이션이 있다)

 

K-Sign Dataset GTUtility 생성

- 현재 CRNN 모델에 잘 들어갈 수 있도록 전처리 과정이 필요하다 

 

어노테이션( json 파일 ) 확인

import json

with open('data/K-Sign/HighQuality/K-SignNet_DS_Sign_Annotation_HighQuality.json',encoding='UTF8') as f:
    ksign = json.load(f)

>> encoding을 UTF8로 설정을 해주어야 에러 없이 JSON파일을 불러올 수 있다.

>> 가져온 제이슨 파일은 딕셔너리 타입니다.

>> ksign.keys()의 값은 이미지 파일의 이름에 뒤에 특정 숫자가 붙는다. 

 

ksign.key() 값이다.

 

Key에 해당하는 Value를 확인

- 각 이미지에 해당하는 어노테이션 형식 확인

 

이미지 하나에 해당하는 Value값

 

더보기

file_attributes : dataSource, imageSource, image_resolution, labeling 등 파일에 대한 info

filename : 해당 이미지 파일의 이름

regions : region_attributes(촬영한 지역에 정보)

             : shape_attributes(데이터 박스의 좌표 값) 

               >> polygon 형태일 경우 : all_point_x [ x1, x2, x3, x4 ]와 all_point_y [ y1, y2, y3, y4 ] 값이 들어있다.

               >> rect 형태일 경우 : box값으로 [ x, y, w, h ] 값이 들어있다

               >> 텍스트 박스가 여러 개일 경우 regions안에 여러 개가 들어있다.

size : 사이즈 값이 있는데 이 값과 이미지 파일의 이름을 붙여서 key값으로 사용된다 

 

box값은 rect 타입과 polygon 타입으로 구성.

if gt_type == "rect":
    x = gt_data[img]['regions'][ann]['shape_attributes']['x']
    y = gt_data[img]['regions'][ann]['shape_attributes']['y']
    w = gt_data[img]['regions'][ann]['shape_attributes']['width']
    h = gt_data[img]['regions'][ann]['shape_attributes']['height']
  
    box = np.array([x,y,x+w,y,x+w,y+h,x,y+h], dtype=np.float32)
    
else gt_type == "polygon":
    xlist = gt_data[img]['regions'][ann]['shape_attributes']['all_points_x']
    ylist = gt_data[img]['regions'][ann]['shape_attributes']['all_points_y']
    
    if len(xlist)!= 4:
        continue
    
    xy= []
    xy = [xlist[0]]+ [ylist[0]]+ \
    [xlist[3]]+ [ylist[3]]+ \
    [xlist[2]]+ [ylist[2]]+ \
    [xlist[1]]+ [ylist[1]]
    
    box = np.array(xy, dtype=np.float32)
    
else:
    continue

    >> 데이터의 형태에 따라 전처리해주는 방식이 다르다.

    >> 일단 최종 box에 들어갈 값은 박스의 4개의 (x, y) 값이다

    >> x, y 값은 왼쪽 위 > 오른쪽 위 > 오른쪽 아래 > 왼쪽 아래 점 순서로 바꿔준다

        (현재 COCO-Text의 boxes의 값과 동일하게 맞춰주기 위해서)

 

boxes 값을 정규화

- boxes 값의 x값들은 이미지의 width로 나눠준다 (0과 1 사이로 맞춰줌)

- boxes 값의 y값들은 이미지의 height로 나눠준다 (0과 1사이로 맞춰줌)

boxes = np.asarray(boxes)
boxes[:,0::2] /= 2560
boxes[:,1::2] /= 1440

 

최종 아웃풋을 COCO-Text의 변수 값들과 동일한 형태로 맞춘다

- image_names : 이미지 파일 명

- data : bbox의 값 [ x1, y1, x2, y2, x3, y3, x4, y4 ] 8개의 배열로 들어간다

- text : label text 값이 들어간다

- image_path : 이미지 파일이 있는 경로

 

 

최종 코드 확인

data_KSign.py
import numpy as np
import json
import os

from ssd_data import BaseGTUtility

class GTUtility(BaseGTUtility):
    """
    Utility for Korean-text dataset.

    """

    def __init__(self, data_path, quality = 'high', polygon=True, only_with_label=True):
        test = False

        self.data_path = data_path
        gt_path = data_path
        image_path = data_path
        #image_path = os.path.join(data_path, 'train')
        self.gt_path = gt_path
        self.image_path = image_path
        self.classes = ['Background', 'Text']
        
        self.image_names = []
        self.data = []
        self.text = []
        
        if quality == 'high':
            with open(os.path.join(gt_path, 'K-SignNet_DS_Sign_Annotation_HighQuality.json'),encoding='UTF8') as f:
                gt_data = json.load(f)
        elif quality =='mid':
            with open(os.path.join(gt_path, 'K-SignNet_DS_Sign_Annotation_MidQuality.json'),encoding='UTF8') as f:
                gt_data = json.load(f)
        elif quality == 'low':
            with open(os.path.join(gt_path, 'K-SignNet_DS_Sign_Annotation_LowQuality.json'),encoding='UTF8') as f:
                gt_data = json.load(f)
        else:
            print('quality 입력!!')
        
        for img in gt_data.keys():
            image_name = gt_data[img]['filename']
            #print(image_name)
            
            boxes = []
            text = []
            for ann in range(len(gt_data[img]['regions'])):
                gt_type = gt_data[img]['regions'][ann]['shape_attributes']['name']

                if gt_type == "rect":
                    x = gt_data[img]['regions'][ann]['shape_attributes']['x']
                    y = gt_data[img]['regions'][ann]['shape_attributes']['y']
                    w = gt_data[img]['regions'][ann]['shape_attributes']['width']
                    h = gt_data[img]['regions'][ann]['shape_attributes']['height']
                    
                    #box = np.array([x,y, x+w, y+h], dtype=np.float32)
                    #box = np.array([x,y,x,y+h,x+w,y+h,x+w,y], dtype=np.float32)
                    box = np.array([x,y,x+w,y,x+w,y+h,x,y+h], dtype=np.float32)
                    
                elif gt_type == "polygon": # for 4points
                    xlist = gt_data[img]['regions'][ann]['shape_attributes']['all_points_x']
                    ylist = gt_data[img]['regions'][ann]['shape_attributes']['all_points_y']
                    
                    if len(xlist)!= 4:
                        continue
                    
                    xy= []
                    xy = [xlist[0]]+ [ylist[0]]+ \
                         [xlist[3]]+ [ylist[3]]+ \
                         [xlist[2]]+ [ylist[2]]+ \
                         [xlist[1]]+ [ylist[1]]
                    #여기서 박스의 모양:
                    #가장 왼쪽 상단 > 오른쪽 상단 > 오른쪽 하단 > 왼쪽 하단 순서로 이동.
                    
                    '''for x, y in zip(xlist, ylist):
                        xy = xy + [x] + [y]'''
                    
                    box = np.array(xy, dtype=np.float32)
                else:
                    continue
                    
                if 'annotation_kr' in gt_data[img]['regions'][ann]['region_attributes'].keys():
                    txt = gt_data[img]['regions'][ann]['region_attributes']['annotation_kr']
                else:
                    if only_with_label:
                        continue
                    else:
                        txt = ''
                        
                boxes.append(box)
                text.append(txt)

            if len(boxes) == 0:
                #print("No Bounding Box !")
                continue
                
            boxes = np.asarray(boxes)
            #print(boxes.shape)
            boxes[:,0::2] /= 2560
            boxes[:,1::2] /= 1440
            
            boxes = np.concatenate([boxes, np.ones([boxes.shape[0],1])], axis=1)
            
            self.image_names.append(image_name)
            self.data.append(boxes)
            self.text.append(text)
        
        self.init()
        
if __name__ == '__main__':
    
    gt_util = GTUtility('data/K-SIGN/', validation=False, polygon=True, only_with_label=True)

    import pickle
    
    file_name = 'gt_util_ksigntext.pkl'
    print('save to %s...' % file_name)
    pickle.dump(gt_util, open(file_name,'wb'))
    print('done')
    
    print(gt_util.data)

>> 위 GTUtility를 호출할 때 파라미터로 quality와 이미지 데이터가 있는 경로를 준다.

>> quality = 'high' / 'mid' / 'low' 중 하나를 주면 된다.

 

 

Json파일을 Pickle파일로 변경

위에서 만든 클래스를 import 한다.

from data_KSign import GTUtility

 

3가지 퀄리티 각각의 GTUtility 객체를 생성한다.

gt_util_high = GTUtility('data/K-Sign/HighQuality/', quality='high')

gt_util_mid = GTUtility('data/K-Sign/MidQuality/', quality='mid')

gt_util_low = GTUtility('data/K-Sign/LowQuality/', quality='low')

- 위에서 생성한 객체를 print() 한다.

- 생성된 객체에 대한 간략한 summary()를 확인할 수 있다.

 

위에서 생성한 객체를 이용해 피클 파일 생성

#HighQuality 피클파일 
file_name = 'gt_util_ksign_high.pkl'
pickle.dump(gt_util_high, open(file_name,'wb'))

#MidQuality 피클파일 
file_name = 'gt_util_ksign_mid.pkl'
pickle.dump(gt_util_mid, open(file_name,'wb'))

#LowQuality 피클파일 
file_name = 'gt_util_ksign_low.pkl'
pickle.dump(gt_util_low, open(file_name,'wb'))

>> pickle.dump(객체, open(파일명, 'wb')를 하면 피클 파일이 생성된다.

 

추후에 생성한 피클을 로딩할 때

import os
import pickle

from data_cocotext import GTUtility

#HighQuality
file_name1 = 'gt_util_ksign_high.pkl'

with open(file_name1, 'rb') as f:
    gt_util_high = pickle.load(f)
    
#MidQuality    
file_name2 = 'gt_util_ksign_mid.pkl'

with open(file_name2, 'rb') as f:
    gt_util_mid = pickle.load(f)
    
#LowQuality    
file_name3 = 'gt_util_ksign_low.pkl'

with open(file_name3, 'rb') as f:
    gt_util_low = pickle.load(f)

>> 위와 같은 방식으로 피클 파일을 로드시키면 된다.

반응형