본문 바로가기

개발/Python

[Python] argparse 기본 사용법(feat. 이미지 처리 프로그램)

"argparse, python 프로그램의 자유도의 날개를 달아줘요!"

 

최근 몇 달 간 python으로 이미지를 처리하는 코드를 짤 일이 많았다.

그 때마다, 매 번 코드에 있는 이미지 경로 이름을 바꿔가며 작성한 코드를 실행했었다. 어느 정도 시행 착오를 겪어가며 작성한 코드였기 때문에 이미지 경로만 다르게 넣어주면 되는데, 이 경로명을 일일히 IDE(visual studio code를 사용하고 있다.)를 켜서 수정하고 다시 실행하고 하는 것이 너무너무 귀찮았다.

 

#IMAGE_DIR = './Desktop/image1/'
#IMAGE_DIR = './Desktop/image2/'
#IMAGE_DIR = './Desktop/image3/'
#IMAGE_DIR = './Desktop/image4/'
#IMAGE_DIR = './Desktop/image5/'
#IMAGE_DIR = './Desktop/image6/'
IMAGE_DIR = './Desktop/image7/'

image_processing(IMAGE_DIR)

 

위에 보이는 것처럼 코드를 계속 수정하면서!

새로운 작업 요청이 들어올 때마다 VS code를 켜고, 이미지 처리 프로그램을 켜고, 이미지 경로를 수정하고, 실행하고... 과정의 반복이었다.

 

그렇게 귀찮음에 짜증 지수가 쭉쭉 올라가던 내게, argparse가 나타났다. 

https://docs.python.org/ko/3/library/argparse.html # argparse에 대한 자세한 내용은 api 문서를 참고하자!

argparse는 터미널 상에서 파이썬 코드를 실행할 때 main 함수에 전달되는 인자들을 코드 내에서 사용할 수 있도록 해주는 모듈이라고 생각하면 편하다. 코드 내에서 활용되는 내부 변수들을 사용자에게 편하게 입력 받아 사용할 수 있다.(이후에 나올 코드를 보면 이해가 빠르다!)


지금부터 argparse를 사용한 간단한 이미지 처리 프로그램을 같이 작성해보며 사용법을 살펴보도록 하자!

 

우선 이미지 처리 프로그램은 다음과 같은 3가지 요구사항을 만족시키기 위한 프로그램으로 한다.

  1. RGBA 채널을 RGB 채널로 바꾼다! (고정)
  2. 이미지의 크기를 원하는 width, height로 바꾸고 싶다!
  3. 이미지 저장 방식을 원하는 대로(.png, .jpg, ...) 바꾸어 저장하고 싶다!

처리할 이미지들은 코드가 위치하는 경로 내에 폴더를 만들어 저장한다. 원하는대로 입맛에 맞게 수정하면 된다.

우선, argparse 없이 이미지 처리를 진행하는 코드를 작성해보자. 

cv2를 사용할 수도 있지만 나는 PIL을 활용하여 이미지 처리를 진행할 것이다.

 

# without_argparse.py
from PIL import Image
import os

ROOT_DIR = './images/'
SAVE_DIR = './results/'
IMG_TYPE = '.jpg'
WIDTH = 250
HEIGHT = 250

if __name__ == '__main__':

    if not os.path.isdir(SAVE_DIR):
    	os.mkdir(SAVE_DIR)
    
    images = os.listdir(ROOT_DIR)
    
    for image in images:
    	img = Image.open(ROOT_DIR + image).convert('RGB')
        img_name = image.split('.')[0]
        
        resized_img = img.resize((WIDTH, HEIGHT))
        
        resized_img.save(SAVE_DIR + img_name + IMG_TYPE)

 

argparse 없이 이미지를 처리하는 코드 전문이다.

전역 변수로 선언한 이미지 저장 경로와 변환한 이미지를 저장할 경로, 이미지 저장 타입, 이미지의 크기를 저장한다.

코드는 우선 저장할 경로가 존재하지 않는다면 폴더를 생성한 후 이미지가 저장된 경로에서 이미지 이름을 읽어 RGB 채널로 이미지를 변환하여 읽어들인다.

이미지 타입의 변환을 위해 이미지의 이름만 따로 img_name 변수에 할당한다.

이후 원하는 크기로 이미지의 크기를 변환한 후 원하는 경로와 타입에 저장한다.

 

이렇게 코드를 작성할 경우 이미지 저장 경로와 변환 이미지 저장 경로, 이미지 타입, 가로와 세로를 변환하기 위해서는 매 번 코드를 수정해야 하는 단점이 있다. 단순히 일회성으로 활용할 코드라면 굳이 argparse를 쓸 필요 없이 위와 같이 작성해서 사용하면 된다.

하지만 나는 1,500여 장의 이미지가 저장된 서로 다른 20개의 폴더에 있는 이미지에 대한 처리를 하고 싶었다. 나와 같이 이미지 처리를 반복적으로 수행하는 작업을 할 때는 이렇게 매 번 경로를 바꾸는 것이 여간 귀찮은 일이 아니다.

요즘 머신 러닝/딥 러닝 코드에서도 많이 사용한다. 데이터 셋이 저장된 경로와 하이퍼 파라미터, 학습 완료된 모델 구조를 저장하는 경로를 사용자가 지정할 수 있도록 argparse를 통해 많이 사용한다.

 

그렇다면 이 코드를 argparse를 활용하여 수정하면 어떻게 될까

 

# with_argparse.py
from PIL import Image
import os
import argparse

ROOT_DIR = ''
SAVE_DIR = ''
IMG_TYPE = ''
WIDTH = 0
HEIGHT = 0

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--root_dir', type=str, default='./images/', help='변환하고자 하는 이미지가 저장된 경로')
    parser.add_argument('--save_dir', type=str, default='./results/', help='변환한 이미지를 저장하고자 하는 경로')
    parser.add_argument('--img_type', type=str, default='.jpg', help='저장하려는 이미지 확장자')
    parser.add_argument('--width', type=int, default=250, help='변환하려는 이미지의 가로')
    parser.add_argument('--height', type=int, default=250, help='변환하려는 이미지의 세로')
    
    opt = parser.parse_args()
    
    ROOT_DIR = opt.root_dir
    SAVE_DIR = opt.save_dir
    IMG_TYPE = opt.img_type
    WIDTH = opt.width
    HEIGHT = opt.height

    if not os.path.isdir(SAVE_DIR):
    	os.mkdir(SAVE_DIR)
    
    images = os.listdir(ROOT_DIR)
    
    for image in images:
    	img = Image.open(ROOT_DIR + image).convert('RGB')
        img_name = image.split('.')[0]
        
        resized_img = img.resize((WIDTH, HEIGHT))
        
        resized_img.save(SAVE_DIR + img_name + IMG_TYPE)

 

코드 자체의 길이는 길어졌지만 코드를 한 번 작성해두면 사용자가 입력할 옵션들의 값을 다시 수정할 필요가 없다!

그렇다면 이 코드는 어떻게 실행할까?

 

python with_argparse.py --root_dir ./another_images/ --save_dir ./another_results/ --img_type .png --width 100 --height 100

 

위와 같은 형태로 parser에 정의한 파라미터의 명을 적고 입력하고 싶은 값을 직접 입력하면 된다!

이렇게 되면 코드 내에 할당한 변수에 우리가 입력한 값이 할당되어 마치 변수에 직접 값을 입력한 것처럼 사용할 수 있게 되는 것이다!

입력을 하지 않아도 된다! default 값을 지정해두었기 때문에 별도로 입력을 하지 않을 경우 default에 할당되어 있는 값을 사용하게 된다.

 

이렇게 코드 실행마다 달라지는, 코드 전체에서 사용되는 값들을 argparse를 활용하여 지정해둘 경우 터미널에서 입력하는 것을 통해 쉽게 실행할 수 있다.

argparse의 또 하나의 큰 장점이 존재한다.

 

argparse의 또 다른 큰 장점

바로 --h를 통해 지정한 속성들의 help를 다른 사람들이 쉽게 확인할 수 있다는 점이다.

내가 작성한 코드를 다른 사람들이 쉽게 실행할 수 있다는 점이 이 모듈의 장점이라고 생각한다.


내가 느낀 argparse의 장점에 대해서 정리하자면

  1. 고정되어 있지 않은 경로명과 같은 변수들을 많이 사용할 때 유용하다.
  2. 다른 사람들이 내가 작성한 코드를 쉽게 사용할 수 있다. - 코드의 실행 방법을 안내하기도 더 쉽다! 문서 작성이 용이!
  3. 프로그램 실행할 때 있어보인다..!(장난장난)

단점이라면 프로그램을 실행할 때 쳐야 하는 것이 많아진다는 것? 하지만 README에 적어두고 복사-붙여넣기 해서 필요한 부분만 수정해서 쓰면 크게 불편하지 않다.

 

argparse를 알게 되고 본격적으로 사용한 지 얼마 안되기도 했고, 베포를 위한 파이썬 프로그램을 잘 작성하지 않는 편이기도 해서 이 포스팅을 통해 argparse에 모든 것을 소개했다! 라고 할 수는 없지만 적어도 보시는 분들께서 한 번쯤은 사용해보셨으면 하는 바람을 남기며 이번 포스팅을 닫도록 하겠다!

반응형