이미지 데이터

이재경·2023년 1월 10일
0

인공지능

목록 보기
10/14

이미지 형태 변환하기

이번 실습에서는 이미지의 형태를 변환하는 기법들을 Pillow를 통해 구현해보도록 하겠습니다.

대표적인 이미지 변형 기법에는 잘라내기(Crop), 회전(Rotate), 크기 변화(Resize), 전단 변환(Shearing) 등이 있습니다.

지시사항에 따라 각각의 기능을 구현해보세요.

지시사항
이미지를 잘라내는 함수 crop을 완성하세요.
이미지를 잘라낼 좌표는 coordinates 파라미터에 지정되어 있습니다.

이미지를 회전하는 함수 rotate를 완성하세요.
angle은 이미지를 반시계 방향으로 회전할 각도입니다.
expand는 회전 결과를 기존 이미지 사이즈 내에서 표현할지 여부를 결정하는 파라미터입니다.

이미지의 사이즈를 변경하는 함수 resize를 완성하세요.
new_size는 새로운 이미지 사이즈입니다.

이미지에 전단 변환(Shearing)을 적용하는 함수 shearing을 완성하세요.
shear_factor는 전단 변환을 적용할 정도, 즉 평행사변형을 얼마나 기울일지를 결정하는 파라미터입니다.
세개의 None에 img에 사용할 메소드, 사용할 변환 이름, 적절한 shear_factor 값을 넣어주면 됩니다.

main 함수에서 불러온 이미지 img에 아래 작업을 수행하도록 하세요.
좌측 상단 좌표는 (150,200)(150, 200)(150,200), 우측 하단 좌표는 (450,300)(450, 300)(450,300)으로 하여 이미지를 잘라내세요.
이미지를 반시계 방향으로 160도만큼 회전시키고, 회전한 이미지를 모두 표현할 수 있도록 하세요.
이미지 크기를 (640,360)(640, 360)(640,360)으로 변경하세요.
전단 변환 정도를 0.8로 하여 전단 변환을 수행하세요.

from elice_utils import EliceUtils

elice_utils = EliceUtils()

from PIL import Image

def crop(img, coordinates):
    # TODO: [지시사항 1번] 이미지를 자르는 코드를 완성하세요.
    img_crop = img.crop(coordinates)
    
    return img_crop
    
def rotate(img, angle, expand=False):
    # TODO: [지시사항 2번] 이미지를 회전하는 코드를 완성하세요.
    img_rotate = img.rotate(angle,expand=expand)
    
    return img_rotate
    
def resize(img, new_size):
    # TODO: [지시사항 3번] 이미지 크기를 변경하는 코드를 완성하세요.
    img_resize = img.resize(new_size)
    
    return img_resize
    
def shearing(img, shear_factor):
    # TODO: [지시사항 4번] 이미지를 전단 변환하는 코드를 완성하세요.
    img_shearing = img.transform((int(img.size[0] * (1 + shear_factor)), img.size[1]),
                            Image.AFFINE, (1, -shear_factor, 0, 0, 1, 0))
                                 
    return img_shearing
    
def show_image(img, name):
    img.save(name)
    elice_utils.send_image(name)

def main():
    img = Image.open("Lenna.png")
    
    # TODO: [지시사항 5번] 지시사항에 따라 적절한 이미지 변환을 수행하세요.
    
    # 이미지 자르기
    img_crop = crop(img,(150,200,450,300))
    
    # 이미지 회전하기
    img_rotate = rotate(img,160,expand=True)
    
    # 이미지 크기 바꾸기
    img_resize = resize(img,(640,360))
    
    # 이미지 전단 변환
    img_shearing = shearing(img,0.8)
    
    print("=" * 50, "Crop 결과", "=" * 50)
    show_image(img_crop, "crop.png")
    
    print("=" * 50, "Rotate 결과", "=" * 50)
    show_image(img_rotate, "rotate.png")
    
    print("=" * 50, "Resize 결과", "=" * 50)
    show_image(img_resize, "resize.png")
    
    print("=" * 50, "Shearing 결과", "=" * 50)
    show_image(img_shearing, "shearing.png")
    
    return img_crop, img_rotate, img_resize, img_shearing

if __name__ == "__main__":
    main()

이미지 색상 변환하기

이번 실습에서는 이미지의 색상을 변환하는 기법들을 Pillow를 통해 구현해보도록 하겠습니다.

대표적인 이미지 색상 변환 기법에는 밝기 변환, 대조 변환, 흑백 변환 등이 있습니다.

지시사항에 따라 각각의 기능을 구현해보세요.

지시사항
이미지의 밝기를 변화시키는 함수 change_brightness을 완성하세요.
factor는 밝기가 변화할 정도입니다.
밝기 변환을 수행할 Enhancer 객체를 만들어야 합니다.

이미지의 대조를 변화시키는 함수 change_contrast을 완성하세요.
factor는 대조가 변화할 정도입니다.
대조 변환을 수행할 Enhancer 객체를 만들어야 합니다.

이미지를 흑백 이미지로 변경하는 함수 change_grayscale를 완성하세요.

main 함수에서 불러온 이미지 img에 아래 작업을 수행하도록 하세요.
이미지를 1.5배 밝게 하세요.
이미지를 5배 어둡게 (0.2배 밝게) 하세요.
이미지의 대조를 3배 강하게 만드세요.
이미지의 대조를 10배 약하게 (0.1배로) 만드세요.
이미지를 흑백으로 변환하세요.

from elice_utils import EliceUtils

elice_utils = EliceUtils()

from PIL import Image
from PIL import ImageEnhance

def change_brightness(img, factor):
    # TODO: [지시사항 1번] 이미지의 밝기를 변화시키는 코드를 완성하세요.
    bright_enhancer = ImageEnhance.Brightness(img)
    img_bright = bright_enhancer.enhance(factor)
    
    return img_bright
    
def change_contrast(img, factor):
    # TODO: [지시사항 2번] 이미지의 대조를 변화시키는 코드를 완성하세요.
    contrast_enhancer = ImageEnhance.Contrast(img)
    img_contrast = contrast_enhancer.enhance(factor)
    
    return img_contrast
    
def change_grayscale(img):
    # TODO: [지시사항 3번] 이미지를 흑백 이미지로 변경하는 코드를 완성하세요.
    img_gray = img.convert("L")
    
    return img_gray
    
def show_image(img, name):
    img.save(name)
    elice_utils.send_image(name)

def main():
    img = Image.open("Lenna.png")
    
    # TODO: [지시사항 4번] 지시사항에 따라 적절한 이미지 변환을 수행하세요.
    
    # 이미지 밝게 하기
    img_bright = change_brightness(img,1.5)
    
    # 이미지 어둡게 하기
    img_dark = change_brightness(img,0.2)
    
    # 이미지 대조 늘리기
    img_high_contrast = change_contrast(img,3)
    
    # 이미지 대조 줄이기
    img_low_contrast = change_contrast(img,0.1)
    
    # 이미지 흑백 변환
    img_gray = change_grayscale(img)
    
    print("=" * 50, "밝은 이미지", "=" * 50)
    show_image(img_bright, "bright.png")
    
    print("=" * 50, "어두운 이미지", "=" * 50)
    show_image(img_dark, "dark.png")
    
    print("=" * 50, "강한 대조 이미지", "=" * 50)
    show_image(img_high_contrast, "high_contrast.png")
    
    print("=" * 50, "약한 대조 이미지", "=" * 50)
    show_image(img_low_contrast, "low_contrast.png")
    
    print("=" * 50, "흑백 이미지", "=" * 50)
    show_image(img_gray, "gray.png")
    
    return img_bright, img_dark, img_high_contrast, img_low_contrast, img_gray

if __name__ == "__main__":
    main()

이미지 필터 변환하기

이번 실습에서는 이미지에 필터를 적용하여 변환하는 기법들을 Pillow를 통해 구현해보도록 하겠습니다.

대표적인 필터 변환 기법에는 샤프닝(Sharpening), 블러(Blur), 경계선 탐지(Edge Detection) 등이 있습니다.

지시사항에 따라 각각의 기능을 구현해보세요.

지시사항
이미지에 샤프닝 필터를 적용시키는 함수 sharpening을 완성하세요.
샤프닝 필터는 ImageFilter에서 가져옵니다.

이미지에 블러 필터를 적용시키는 함수 blur을 완성하세요.
블러 필터는 ImageFilter에서 가져옵니다.

이미지에 경계선 탐지 필터를 적용시키는 함수 detect_edge을 완성하세요.
경계선 탐지 필터는 ImageFilter에서 가져옵니다.

main 함수에서 불러온 이미지 img에 아래 작업을 수행하도록 하세요.
이미지에 샤프닝 필터를 한번 적용하세요.
이미지에 샤프닝 필터를 5번 적용하세요.
이미지에 블러 필터를 한번 적용하세요.
이미지에 블러 필터를 5번 적용하세요.
이미지의 경계선을 찾으세요.

from elice_utils import EliceUtils

elice_utils = EliceUtils()

from PIL import Image
from PIL import ImageFilter

def sharpening(img):
    # TODO: [지시사항 1번] 이미지에 샤프닝 필터를 적용시키는 코드를 완성하세요.
    img_sharpen = img.filter(ImageFilter.SHARPEN)
    
    return img_sharpen
    
def blur(img):
    # TODO: [지시사항 2번] 이미지에 블러 필터를 적용시키는 코드를 완성하세요.
    img_blur =img.filter(ImageFilter.BLUR)
    
    return img_blur
    
def detect_edge(img):
    # TODO: [지시사항 3번] 이미지의 경계선을 탐지하는 코드를 완성하세요.
    img_edge = img.filter(ImageFilter.FIND_EDGES)
    
    return img_edge
    
def show_image(img, name):
    img.save(name)
    elice_utils.send_image(name)

def main():
    img = Image.open("Lenna.png")
    
    # TODO: [지시사항 4번] 지시사항에 따라 적절한 이미지 변환을 수행하세요.
    
    # 이미지 샤프닝 한번 적용하기
    img_sharpen_1 = sharpening(img)
    
    # 이미지 샤프닝 5번 적용하기
    img_sharpen_5 = sharpening(img)
    img_sharpen_5 = sharpening(img_sharpen_5)
    img_sharpen_5 = sharpening(img_sharpen_5)
    img_sharpen_5 = sharpening(img_sharpen_5)
    img_sharpen_5 = sharpening(img_sharpen_5)
    
    # 이미지 블러 한번 적용하기
    img_blur_1 =blur(img)
    
    # 이미지 블러 5번 적용하기
    img_blur_5 = blur(img)
    img_blur_5 = blur(img_blur_5)
    img_blur_5 = blur(img_blur_5)
    img_blur_5 = blur(img_blur_5)
    img_blur_5 = blur(img_blur_5)
    
    # 이미지 경계선 찾기
    img_edge = detect_edge(img)
    
    print("=" * 50, "샤프닝 한번 적용한 이미지", "=" * 50)
    show_image(img_sharpen_1, "sharpen_1.png")
    
    print("=" * 50, "샤프닝 다섯번 적용한 이미지", "=" * 50)
    show_image(img_sharpen_5, "sharpen_5.png")
    
    print("=" * 50, "블러 한번 적용한 이미지", "=" * 50)
    show_image(img_blur_1, "blur_1.png")
    
    print("=" * 50, "블러 다섯번 적용한 이미지", "=" * 50)
    show_image(img_blur_5, "blur_5.png")
    
    print("=" * 50, "경계선 이미지", "=" * 50)
    show_image(img_edge, "edge.png")
    
    return img_sharpen_1, img_sharpen_5, img_blur_1, img_blur_5, img_edge


if __name__ == "__main__":
    main()

딥러닝 모델 학습을 위한 이미지 불러오기

이번 실습에서는 데이터 셋에서 이미지 한장을 불러와 PIL과 numpy 배열로 바꾸어서 이미지의 속성을 살펴보도록 하겠습니다.

이미지를 다루는 인공지능 모델을 사용하기 위해서는 이미지의 표현 방식에 대한 이해가 필요합니다.

이번 실습에서 사용할 이미지는 dataset/val/dogs안에 있는 10개의 이미지중 첫번째 이미지입니다.

지시사항
Image.open을 이용해서 이미지를 불러오는 함수load_image를 완성하세요.
열어야 하는 이미지 파일은 path 경로의 name 이름을 가지고 있습니다.

이미지의 크기를 PIL과 numpy를 통해 확인하는 코드를 완성하세요.
PIL 이미지의 크기를 확인할 때는 size를 사용합니다. 이미지의 크기를 출력하는 함수를 완성하세요.
이미지를 numpy 배열로 변환하여 np_img에 저장하세요.
numpy 배열의 shape를 이용하여 이미지의 형태를 출력하세요

PIL과 numpy로 이미지를 다루는 코드를 완성하세요.
numpy 배열에서 (10, 20)에 위치한 픽셀 값을 가져와 출력하는 코드를 완성하세요. PIL로 가져온 픽셀의 값과 같아야 합니다.
numpy로 변환하면 (세로, 가로, 채널)의 형태로 저장되는 점을 이용하세요
PIL을 이용하여 이미지의 크기를 (224, 224)로 변경하세요.
Tips
load_image: 이미지의 경로(path)와 이미지 이름(name)을 매개변수로 받아 해당 이미지를 불러와 반환합니다.

PIL.Image.open(fp): 파일 경로를 fp로 전달하면 해당 이미지를 불러옵니다.

np.array(img): 이미지를 numpy 배열 형식으로 변환합니다.

from elice_utils import EliceUtils

elice_utils = EliceUtils()

from PIL import Image
import matplotlib.pyplot as plt
import os
import numpy as np

def show_plot(img, title=" "):
    plt.title(title)
    plt.imshow(img)
    plt.savefig("tmp.png")
    elice_utils.send_image("tmp.png")

def load_image(path, name):
    # TODO: [지시사항 1번] 이미지를 불러오는 함수를 완성하세요
    img = Image.open(os.path.join(path,name))
    return img
    
def main():
    data_path = "dataset/val/dogs"   
    
    
    # 이미지를 불러와 plt를 이용하여 출력합니다
    names = os.listdir(data_path)
    img = load_image(data_path, names[0])
    
    # 원본 이미지를 출력
    show_plot(img, "PIL original image")
    
    
    # TODO: [지시사항 2번] 지시사항에 따라 이미지의 크기를 확인하는 코드를 완성하세요.
    # PIL을 통해 이미지 크기 확인
    pil_size =img.size
    print("PIL을 통한 이미지 크기:", pil_size)
    
    # PIL 이미지를 numpy 배열로 변환
    np_img = np.array(img)
    
    # numpy 배열의 shape 확인
    np_shape = np_img.shape
    print("numpy 배열 shape:", np_shape)
    show_plot(np_img, "Numpy array image")
    
    # TODO: [지시사항 3번] PIL과 numpy를 이용하여 이미지를 다루는 코드를 완성하세요.
    # PIL.Image에서 x=10, y=20 의 픽셀값 가져오기
    pil_pix = img.load()[10, 20]
    
    # numpy 배열에서 x=10, y=20 의 픽셀값을 가져오세요
    np_pix =np_img[20,10]
    print("PIL의 픽셀값: {}, numpy의 픽셀값: {}".format(pil_pix, np_pix))
    
    # PIL을 이용하여 이미지의 크기를 (224,224)로 변형하세요.
    resized_img = img.resize((224,224))
    
    # resize된 이미지 출력
    show_plot(resized_img, "Resized image")
    print("resize 결과 사이즈:", resized_img.size)
    
    return pil_size, np_img, np_shape, np_pix, resized_img

if __name__ == "__main__":
    main()

커스텀 데이터셋 불러오기

대용량의 데이터셋은 한번에 메모리에 불러오는 것이 불가능합니다.

대용량의 데이터셋을 학습에 사용할 경우에는 해당 데이터를 사용할 때만 메모리에 불러오는 방법을 사용합니다.

다행히도 tensorflow에서는 이 과정을 수행하는 함수를 제공하고 있습니다.

Tensorflow에서 제공하는 ImageDataGenerator는 데이터셋을 불러오는 기능과 데이터 증강을 적용하는 기능을 제공합니다.

본 실습에서는 개와 고양이로 구성된 데이터 셋을 불러오고 간단한 전처리 과정을 추가하는 방법에 대해 실습하겠습니다.

데이터는 dataset 폴더에 학습 데이터로는 개와 고양이의 사진을 각각 100장씩 준비했으며 검증데이터로는 각각 20장씩 준비했습니다.

지시사항
ImageDataGenerator는 입력 이미지의 픽셀값을 모두 0에서 1사이로 정규화해주는 과정을 추가할 수 있습니다.

정규화를 수행하지 않는 것과 수행하는 것을 각각 만들어 먼저 비교해보고, 이후 실제 데이터셋을 불러와 각각 학습용과 검증용 ImageDataGenerator를 생성해보겠습니다.

정규화를 수행하지 않는 ImageDataGenerator()를 만드세요.
ImageDataGenerator()에 파라미터를 아무것도 전달하지 않으면 됩니다.

정규화를 수행하는 ImageDataGenerator()를 만드세요.
이미지의 각 픽셀값은 0에서 255 사이의 값을 가지고 있습니다.
ImageDataGenerator의 rescale 파라미터에 각 픽셀값을 최대값 255로 나눠주도록 (1/255) 넣어주세요.

학습 데이터와 검증 데이터를 위한 ImageDataGenerator를 만드세요.
둘 모두 픽셀값을 정규화 하도록 만드세요.
train_set의 경로는 dataset/train이 되도록 설정하세요.
valid_set의 경로는 dataset/val이 되도록 설정하세요.

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
data_path = "dataset"

batch_size = 2
img_height = 180
img_width = 180

# path의 데이터를 ImageDataGenerator로 불러와주는 함수
def get_dataset(path, datagen):
    data_set = datagen.flow_from_directory(path,
                                           target_size=(img_width, img_height),
                                           batch_size=batch_size,
                                           class_mode='categorical')
    return data_set

def main():
    # TODO: [지시사항 1번] 정규화 과정이 없는 ImageDataGenerator를 만드세요.
    first_gen = ImageDataGenerator()
    first_set = get_dataset(os.path.join(data_path, "val"), first_gen)
    x, y = first_set.__next__()

    print("\n1. 데이터 제너레이터 만들기")
    print("first_set")
    print("x: {}, y: {}".format(x.shape, y.shape))
    print(x[0][0][0]) # 픽셀이 0~255의 값을 가짐

    # TODO: [지시사항 2번] 픽셀값을 0~1의 값으로 정규화 하는 ImageDataGenerator를 만드세요.
    second_gen = ImageDataGenerator(rescale=1/255)
    second_set = get_dataset(os.path.join(data_path, "val"), second_gen)
    x, y = second_set.__next__()    
    
    print("\n2. 데이터 제너레이터에 정규화 추가하기")
    print("second_set")
    print("x: {}, y: {}".format(x.shape, y.shape))
    print(x[0][0][0]) # 픽셀이 0~1의 값을 가지는 것을 확인하세요

    # TODO: [지시사항 3번] 실제 학습을 위한 ImageDataGenerator를 만드세요.
    # 학습 데이터를 위한 ImageDataGenerator를 만드세요.
    train_gen =ImageDataGenerator(rescale=1/255)
    
    # 학습 데이터셋을 불러오도록 경로명을 설정하세요.
    train_set = get_dataset(os.path.join(data_path, "train"), train_gen)

    # 검증 데이터를 위한 ImageDataGenerator를 만드세요.
    valid_gen = ImageDataGenerator(rescale=1/255)
    
    # 검증 데이터셋을 불러오도록 경로명을 설정하세요.
    valid_set = get_dataset(os.path.join(data_path, "val"), valid_gen)

    print("\n3. 실제 학습을 위한 데이터 제너레이터 작성")
    print("학습 데이터의 길이: ", len(train_set))
    print("검증 데이터의 길이: ", len(valid_set))
    
    return first_gen, second_gen, train_gen, train_set, valid_gen, valid_set

if __name__ == "__main__":
    main()
profile
코딩으로 빛나게

0개의 댓글