이미지 전처리 & 증강

전처리 Preprocessing

Resize

보간법 사용
  • 줄일 때: 하나의 값으로 할당
  • 늘릴 때: 근사 값으로 채움

사이즈가 정사각형이 아닌 경우
  • 정사각으로 만들고 여백을 검정색 패딩으로 채움

Zero-centering

평균이 0인 데이터로 변경
  • 픽셀의 숫자 형태는 0~255
  • 양수보다는 양수와 음수와 공존하는 것이 좋다.
  • Zero-centering: 양수와 음수가 공존하도록 변경

  • 숫자의 평균을 구하고 평균이 0일 때의 값을 구하자.
  • 평균으로부터의 편차를 구하자.

  • X -= np.mean(X, axis=0)
    • 예시) X.shape = (2, 3, 224, 224)
    • (batch, channel, width, height)
    • 결과) X.shape = (1, 3, 224, 224)

색상

Grayscaling 변환
  • 3채널 -> 1채널로
  • RGB를 3:6:1로 하여 합친다.
  • 데이터 양을 줄인다. (텐서의 숫자 줄어듬)
  • 변환시 데이터 복잡도가 올라간다.
  • overfit일 때, Grayscaling으로 바꾸면 효과가 있다.

이진화 작업
  • 0과 1로만 표현
  • 데이터 양을 줄인다. (텐서의 크기 동일)

노이싱

디노이징
  • 노이즈 제거
  • underfit의 경우, 문제를 쉽게 한다.

  • 블러: 이미지를 부드럽게 또는 흐릿하게
  • 필터링: 데이터를 걸러냄
  • 모폴로지: 픽셀값 대체
    • 팽창: 최대픽셀 대체 밝게, 끊어진 부분을 연결
    • 침식: 최소픽셀 대체 어둡게, 흰점 노이즈 제거
    • 혼합:
      • 열림(오프닝): 침식 > 팽창
      • 닫힘(클로징): 팽창 > 침식

애드노이
  • 노이즈 추가
  • overfit의 경우, 문제를 어렵게 한다.
  • 학습데이터가 너무 쉬운 경우, 애드노이싱을 사용한다.

증강 Augmentation

  • 데이터 수집에 한계가 놓인 상태에서, 기존 데이터셋을 변형하여 재생산한다.
  • 직접 수집 데이터만큼은 아니지만 미세한 효과를 준다. 

증강과 학습난이도

  • 증강 데이터는 변형 과정에서 난도를 높인다.

증강의 기획적 판단

  • 테스트데이터의 선을 넘지 않는다. 
    • 테스트 데이터에 존재하지 않는 것을 만들지 않는다.

  • 학습데이터보다 쉽지 않게 한다.

  • 증강의 범위: 학습 ~ 테스트 데이터

Albumentations

  • 이미지 증강 파이썬 라이브러리

  • 지원기법
    • 픽셀 수준: 흐리게 밝기, 대비, 노이즈, RGB 변경
    • 공간 수준: 이미지 회전, 반전, 대칭
    • 크기 변환: 사이즈조정, 잘라내기
    • 혼합 : 비, 그림자, 눈, 안개 

레이블 혼합

두 이미지의 투명도를 조정해서 혼합
두 이미지의 특정 영역을 혼합

이미지 처리시, 메모리 부족

  1. 메모리 요구사항이 낮은 모델 사용
  2. 배치 크기 줄이기
  3. 이미지 크기 줄이기
  4. 증강 데이터를 미리 만들지 않는다. (훈련 중에 조금씩 만들면서, 훈련 과정에서 증강데이터 훈련을 추가한다.)
  5. 더이상 필요하지 않는 변수는 del로 지운다.
  6. 메모리 프로파일링 도구 사용

Python 실습

import cv2
import os

import numpy as np
from matplotlib import pyplot as plt

!pip install gdown==v4.6.3

# 구글 드라이브에 올린 이미지 링크에서 뒷 부분만 발췌
# https://drive.google.com/file/d/1EVDm6wR2E2ukbW3u17VKaGWk5XkDedX6/view?usp=drive_link
!gdown 1EVDm6wR2E2ukbW3u17VKaGWk5XkDedX6

!unzip imgset_mini.zip

Resize

target_size = 500

# img_path 순회하면서 코드 반복
# 불러오기 -> resize -> 저장하기
for filename in ['airplane', 'car', 'dog']:
    img_path = '/content/'+filename+'.jpg'
    img = cv2.imread(img_path)

    # RGB로 변경
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

    # 이미지의 width와 height 중 긴 쪽을 img_size에 맞추기
    # 둘 중 큰 값을 target_size와 ratio 계산
    if(img.shape[1] > img.shape[0]) : # 세로 > 가로
        ratio = target_size/img.shape[1] # 비율 = target_size/세로
    else :
        ratio = target_size/img.shape[0] # 비율 = target_size/가로

    # cv2.resize함수를 활용하면 ratio를 입력하여 원하는 사이즈로 resize 가능
    # fx와 fy의 비율을 유지한다. INTER_LINEAR을 선형보간법
    img = cv2.resize(img, dsize=(0, 0), fx=ratio, fy=ratio, interpolation=cv2.INTER_LINEAR)
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

    # 가로, 세로
    w, h = img.shape[1], img.shape[0]

    # 패딩 길이 계산 = (긴 변 길이 - 짧은 변 길이) / 2
    # * 어차피 긴변은 target size 와 동일하기 때문에
    # * 둘 다 target_size와의 차이를 계산한다.
    dw = (target_size - w)/2 # target_size와 w(=가로)의 차이
    dh = (target_size - h)/2 # target_size와 h(=세로)의 차이

    M = np.float32([[1,0,dw], [0,1,dh]])  #(2*3 이차원 행렬)
    img_re = cv2.warpAffine(img, M, (target_size, target_size)) #이동변환: 좌측상단정렬을 (좌측)중앙정렬로

    cv2.imwrite(f'/content/resized/{filename}_img.jpg' , img_re)

Resize + Agumentation(증강)

def augmentation(target_size):
    answer1 = input('grayscaling은 1, 이진화는 2: ')
    answer2 = input('zero-centering은 1, 안하려면 0을 입력하세요.: ')
        
    list_img =[]
    # 불러오기 -> resize -> 저장하기
    for filename in ['airplane', 'car', 'dog']:
        img_path = '/content/'+filename+'.jpg'
        img = cv2.imread(img_path)

        # 이미지의 width와 height 중 긴 쪽을 img_size에 맞추기
        if(img.shape[1] > img.shape[0]) : # 세로 > 가로
            ratio = target_size/img.shape[1] # 비율 = target_size/세로
        else :
            ratio = target_size/img.shape[0] # 비율 = target_size/가로

        # cv2.resize함수를 활용하면 ratio를 입력하여 원하는 사이즈로 resize 가능
        img = cv2.resize(img, dsize=(0, 0), fx=ratio, fy=ratio, interpolation=cv2.INTER_LINEAR)

        # 패딩 길이 계산 = (긴 변 길이 - 짧은 변 길이) / 2
        w, h = img.shape[1], img.shape[0]
        dw = (target_size - w)/2 # target_size와 w(=가로)의 차이
        dh = (target_size - h)/2 # target_size와 h(=세로)의 차이

        #이동
        M = np.float32([[1,0,dw], [0,1,dh]])  #(2*3 이차원 행렬)
        img_re = cv2.warpAffine(img, M, (target_size, target_size)) #이동변환: 좌측상단정렬을 (좌측)중앙정렬로

        #BGR을 그레이스케일로 변경
        img_aug = cv2.cvtColor(img_re, cv2.COLOR_BGR2GRAY)

        # 이진화 (이녀석만 주석처리 하면됨.)
        if answer1 == '2':
            thresh = 127.5
            binarization = lambda img : cv2.threshold(img, thresh, target_size, cv2.THRESH_BINARY)
            img_aug = [binarization(img)[1] for img in img_aug]

        #zero-centering
        mean_img = np.mean(img_aug, axis=0)
        zero_centered_images = img_aug - mean_img

        #리스트 저장
        if answer2 == '1':
            list_img.append(zero_centered_images)
        else:
            list_img.append(img_aug)

    #출력
    plt.figure(figsize=(15,5))

    for idx, img in enumerate(list_img):
        plt.subplot(1,3,idx+1)
        # plt.imshow(img) #  색상 맵(color map)을 자동으로 적용하기 때문에 제대로 출력x
        plt.imshow(img, cmap='gray')








댓글 쓰기

다음 이전