Python tech/Computer Vision

[Python CV] 세그멘테이션을 통해 이미지 잘라내고 회전하기

콜레오네 2021. 8. 4. 04:17

이미지 데이터 전처리 (Image Preprocessing)

딥러닝을 활용하여 이미지 데이터를 훈련시키기 위해 필요한 과정 중 하나가 바로 이미지 데이터 전처리입니다.

 

AI HUB의 축산물 품질 이미지 데이터를 다운로드하였습니다.

https://aihub.or.kr/aidata/30733

 

축산물 품질(QC) 이미지 | AI 허브

구축 내용 및 제공 데이터량

aihub.or.kr


이 중에서 제가 사용한 데이터는 소고기와 돼지고기 데이터입니다.

아래 사진은 AI HUB에서 제공하는 육류 이미지 데이터의 예시입니다.

AI HUB 소고기 데이터
AI HUB 돼지고기 데이터

 


처음 원천 데이터를 그대로 fine tuning 시켰고, 그 결과 정확도가 50% 이상 오르지 않는 처참한 결과가 나왔습니다...;;

 

그래서 해결 방법을 고민하던 중, 이미지 데이터 전처리의 필요성을 느끼고, AI HUB에서 제공하는 레이블 데이터 (json)을 이용해 보기로 했습니다.

 

각 이미지마다 쌍을 이루는 json 파일이 제공되고, 이미지의 메타 데이터는 이미지 크기, 등급 분류, 세그멘테이션 등의 정보가 담겨있었습니다.

{"label_info": 
{"image": 
{"file_name": "QC_cow_segmentation_1_069428.jpg", 
"width": 1080, 
"height": 1920}, 

"shapes": [
{"label": "hanwoo", 
"points": [[500.6648199445983, 935.6232686980608], [492.3545706371191, 919.0027700831024], ...], 
"shape_type": "segmentation", 
"grade": "1", 
"gender": "steer"}]}}

json 파일은 딕셔너리처럼 활용할 수 있습니다.

여기서 points 정보가 바로 세그멘테이션 정보입니다.

이미지에서 고기의 위치를 대략적으로 알려줍니다.

 

points는 [x, y] 좌표의 쌍으로 이루어진 2차원 리스트입니다.

세그멘테이션을 기준으로 고기 위치가 완전히 포함되게 잘라내어 학습에 불필요한 부분을 제거해보겠습니다.

y좌표 리스트와 x 좌표 리스트를 각각 생성해준 다음, 각 리스트의 최솟값과 최댓값을 통해 이미지에서 잘라낼 부분을 정할 수 있습니다.

 

다음은 세그멘테이션 정보를 이용하여 이미지를 잘라내는 코드입니다.

# 세그멘테이션 기준으로 이미지 잘라내기
def cropBySeg(image, point, padd = 5):
    ylist, xlist = [], [] # y좌표 리스트, x좌표 리스트
    for x, y in point:
        ylist.append( int(y) )
        xlist.append( int(x) )

    # 잘라낼 이미지 좌표리스트, 처음과 마지막 포인트
    crop_y, crop_x = [ min(ylist), max(ylist) ], [ min(xlist), max(xlist) ]
    
    # 잘라낼 이미지의 가로 세로 길이
    w, h = crop_x[1]-crop_x[0], crop_y[1]-crop_y[0]

    # 이미지 잘라내기
    cropped_image = image[ crop_y[0] - padd: crop_y[1] + padd , crop_x[0] - padd: crop_x[1] + padd ]
    return cropped_image, w, h

 

그다음 과정으로 잘라낸 이미지를 세로로 긴 이미지로 전환하겠습니다.

직사각형 이미지는 가로로 긴 이미지와 세로로 긴 이미지 2가지 종류가 있습니다.

이를 통일시켜 주기 위해, 저는 가로 이미지일 경우 90도 회전시켜 세로 이미지로 변경시켜주었습니다.

 

아래 함수는 위 cropBySeg() 함수를 이용하여 개발하였습니다.

# 이미지를 세그먼트대로 잘라낸 다음, 세로 이미지로 변경
# 이미지 경로, 이미지 이름, json파일 경로, json파일 이름, 저장할 디렉터리, 여유 픽셀 사이즈
def preprocessing(imagepath, imagename, jsonpath, jsonname, saved_dir, pad = 10):
    # json 파일 읽어들이기
    with open(f"{jsonpath}{jsonname}.json", 'rt') as f:
        json_data = json.load(f)
    # 세그멘테이션 정보
    points = json_data['label_info']['shapes'][0]['points']
    # 이미지 읽기
    image = cv2.imread(f'{imagepath}{imagename}.jpg', cv2.IMREAD_COLOR)
    # 이미지 잘라내기
    cropped_image, w, h = cropBySeg(image, points, padd = pad)
    

    if w > h: # 가로 이미지일 경우
        # 90도 회전시키기
        cropped_image = cv2.rotate(cropped_image, cv2.ROTATE_90_CLOCKWISE)
    # 잘라낸 (그리고 회전시킨) 이미지 저장
    cv2.imwrite(saved_dir + "/" + imagename + "_crop.jpg", cropped_image)
    return 0

 

다음과 같이 활용하시면 됩니다.

impath = "./sample/image/" #이미지 데이터 경로
jpath = "./sample/seg/" # json파일 데이터 경로

imname = "QC_pig_001" # 이미지 파일 이름
jname = "QC_pig_001" # 당연히 json 파일 이름도 이미지 파일 이름과 동일합니다

savedd = "./sample/crop/" # 잘라낸 이미지 파일을 저장할 경로

# 이미지 전처리 실행
preprocessing(impath, imname, jpath, jname, savedd, pad = 0)

그 결과...

원본 소고기 이미지
이미지 전처리 후 이미지

 

 

원본 돼지고기 이미지
이미지 전처리 후 회전시킨 돼지고기 이미지

 

 

이상 세그맨테이션 정보를 이용하여, 이미지를 잘라내고 회전시켜보았습니다.

 

반응형