1.이미지 프로세싱
2.텍스트 프로세싱
#1. 이미지 프로세싱
복사해서 붙여넣기
왼쪽의 장영실 동상 그림을 오른쪽 배경 위에 올려봅시다.
def paste(canvas, img, x1, y1): => 배경, 동상, 붙이려는 픽셀
w, h = img.size()
for y in range(h):
for x in range(w):
canvas.set(x1 + x, y1 + y, img.get(x, y))
=> 붙이려는 픽셀의 x,y값 x1,y1에 img의 w,h만큼 픽셀 하나하나를
x,y에 for문으로 넣어 붙인다
=> 하지만 이 경우 동상 사진의 배경이 잘리지 않고 그대로 들어간다
크로마키
크로마키는 두 개의 영상을 합성하는 기술입니다.
한 영상의 특정 색을 투명하게 만들어서 뒤의 배경 영상을 비치게 할 수 있습니다.
이 기술은 일기 예보에서 많이 사용합니다.
색 차이
오른쪽 사진의 배경은 정확히 한 가지 색이 아닙니다
– 파란색을 띄는 비슷한 색일 뿐입니다.
두 색이 얼마나 비슷한지 알 수 있는 함수가 있으면, 함수를 통해
어느 부분이 사진의 배경인지 알 수 있습니다.
def dist(c1, c2):
r1, g1, b1 = c1
r2, g2, b2 = c2
return math.sqrt((r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2)
=> c1, c2의 색의 차이를 구하는 dist(c1,c2)
이 수식은 3차원 공간에서 두 점의 거리를 구하는 식과 같습니다.
크로마키
def chroma(img, key, threshold): => img 는 동상사진/ key는 파란색 픽셀
w, h = img.size()
for y in range(h):
for x in range(w):
p = img.get(x, y) => img.get(x,y) 는 해당 픽셀의 r,g,b를 구한다
if dist(p, key) < threshold: => 정해진 threshold과 차이가 적으면
img.set(x, y, Color.yellow)=> 노랑으로 바꾼다
이제 노란색 배경 대신, 배경 사진의 색을 이용하는 함수를 만들어 봅시다.
def chroma_paste(canvas, img, x1, y1, key): => 배경, 동상, x1,y1은 동상을 붙이기 시작할 픽셀 (왼,위), 색 비교대상(노랑색)
w, h = img.size()
for y in range(h):
for x in range(w):
p = img.get(x, y) => p는 동상 사진의 각 픽셀
if p != key: => rgb가 비교대상과 다르면
canvas.set(x1 + x, y1 + y, p) => 시작점으로부터 모든 픽셀은 p(동상의 rgb로 바뀐다)
정보 은닉
사람은 색의 작은 차이를 거의 인지하지 못합니다.
이 현상은 사진 안에 어떤 정보를 숨기는 데 사용할 수 있습니다.
다음은 사진 img 안에 흑백 사진을 숨기는 알고리즘입니다.
* img의 모든 픽셀 (r,g,b)에서, r이 홀수면 1을 뺍니다. => img의 모든 픽셀의 r을 짝수로 만든다
* 흑백 사진의 검정색 픽셀과 동일한 위치에 있는 img의 모든 픽셀을 찾아, 픽셀의 r에 1을 더합니다. => 숨기려는 사진의 검은 부분을 홀수로 만든다
이 숨겨진 흑백 사진은 img의 모든 픽셀 (r,g,b)에서 r이 홀수면 해당 픽셀을 검정색으로, 짝수면 하얀색으로 바꿔서 얻을 수 있습니다.
정보 은닉 예제
정보 숨기기 (1/2)
정보 숨기기 (2/2)
정보 숨기기 코드 (1/2)
# hide bwimg into img
def hide_picture(canvas, img, bwimg): => 동상, 숨기려는 사진
w, h = img.size()
for y in range(h):
for x in range(w):
r, g, b = img.get(x, y)
if r % 2 == 1:
r = r - 1 => 동상의 r이 홀수면 짝수로
img.set(x, y, (r, g, b))
black = (0, 0, 0)
for y in range(h):
for x in range(w):
r, g, b = img.get(x, y)
if bwimg.get(x, y) == black: => 숨기려는 사진의 해당 픽셀의 검은색이면 r을 짝수로
r = r + 1
canvas.set(x, y, (r, g, b))
정보 숨기기 코드 (2/2)
white = (255, 255, 255)
black = (0, 0, 0)
def restore_picture(canvas, img):
w, h = img.size()
for y in range(h):
for x in range(w):
r, g, b = img.get(x, y)
if r % 2 == 1: => 홀수면 검은색, 짝수면 하얀색
canvas.set(x, y, black)
else:
canvas.set(x, y, white)
#2. 텍스트 프로세싱
파일
"planets.txt" 파일은 다음 내용을 가지고 있습니다.
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune
f 는 파일의 내용이 아니라 파일 객체입니다. (type: <class ‘_io.TextIOWrapper’>)
open으로 파일을 여는 것.
\n은 파일에서 읽어온 개행(줄 바꿈) 문자를 의미합니다.
파일에서 문자열 읽기
파일에서 읽어온 문자열 앞뒤의 공백 문자(줄 바꿈 문자, 띄어쓰기 등)를 제거하기 위해서 strip(), rstrip()함수를 사용합니다.
print()문에 end=" " 인자를 추가하면 문자열을 출력한 후 줄을 바꾸는 대신 한 칸을 띄어 쓸 수 있습니다.
파일 객체에 for 반복문을 사용하면 반복할 때마다 readline() 함수를 실행합니다. 반복문은 파일의 마지막 줄을 읽은 후에 종료됩니다.
파일 객체의 사용이 끝나면 f.close()함수를 실행해야 합니다.
close로 파일을 닫는 것.
파일 읽기
다음은 파일 전체의 내용을 읽어 리스트에 저장하는 프로그램입니다.
planets = []
f = open("planets.txt", "r")
for line in f:
planets.append(line.strip())
f.close()
print(planets)
파일 객체는 위와 비슷한 일을 하는 멤버 함수를 가지고 있습니다.
(이 함수는 공백 문자를 따로 제거하지는 않습니다)
planets = f.readlines()
단어 찾기
파일에서 earth라는 단어가 포함된 줄의 위치를 찾고 싶습니다.
f = open("planets.txt", "r")
current = 0
earth = 0
for line in f:
current += 1
planet = line.strip().lower() => 모든 라인을 하나씩 읽고 개행 없애고 소문자로
if planet == "earth":
earth = current
print("Earth is planet #%d" % earth)
이 프로그램은 earth 단어의 위치와 관계 없이 항상 파일 전체 내용을 읽지만,
단어를 찾은 이후에는 더 이상 파일을 읽을 필요가 없습니다.
빠른 단어 찾기
break 키워드는 현재 실행중인 반복문을 중지하고 빠져나옵니다.
f = open("planets.txt", "r")
earth = 0
for line in f:
earth += 1
planet = line.strip().lower()
if planet == "earth":
break
print("Earth is planet #%d" % earth)
break 를 사용하면 가장 안쪽의 반복문만 빠져나옵니다.
파일의 코멘트
파일의 내용에는 주석이 있을 수도 있습니다.
파일의 모든 주석이 #으로 시작한다고 하면, 다음과 같이 주석의 내용을 읽지 않고 건너뛸 수 있습니다.
f = open("planetsc.txt", "r")
earth = 0
for line in f:
planet = line.strip().lower()
if planet[0] == "#":
continue => earth에 1을 더하지 않고 다시 for문으로
earth += 1 =>라인마다 일씩 더한다
if planet == "earth":
break
print("Earth is planet #%d" % earth) => 몇번째있는지(주석을 제외한 채) 알수 있음
continue 키워드는 현재 실행중인 반복을 건너뜁니다.
큰 파일
113,809개의 영어 단어로 이루어진 words.txt 파일의 자료를 사용해서 단어 게임을 해 봅시다.
(https://en.wikipedia.org/wiki/Moby_Project)
단어의 길이가 18보다 긴 모든 영어 단어를 출력해 봅시다.
(예시: counterdemonstrations, 21글자)
f = open("words.txt", "r")
for line in f:
word = line.strip()
if len(word) > 18:
print(word)
f.close()
단어 게임
글자 ‘e’가 포함되지 않은 단어의 수를 세 봅시다.
f = open("words.txt", "r")
count = 0
for line in f:
word = line.strip()
if not "e" in word:
count += 1
print("%d words have no 'e'" % count)
f.close()
Abecedarian words
단어의 모든 글자가 알파벳 순서로 정렬된 단어들을 찾아봅시다.
(예시: art, allow, cello)
def is_abecedarian(word):
for i in range(1, len(word)):
if word[i-1] > word[i]:
return False
return True
f = open("words.txt", "r")
for line in f:
word = line.strip()
if is_abecedarian(word):
print(word)
f.close()
연속된 동일한 문자 파악하기
동일한 두 글자가 연속해서 3번 이상 이어지는 단어는 얼마나 있을까요?
(예시: bookkeeper)
(유사하지만 해당되지 않는 경우: Committee, Mississippi)
def three_doubles(word):
s = ""
for i in range(1, len(word)):
if word[i-1] == word[i]:
s = s + "*" -> 연속으로 같으면 s에 *
else:
s = s + " " -> 아니면 s에 한칸
return "* * *" in s -> oo(*)k( )k(*)e( )e(*): ok, ke는 연속이 아니므로
=> 답은 true, false로 나옴
=>s에 해당 모양이 있으면 t, 아니면 f
파일 쓰기
파일을 새로 만들고, 내용을 쓰는 것도 가능합니다.
f = open("./test.txt", "w")
f.write("CS101 is fantastic\n")
f.close()
파일을 쓰기 위해서는 "w" 모드를 사용해야 합니다.
파일 객체에는 파일에 내용을 쓰기 위한 write(text)멤버 함수가 있습니다.
print()와는 달리, write() 함수는 text 내용 출력 후 자동으로 줄을 바꾸거나 공백 문자를 넣지 않습니다. 줄을 바꾸고 싶다면 개행 문자 '\n'을 추가로 출력해야 합니다.
파일 사용이 끝나면 close()를 호출해야 합니다.
(호출하지 않으면 파일이 불완전하게 저장될 수 있습니다)
금융 자료
환율 자료를 이용해 실습을 해 봅시다. 1994.txt ... 2009.txt 파일은 해당 연도의 일별 KRW-USD 환율 정보를 가지고 있습니다. (www.oanda.com)
2009/05/11 0.00080110
2009/05/12 0.00083010
...
즉, 2009년 5월 11일에는 1 미국 달러가 약 1248.28 원이었습니다.
(1248.28 ≒ 1/ 0.00080110)
먼저, 모든 16개 파일을 읽어서, 각 라인의 문자열에 대해 split 함수를 사용하여,
날짜, 환율 정보가 담긴 튜플의 리스트로 만듭니다.
[... (20091227, 1154), (20091228, 1154),
(20091229, 1167), (20091230, 1167),
(20091231, 1163)]
최고, 최저 환율과 각 연도별 평균 환율을 구해봅시다.
Minimum: (19950705, 755)
Maximum: (19971223, 1960)
월별 최대, 최소 환율을 구해봅시다.
def find_minmax(yr):
minmax = [ (9999, 0) ] * 12
data = read_year(yr) => [(연월시, 환율)]에서 yr를 인자로 연도별로 튜플 리스트를 뽑는다
for d, v in data:
# make month 0 .. 11
month = (d // 100) % 100 - 1 => 연월일을 100으로 나눈 몫을 100으로 나눈 나머지
(-1은 밑에 인덱싱을 할 때 0부터 계산하니까 12월이면 0부터 세 면 13이니까 1부터 세도록 1을 빼준다)
minr, maxr = minmax[month] => [(9999, 0)] 목록에서 해당 월을 찾아 앞과 뒤를 minr, maxr로 지정
if v < minr:
minr = v => 웬만하면 다 9999보다 작음. 그러므로 minr(9999)가 v로 바뀜. 그 뒤로 바뀐 v와 각각 환율을 비교하면서 더 작으면 바뀌고 안 작으면 그대로
if v > maxr:
maxr = v => 웬만하면 다 0보다 큼. 그러므로 maxr(0)가 v로 바뀜. 그 뒤로 바뀐 v와 각각 환율을 비교하면서 더 크면 바뀌고 안 크면 그대로
minmax[month] = minr, maxr => 그러므로 마지막에 가장 적었을 때와 가장 컸을 때의 환율이 남음
return minmax
그래프 만들기
cs1media 모듈을 이용해 환율 변화 그래프를 만들어 봅시다.