백지에서 새로운 기능을 구현하는것은 어렵습니다.
그렇게 느끼는 가장 큰 이유는 어디서부터 시작해야할지 모르기 때문입니다. 우리가 지금까지 20여 년에 걸쳐 뭔가를 해결해본 경험들 중 가장 많은 비중을 차지했던건 단순한 문제들이었습니다. 그래서 저는 이전 포스팅에서 구현하고자 하는 기능을 머리 속에만 담지 말고 그 기능들을 분할하고 클래스별로 역할을 나누라는 제안을 했습니다. 그러나 클래스별로 역할을 나눠도 사실 뭔가를 하기에는 딱히 답이 나오지 않습니다. 그래서 또 하나의 제안을 하겠습니다.
구현하고자 하는 기능을 문제로 만드세요.
구현하고자 하는 기능을 문제로 만들어보면 프로그램을 제작하는데 접근하는 시각이 조금 달라집니다. 일단 '문제' 라는 건 우리가 오랫동안 풀어왔던 그 문제의 언어 형식과 비슷하기 때문에 조금은 더 친근하게 다가 올 수 있습니다.(친근하다고 했지 쉽다고는 안했습니다.) 또한 문제를 만드는 과정에서 그 문제를 어떻게 해결해야하는지에 관한 실마리를 얻을 수도 있습니다.
여기, 우리가 구현하고자 하는 핵심 로직에 대해 일단 말로 한 번 풀어보겠습니다.
배경화면이 8장이 있고, 이걸 하루에 걸쳐 시간에 따라 천천히 변해야 한다.
이제 이걸 하나의 문제로 표현을 바꿔보겠습니다.
배경화면이 8장이 있고, 이걸 하루에 걸쳐 꾸준히 변경되게 해야한다. 8장의 배경화면을 사용한다면 배경화면을 3시간에 1번 주기로 바꾸면 되지만, 배경화면을 갑자기 바꾸면 색에 변화가 크다. 따라서 부드럽게 바뀌도록 배경화면들을 합성해서 표시해야 하는 로직을 구현하시오.
여기서 눈여겨 봐야 할 것은 배경화면이 부드럽게 바뀌도록 해야 한다는 겁니다. 이제 핵심 로직에서 구현해야 할 사항들을 정리해봅시다.
1. 현재 시간 확인하기
2. 배경화면 파일 리스트로 불러오기
3. 배경화면 합성하기
4. 배경화면 설정하기
이정도면 핵심 기능을 만들 수 있을 것 같습니다. 이제 단계별로 기능들을 구현해봅시다.
import os, cv2, time, ctypes
class Main: # 시간에 따라 배경화면을 변경하는 Main 클래스를 선언합니다.
def __init__(self, abs_path): # 파일이 존재하는 절대 경로를 인자로 받습니다.
self.abs_path = abs_path # 클래스 내에서 abs_path를 사용할 수 있도록 합니다.
self.wallpaper_list = [] # 배경화면이 존재하는 목록을 저장하는 리스트를 선언합니다.
self.wall_type = None # 설정할 배경화면의 타입(Catalina or Mojave)
self.current_picture = None # 현재 배경화면의 이름
self.previous_picture = None # 이전 배경화면의 이름
self.mix = 0 # 위의 두 배경화면을 합성할 비율을 선언합니다.
0. 선언 단계 | 선언 단계에서는 필요한 모듈을 불러오고 Main 클래스를 선언합니다.
os모듈은 윈도우 시스템 관련 필요한 변수들을 __init__함수에 저장해줍니다.
# 파일이 존재하는 위치에서 배경화면 파일 리스트 불러옵니다.
def get_wallpaper_label(self): # 사용하고자 하는 배경화면의 버전을 선택합니다. 여기에서는 일단 Catalina를 기본으로 합니다.
os.chdir(self.abs_path) # 절대 경로로 이동합니다.
# wallpaper/catalina 경로가 존재하고, 인자로 Catalina를 받았다면 아래의 코드 실행
if self.wall_type == 'Catalina' and os.path.exists('./wallapaper/Catalina'):
return os.listdir(self.abs_path + '\\wallpaper\\Catalina') #경로 내 존재하는 파일들의 이름을 리스트로 받아서 반환합니다.
else:
print('requirement is not fulfilled.')
return []
1. 배경화면 리스트 불러오기 | 배경화면이 저장된 곳에서 배경화면 파일들을 불러와서 리스트에 저장합니다.
# 사진 불러오고 합성하는 핵심 기능 담겨있습니다.
def change_background_catalina(self, wall_type, apply_now=False): 인자로 wall_type과 apply_now를 받습니다.
self.wall_type = wall_type
self.wallpaper_list = self.get_wallpaper_label()
현재 시간과 자정 이후부터 몇 분이나 경과되었는지 구합니다.
hour = time.localtime().tm_hour
min = time.localtime().tm_min
sec = time.localtime().tm_sec
elasped = min + hour * 60
#이미지가 8장이고, 이미지들은 180분마다 변합니다.
#이미지를 합성해서 이미지가 18분마다 변하도록 하겠습니다.
# 매 18분 마다 이미지의 비율을 확인하고 변경합니다.
if (elasped % 18 == 0) and sec < 3 or apply_now == True:
os.chdir(self.abs_path)
self.mix = (elasped - (hour // 3) * 180) * 10 / 18 # 비율 값을 정합니다. 3시간동안 0에서 100까지의 값이 반복됩니다.
print('배경화면을 변경합니다. time {}:{}, elasped :{} cur : {} {}%, prev :{} {}%'
.format(hour, min, elasped, self.current_picture, int(self.mix), self.previous_picture,
int(100 - self.mix)))
# 시간 경과에 따라 이미지 합성을 수행합니다.
# 현재 시간 간격에 해당하는 이미지와 이전 시간 간격에 해당하는 이미지 파일 이름을 구합니다.
self.current_picture = self.wallpaper_list[(hour // 3)]
self.previous_picture = self.wallpaper_list[(hour // 3) - 1]
# 이미지들이 있는 경로를 구합니다.
cur_pic_path = self.abs_path + '\\wallpaper\\Catalina\\' + self.current_picture
prev_pic_path = self.abs_path + '\\wallpaper\\Catalina\\' + self.previous_picture
#OpenCV를 통해 이미지를 불러옵니다.
cur_pic = cv2.imread(cur_pic_path)
prev_pic = cv2.imread(prev_pic_path)
# 이미지별로 가중치를 주어 합성을 수행합니다.
# 합성된 이미지는 현재 이미지*(self.mix %)와 이전 이미지 *(100-self.mix)%로 이루어져 있습니다.
weighted_img = cv2.addWeighted(cur_pic, float(self.mix) / 100, prev_pic, float(100 - self.mix) / 100, 0)
# 이미지를 저장합니다.
os.chdir('./wallpaper')
t1 = time.time()
cv2.imwrite('catalina_processed.jpg', weighted_img)
t2 = time.time()
print('{}초 소요'.format(t2-t1)) # 합성에 소요된 시간을 구해서 현재 if문의 sec<5 값을 조절합니다. 그렇지 않으면 않으면 1분에 배경화면 설정이 수 십 번 이루어집니다.
self.apply_wallpaper()
os.chdir('../')
3. 배경화면 합성하기 | 배경화면을 절대 시간에 따라 하루 주기로 단순히 돌릴 수도 있지만, 여기에서는 OpenCV를 활용해서 배경화면들을 합성하고, 합성된 배경화면이 18분마다 적용되도록 했습니다. self.mix 변수는 3시간 주기로 0에서 100까지 늘어납니다. 예를 들어 현재 시간이 00:36 이면 self.mix는 20이 되고, 현재시간이 03:00이면 00이 됩니다.
# 합성한 이미지를 배경화면으로 설정합니다.
def apply_wallpaper(self):
os.chdir(self.abs_path)
os.chdir('./wallpaper')
wallpaper_path = os.getcwd() + r'\catalina_processed.jpg'
ctypes.windll.user32.SystemParametersInfoW(0x14, 0, wallpaper_path, 0x3) # SystemParametersInfoA
4. 배경화면 설정하기 | 배경화면을 설정합니다. ctypes 모듈을 이용해서 배경화면을 설정할 수 있도록 합니다.
if __name__ == '__main__': # .py 파일을 직접 실행할 경우 본 if 문 아래의 코드가 실행됩니다.
abs_path = os.getcwd() # 현재의 절대 경로를 얻습니다.
main = Main(abs_path)
initial_apply = True # 실행 즉시 배경화면이 적용되도록 합니다. 그렇지 않으면 배경화면 적용을 위해 최대 18분까지 기다려야 할 수도 있습니다.
while True: # 무한루프를 돌면서 시간에 따라 배경화면을 적용합니다.
main.change_background_catalina(apply_now=initial_apply)
initial_apply = False
클래스가 실행되는 부분입니다. 이정도까지 코드를 짰으면 실제로 배경화면이 적용되는지 확인해보기 위해 아래의 링크에서 Catalina 배경화면을 받아 (파이썬 코드가 실행되는 경로)/wallpaper/Catalina 에 저장해 주고 코드를 실행하면 정상적으로 실행되는 것을 볼 수 있습니다.
글이 도움이 되셨다면 왼쪽 아래의 공감버튼과 광고 클릭 부탁드립니다. 고마움을 표현할 수 있는 가장 쉬운 방법입니다.
감사합니다.