728x90

스파르타 코딩클럽의 딥러닝 이미지 처리 수업을 기반으로 공부한 내용을 정리하고 있습니다.

 

이미지 처리를 활용한 서비스를 만들기에 앞서, 이 이미지 처리에 도와줄 딥러닝 모델들이 필요하다.

이 모델들의 경우도 딥러닝의 다양한 학습 방식을 통해서 만들어지지만, 우선 이미 만들어진 딥러닝 모델들로 이미지 처리 하는 법에 대해서 정리해 보려 한다!

 

우선 이미지 처리를 위해서는 Numpy 모듈이 필요하다. 이 모듈을 import 해오자.

1
import numpy as np
cs

해당 모듈은 다차원 배열의 연산을 도와주는 패키지이며, pandas와 함께 데이터 분석 및 시각화에 많이 활용되고 있다.

실제로 존재하는 다양한 데이터들은 이미지, 오디오 등 다양한 형태이며, 이를 컴퓨터가 읽을 수 있도록 숫자 형식으로 변환해 주어야 한다. 

물론 파이썬에 내장되어 있는 list라는 패키지를 써도 되지만, 데이터의 수가 방대해 지면 내장된 패키지로도 힘들기 때문에 numpy 패키지를 써주는 것이다.

 

그리고 이미지 처리에 쓰일 딥러닝 모델을 불러와야 한다.

1
2
3
#딥러닝 모델을 불러오기
#변수명 = cv2.dnn.readNetFromTorch('불러오고자 하는 모델파일명과 위치)
net = cv2.dnn.readNetFromTorch('활용하려는 모델 파일명 및 위치')
cs

-> cv2의 dnn 모델을 사용하는데, 해당 모델을 Torch로부터 읽는 다는 것이다. Torch는 딥러닝 프레임 워크 중 하나이다. 

즉 Torch로 만들어진 모델을 읽어오는 것이다.

 

그리고 처리를 하려는 이미지를 불러온다. 이는 블로그에 정리한 이미지처리 기본의 글을 참고하면 된다.

 

이미지 전처리하기

이렇게 필요한 모듈을 import하고, 모델을 불러오고 처리하려는 이미지를 출력한 다음에는 이미지 전처리 과정을 거치면 된다.

 

여기서 이미지 전처리란 무엇일까?

이미지라는 데이터는 단편적으로 보이지만, 실제로 매우 많은 데이터를 가지고 있다. 따라서 이를 한 번 가공해주는 과정을 거쳐야만 컴퓨터가 좀 더 효율적으로 분석할 수 있게 된다. 즉, 이미지 내에서 불필요한 데이터를 줄이고 유의미한 데이터를 정제하는 과정이 필요하고 이때 전처리 알고리즘을 사용한다. 전처리 과정이란 이미지 처리 시에 사용되는 알고리즘을 좀 더 효율적으로 활용하기 위해 유의미한 정보로 가공하는 과정이다. 

간단히 말하면 이미지를 조작하는 과정이다. 이를 통해 딥러닝 모델의 정확도 즉 성능을 높일 수 있는 것이다. 

전처리는 다양한 방법이 존재한다. 

 

**전처리 코드

(처리하려는 이미지를 읽는 코드와 출력하는 코드 사이에 코드를 기입한다.)

1
2
3
4
5
6
7
8
#전처리 관련 코드
h, w, c = img.shape
 
img = cv2.resize(img, dsize=("변경하고자하는 사이즈", int(h / w * "변경하고자 하는 사이즈")))
 
MEAN_VALUE = [103.939116.779123.680]
blob = cv2.dnn.blobFromImage(img, mean=MEAN_VALUE)
 
cs

 

-> img.shape 로 이미지의 높이, 너비, 채널을 받을 수 있다. 각 높이(h), 너비(w), 채널(c)을 변수 h,w,c에 담아둔다.

-> 그리고 이 이미지를 너비 X로 이미지의 크기를 변형시킬 것이다. 즉 리사이징을 해줄 것이다. 이 코드가 4번째 줄 코드이다.

    비율을 유지하면서 이미지를 리사이징 하기 위해 해당 코드를 활용 했다.

    따라서 너비를 x로 리사이징 하면, 비례식을 활용 한다면, 높이는 h/w*x 가 되는 것이다. 리사이징한 높이가 소수점이 나올 수 있으므로,        int 처리 해주는 것이다.

   => ex) 너비 : 높이 = x : y -> 500 : new_y

               y*500 = x * new_y

              new_y = y/x*500

 

-> 여기서 MEAN_VALUE 는 연구원들이 사용했던 전처리 방법입니다.(즉 암기하자. 이미지 처리에 활용되는 어떠한 공식 중 하나)

 이미지 각 픽셀에 [103.939, 116.779, 123.680] 이 값을 빼서 성능을 높이는 것이다. 

-> cv2.dnn.blobFromImage 코드가 전처리 코드인데, 처리하려는 이미지를 img로 불러오고, MEAN_VALUE를 이미지의 각 픽셀에서 빼주면서 성능이 높아 지는 것이다.  또한 해당 코드를 통해 딥러닝 모델에 넣기 위한 이미지 데이터 차원 변형도 거치게 된다. 

그렇다면 어떻게 차원이 변형되는 것일까? 원래는 높이,너비,채널 의 형태인 이미지에서 데이터가 하나 더 추가되고, 데이터의 순서가 바뀌게 된다. 가령 채널이 앞으로 가는 것 처럼? 이렇게 변형이 되어서 컴퓨터가 더 잘 이해할 수 있게 되는 것이다.

차원 변형 후 (1, 채널, 높이, 너비) 모양에서 1은 딥러닝에서 배치 사이즈를 의미합니다. 딥러닝 모델을 학습시키는 과정에서 이미지를 한 장씩 학습시키지 않고 여러 이미지를 한꺼번에 학습시키죠. 만약 이미지를 32개씩 묶어서 학습시킨다면 배치 사이즈는 32가 됩니다. (32, 채널, 높이, 너비) 
여기서 나는 1개의 테스트 이미지를 사용할 것이므로 배치 사이즈가 1이 됩니다. 따라서 (1, 채널, 높이, 너비) 형태가 되는 것입니다.

 

이미지 추론 결과 보고 후처리 하기

이미지 추론 결과

1
2
3
net.setInput(blob)
output = net.forward()
 
cs

-> 전처리한 이미지(blob)를 모델에 넣고(setInput) 추론(forward)합니다. output 변수에 추론한 결과가 저장됨.

 

이렇게 저장된 추론값을 다시 우리가 볼 수 있도록 이미지로 변경되는 과정을 거쳐야 하는데 이것이 후처리 이다.

**후처리 코드

1
2
3
4
5
output = output.squeeze().transpose((120))
output += MEAN_VALUE
 
output = np.clip(output, 0255)
output = output.astype('uint8')

cv2.imshow('result', output)

cs

전처리했던 과정을 거꾸로 진행하면 된다.

 

-> 차원 줄이기 차원 변형했던 것을 원래대로 (높이, 너비, 채널) 순으로 다시 되돌려 놓는다.

  squeeze() 를 사용하여 추가했던 첫 번째 차원을 삭제한다. (1, 채널, 높이, 너비)에서 (1, ) 부분을 없애고 (채널, 높이, 너비) 형태로 만듬.

-> 순서 바꾸기 : transpose()를 사용하여 (채널, 높이, 너비) → (높이, 너비, 채널) 형태로 변형한다.

 

-> 더하기 전처리 했을 때 MEAN_VALUE 를 뺐는데 후처리 할 때는 MEAN_VALUE를 다시 더해준다,

 

-> 범위 넘어가는 값 잘라내기

   MEAN_VALUE 더하고 나면 255의 이미지 범위를 넘어가는 경우가 발생하므로 해당 과정이 필요하다. 

    이미지 픽셀 값은 0-255 범위 안에 들어와야하는데 계산 과정에서 간혹 픽셀 값이 0 미만이거나 255를 초과하는 픽셀이 생기고,

    이런 값들을 np.clip()을 사용하여 없애줄 수 있다.

 

-> 자료형 바꾸기 마지막으로 이미지의 자료형을 일반 이미지에서 쓰이는 정수형(uint8)으로 바꿔준다.

-> 그리고 마지막 줄 코드를 통해 변형된 이미지를 출력 할 수 있다.

 

**결과 이미지

딥러닝 모델은 고흐의 별이 빛나는 밤에 였다. 해당 화풍을 내가 원하는 이미지에 씌워보는 이미지 처리를 진행해 본것!

 

 

+)이미지 출력 시 waitKey 활용하기

일반적으로 이미지 창이 떠있고 이를 다시 닫게 하기 위해서 사용되는 메소드가 waitKey이다. 

보통 항상 떠있고, 키보드 아무 버튼을 누르면 꺼지게 하는 것을 사용하고 이것이 cv2.waitKey(0) 이다.

그리고 cv2.waitKey(1) == ord('q') 를 통해, q 버튼을 누르면 꺼지게 하는 기능을 쓸수도 있다.

 

그렇다면 정확히 해당 메소드의 역할은 무엇이고 어떻게 사용하는 것일까?

정확히는 입력 대기 키라고 부르며, 인자를 비워두거나 0인 경우, 키 입력이 있을 때 까지 무한정 기다리게 된다. 즉 imshow 명령어를 시행한 이후에 특정 키 입력이 있을 때 까지 해당 명령을 계속 이행하는 것이다.

 

그리고 숫자의 의미는 ms로 1초 = 1000 이다.

cv2.waitKey(1) == ord('q') 해당 코드의 경우 변수 1은 의미가 없고, 비워두고 ord의 변수에 특정 키워드를 입력하면 그 키값의 입력을 기다리게 되는 것이다. 참고로 esc 키의 경우 Ascii Code로 27이므로, cv2.waitKey() == ord(27) 로 입력하면 된다.

 

 

 

Reference

 

numpy 모듈이란? brownbears.tistory.com/480

이미지 전처리란? 076923.github.io/posts/ComputerVision-6/

 

728x90

+ Recent posts