이미지 데이터 전처리 (Image Preprocessing)
딥러닝을 활용하여 이미지 데이터를 훈련시키기 위해 필요한 과정 중 하나가 바로 이미지 데이터 전처리입니다.
AI HUB의 축산물 품질 이미지 데이터를 다운로드하였습니다.
https://aihub.or.kr/aidata/30733
이 중에서 제가 사용한 데이터는 소고기와 돼지고기 데이터입니다.
아래 사진은 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)
그 결과...
이상 세그맨테이션 정보를 이용하여, 이미지를 잘라내고 회전시켜보았습니다.
'Python tech > Computer Vision' 카테고리의 다른 글
[Python opencv] K-means 활용, 이미지 색상 개수 줄이기 (3) | 2021.05.16 |
---|---|
[Python opencv] cv2 색상 구분 기준으로 라인 그리기 (0) | 2021.05.16 |
[Python OpenCV] 이미지를 그림화 하기 (색 일반화) (0) | 2021.04.05 |
[camelot] line_scale이란? (opencv로 라인 추출) (0) | 2021.03.09 |
[camelot] read_pdf() 파라미터 (0) | 2021.02.08 |