나른한 코딩 생활

[24일차] ABC 부트캠프 이미지 필터링 및 학습 본문

ABC 부트캠프

[24일차] ABC 부트캠프 이미지 필터링 및 학습

GerHerMo 2024. 7. 28. 18:21

지금까지는 csv 및 함수와 같은 데이터셋을 가지고 머신러닝을 진행했었다.

 

오늘은 다양한 이미지를 여러가지 방법으로 필터링 해보고 이에 따른 머신러닝을 예제를 통해 공부해보자


Rose - 장미 이미지 필터링

# 24.07.25 목요일
import cv2
import numpy as np
img = cv2.imread(filename='Rose.jpeg',flags=cv2.IMREAD_GRAYSCALE)
# jpg : 손실 압축 / png : 무손실 압축 + 투명도 채널 추가
# Lenna_515x512.png 와 Rose.jpeg 번갈아 확인
cv2.imshow(winname="Rose", mat=img)
cv2.waitKey() #  창을 닫지 마라
cv2.destroyAllWindows() # 창을 없애라
# filter =(3,3)
'''
filter = [[-1,-1,0],
          [-1,0,1],
          [0,1,1]]
'''
kernel = np.array([[-1, -1, 0],
                   [-1, 0, 1],
                   [0, 1, 1]])
kernel2 = np.array((-1,-1,0,-1,0,1,0,1,1))
# 두 방법 모두 가능 kernel2 는 np.array() 를 제거해도 작동은 함
dst = cv2.filter2D(img, -1, kernel2)
cv2.imshow(winname='FILTER',mat=dst)
cv2.waitKey()
cv2.destroyAllWindows()

좌측 : Rose.jpeg 원본 / 중간 : img(GreyScale) / 우측 : cv2.imshow(winname=FILTER,mat=dst)

 


Lenna - 인물 사진 정규화

원본 Lenna 이미지는 다음과 같다

Lenna_512x512.png

import cv2
img = cv2.imread(filename='Lenna_512x512.png',flags=cv2.IMREAD_GRAYSCALE)
(minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(img)
print(minVal, maxVal, minLoc, maxLoc)
# 39.0 245.0 (510, 68) (117, 272)
# 이미지의 제일 우측최하단의 좌표가 (512,512) 이다
dst = cv2.normalize(src=img,dst=None,alpha=100,beta=255,
                    norm_type=cv2.NORM_MINMAX)
(minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(dst)
# 100.0 255.0 (510, 68) (117, 272)
print(minVal, maxVal, minLoc, maxLoc)
cv2.imshow('LENNA',img)
cv2.imshow(winname='NORM',mat=dst)
cv2.waitKey()
cv2.destroyAllWindows()

좌측 : GrayScale 한 Lenna 이미지 / 우측 : 좌측 이미지를 alpha=100, beta=255로 정규화시킴


VGG19 NetWork - 사물 이미지 학습 및 예측

VGG19 구조

VGG19은 19개의 층으로 이루어져 있음. 이 중 16개는 합성곱층(conv layer)이고, 3개는 완전 연결층(fully connected layer)임. 주요 구성 요소는 다음과 같음:

  1. 합성곱층:
    • 3x3 크기의 필터를 사용해 이미지를 처리함. 필터 개수는 네트워크가 깊어질수록 증가함.
    • 필터 개수는 처음에는 64개로 시작해서 128개, 256개, 512개로 늘어남.
    • 각 합성곱층 뒤에는 ReLU 활성화 함수가 적용됨.
  2. 최대 풀링층:
    • 2x2 크기의 필터와 스트라이드 2를 사용해 이미지 크기를 줄임.
    • 총 5개의 풀링층이 있고, 각 합성곱 블록(conv block) 뒤에 배치됨.
  3. 완전 연결층:
    • 마지막에 3개의 완전 연결층이 있고, 첫 두 개는 각각 4096개의 유닛을 가짐.
    • 마지막 층은 분류할 클래스 수에 따라 유닛 수가 달라짐 (예: ImageNet 데이터셋의 경우 1000개 클래스).
  4. Softmax 층:
    • 최종 출력에서 각 클래스의 확률을 계산하기 위해 Softmax 함수를 사용함.

VGG19의 특징

  • 단순한 구조: VGG19은 규칙적인 구조로 되어 있어 이해하고 구현하기 쉬움.
  • 높은 성능: 깊이 있는 구조 덕분에 이미지 분류 성능이 좋음.
  • 전이 학습: 사전 학습된 모델을 사용해 다른 데이터셋에 쉽게 적용할 수 있음.

VGG19의 단점

  • 큰 모델 크기: 깊은 구조로 인해 파라미터 수가 많아 메모리 사용량이 크고, 학습과 추론 속도가 느릴 수 있음.
  • 높은 연산 비용: 많은 합성곱층과 완전 연결층으로 인해 연산 비용이 높음.

VGG19은 이미지 인식과 분류에서 매우 유용한 모델로, 전이 학습을 통해 다양한 컴퓨터 비전 작업에서 성능을 향상시키는 데 자주 사용됨.

import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D, Dropout, Input

model = tf.keras.models.Sequential([])
'''
model.add(Conv2D(filters=64, kernel_size=(3,3),
          padding="same", activation="relu",
          input_shape=(224,224,3)))
model.add(Conv2D(filters=64,kernel_size=(3,3),
                 padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))
'''
model.add(Input(shape=(224, 224, 3)))  # Input shape 수정
model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same", activation="relu"))
model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Conv2D(filters=128,kernel_size=(3,3),padding="same", activation="relu"))
model.add(Conv2D(filters=128,kernel_size=(3,3),padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

model.add(Conv2D(filters=256,kernel_size=(3,3),padding="same", activation="relu"))
model.add(Conv2D(filters=256,kernel_size=(3,3),padding="same", activation="relu"))
model.add(Conv2D(filters=256,kernel_size=(3,3),padding="same", activation="relu"))
model.add(Conv2D(filters=256,kernel_size=(3,3),padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))


model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
# Dropout? : 계산량이 폭발적으로 증가할때 사용하면 좋긴함
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1000, activation='softmax')) # Assuming 1000 classes for classification
model.compile(optimizer=tf.keras.optimizers.Adam(0.003),
              loss='categorical_crossentropy')

# Print the model summary
model.summary()
# vgg19_weights_tf_dim_ordering_tf_kernels.h5 파일

model2 = model.load_weights('vgg19_weights_tf_dim_ordering_tf_kernels.h5')
import cv2
image1 = cv2.imread(filename='labtop.jpg')
# cv2.imshow("IMAGE1",image1)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
new_image1 = cv2.resize(image1,(224,224))
import numpy as np
new_image1 = new_image1[np.newaxis, :]
predict_image = model.predict(new_image1)
print(predict_image)
print(np.argmax(predict_image)) # 681

해당 코드에서 위 작업을 전부 수행하기에는 시간적인 여유가 없기에

vgg_weights_tf_dim_ordering_tf_kernels.h5 파일은 교수님의 파일을 사용하였다 

이미지 예측을 위한 예시 이미지 : laptop.jpg
classes.txt 내에 681은 notebook computer -> 예측성공


MRI - cbook 을 통한 사진 가져와 표시

import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import numpy as np

with cbook.get_sample_data('s1045.ima.gz') as dfile:
    im = np.frombuffer(dfile.read(), np.uint16).reshape((256,256))
fig, ax = plt.subplots(num="MRI_demo")
ax.imshow(im)
ax.axis('off')
plt.show()

's1045.ima.gz'


Weight - 값에 따른 이미지 변화

import cv2
image_1 = cv2.imread(filename='C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Image_1.jpg')
image_2 = cv2.imread(filename='C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Image_2.jpg')


def changing_weight_value(x: int)-> None:
    weight = x / 100 #weight 를 백분률 사용 0 ~ 1 사이의 값 (왜냐하면 트랙으로 입력 받는 값이 0 ~ 100)
    merged_image = cv2.addWeighted(src1=image_1, alpha=1 - weight, src2=image_2, beta=weight, gamma=0)
    cv2.imshow(winname="Display", mat=merged_image)
    return None

cv2.namedWindow(winname='Display')
cv2.createTrackbar('weight', 'Display', 0, 100, changing_weight_value)
cv2.waitKey(delay=0)
cv2.destroyAllWindows()

좌측 : 초기 실행시 / 중간 : weight 값이 매우 낮을경우 / 우측 : weight 값이 매우 높을경우
weight 값이 중간일 경우 이미지가 포개짐


이미지 필터링 - 필터에 따른 이미지 비교

import numpy as np
import cv2
original_image = cv2.imread(filename='C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Free_Image_6.jpg', flags=cv2.IMREAD_COLOR)
kernel1 = np.ones(shape=(3,3), dtype=np.float32) / 9
kernel2 = np.ones(shape=(9,9), dtype=np.float32) / 81

# 필터(weighted value)
average_image_3_by_3 = cv2.filter2D(src=original_image, ddepth=-1, kernel=kernel1)
average_image_9_by_9 = cv2.filter2D(src=original_image, ddepth=-1, kernel=kernel2)
cv2.imshow(winname="Original Image", mat=original_image)
cv2.imshow(winname="3by3 filtered", mat=average_image_3_by_3)
cv2.imshow(winname="9by9 filtered", mat=average_image_9_by_9)
cv2.waitKey(delay=0)
cv2.destroyAllWindows()

필터링 값이 클수록 이미지의 선명도가 달라지는 것을 확인할 수 있음


Threshold - 고양이 이미지 변화

임계값 처리(Thresholding): 이미지에서 픽셀 값을 특정 임계값과 비교하여, 그 값을 넘으면 하나의 값(예: 흰색), 넘지 않으면 다른 값(예: 검은색)으로 변환하는 방법임. 주로 이진화(binarization)라고도 함.

아래 코드엣어 사용할 Free_Image_12.jpg

import cv2
color_image = cv2.imread('C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Free_Image_12.jpg',
                         cv2.IMREAD_COLOR)
gray_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2GRAY)

def changing_threshold(x:int) -> None:
    (_, threshold_image) = cv2.threshold(src=gray_image,
                                         thresh=x,
                                         maxval=255,
                                         type=cv2.THRESH_BINARY)
    cv2.imshow(winname="Threshold Image", mat=threshold_image)
    return None

cv2.namedWindow("Threshold Image")
cv2.createTrackbar('THRESHHOLD', 'Threshold Image',
                   0, 255, changing_threshold)
# cv2.imshow('Threashold Image', gray_image)
cv2.waitKey()
cv2.destroyAllWindows()

맨좌측 : 초기 실행 // 이후 -> Threshold 값에 따른 고양이 이미지 변화


초 - 윤곽선 필터

import cv2
original_image = cv2.imread('C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Free_Image_10.jpg')
image_gray = cv2.imread(filename='C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Free_Image_10.jpg',
                        flags=cv2.IMREAD_GRAYSCALE)
edge_image = cv2.adaptiveThreshold(image_gray,255,
                                   cv2.ADAPTIVE_THRESH_MEAN_C,
                                   cv2.THRESH_BINARY,9,0) # C : -5 ~ 5 값 사용
cv2.imshow('Original Image', original_image)
cv2.imshow(winname="EDGE", mat=edge_image)
cv2.waitKey(0)
cv2.destroyAllWindows()


합성사진 만들기

아래는 원본 이미지 파일 두개이다 좌측이 배경 우측이 인물사진이다

좌 : Background_Image.jpg / 우 : Front_Image_jpg

# 합성사진 만들기
import cv2
import numpy as np
front_image = cv2.imread('C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Front_Image.jpg',cv2.IMREAD_COLOR)
background_image = cv2.imread('C:\ABCBootCamp\pythonProject_test\Example\Source_Codes\Background_Image.jpg',cv2.IMREAD_COLOR)

# 원본 이미지들 보기
# cv2.imshow(winname='Front Image',mat=front_image)
# cv2.imshow(winname='Background Image',mat=background_image)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

# 녹색 HSV 확인 // 녹색 HUE 찾은 후 빼기
image_hsv=cv2.cvtColor(src=front_image,code=cv2.COLOR_BGR2HSV)
green_lower_bound = np.array([40,100,50]) # 녹색의 하한선
green_upper_bound = np.array([80,255,255]) # 녹색의 상한선

# mask image
mask_image = cv2.inRange(src=image_hsv, lowerb=green_lower_bound, upperb=green_upper_bound)
cv2.imshow('Mask image', mat= mask_image)

# inverse image
inverse_mask_image = cv2.bitwise_not(mask_image)
cv2.imshow('Inverse mask image', mat= inverse_mask_image)

# 녹색 픽셀들만 추출하기
extract_green_pixels = cv2.bitwise_and(src1=front_image,src2=front_image,mask=mask_image)
cv2.imshow('Extract green image', mat=extract_green_pixels)

# 녹색 아닌 픽셀만 추출하기
not_extract_green_pixels = cv2.bitwise_and(src1=front_image,src2=front_image,mask=inverse_mask_image)
cv2.imshow('Not Extract green image', mat=not_extract_green_pixels)


# 녹색과 겹치는 배경 추출하기
extract_green_background_image = cv2.bitwise_and(
    src1=background_image, src2=background_image, mask=mask_image)
cv2.imshow('Extract green background image', mat=extract_green_background_image)

# 녹색 제거 전경 + 배경 추출하기 = 합성하기
merge_image = cv2.bitwise_or(
    src1=not_extract_green_pixels, src2=extract_green_background_image)
cv2.imshow('Merge image', mat=merge_image)
#cv2.imwrite("Fake_image.jpg", merge_image)
# 만든 merge_image 를 Fake_image 라는 이름으로 저장
cv2.waitKey()
cv2.destroyAllWindows()

Fake_Image.jpg