오늘은 화이트 크리스마스 기념?으로 2개의 글을 올릴까한다.
어제는 노량 오늘은 서울의 봄을 보고 왔는데 이순신 장군님으로 국뽕을 치사량 만큼 채워놨더니 두광이가 채워놓은 국뽕을 싹 다 배출시킨 느낌이였다ㅎㅎ
실패하면 반역 성공하면 혁명 아닙니까!!
이 한마디가 가장 인상적이였다.
이번 Chapter는 영상처리에 대한 내용이다.
: 입력 영상의 특정 좌표 픽셀 값을 변경하여 출력 영상의 해당 좌표 픽셀 값으로 설정하는 연산
: 영상을 전체적으로 더욱 밝거나 어둡게 만드는 연산
cv2.add(src1, src2, dst=None, mask=None, dtype=None) -> dst
1) src1 : (입력) 첫 번째 영상 또는 스칼라
2) src2 : (입력) 두 번째 영상 또는 스칼라
3) dst : (출력) 덧셈 연산의 결과 영상
4) mask : 마스크 영상
5) dtype : 출력 영상 (dst)의 타입
6) 참고 사항
- 스칼라는 실수 값 하나 또는 실수 값 4개로 구성된 튜플
- dst를 함수 인자로 전달하려면 dst 크기가 src1, src2와 같아야 하며, 타입이 적절해야함
import sys
import numpy as np
import cv2
# 그레이스케일 영상 불러오기
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
dst = cv2.add(src, 100)
#dst = np.clip(src + 100., 0, 255).astype(np.uint8)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
# 컬러 영상 불러오기
src = cv2.imread('lenna.bmp')
if src is None:
print('Image load failed!')
sys.exit()
dst = cv2.add(src, (100, 100, 100, 0))
#dst = np.clip(src + 100., 0, 255).astype(np.uint8)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.add(src1, src2, dst=None, mask=None, dtype=None) -> dst
1) src1 : (입력) 첫 번째 영상 또는 스칼라
2) src2 : (입력) 두 번째 영상 또는 스칼라
3) dst : (출력) 덧셈 연산의 결과 영상
4) mask : 마스크 영상
5) dtype : 출력 영상 (dst)의 타입
6) 참고 사항
- 스칼라는 실수 값 하나 또는 실수 값 4개로 구성된 튜플
- dst를 함수 인자로 전달하려면 dst 크기가 src1, src2와 같아야 하며, 타입이 적절해야함
cv2.assWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None) -> dst
1) src1 : 첫 번째 영상
2) alpha : 첫 번째 영상 가중치
3) src2 : 두 번째 영상. src1과 같은 크기 & 같은 타입
4) beta : 두 번째 영상 가중치
5) gamma : 결과 영상에 추가적으로 더할 값
6) dst : 가중치 합 결과 영상
7) dtype : 출력 영상의 타입
: 가중치를 a=b=0.5로 설정한 가중치 합
cv2.subtract(src1, src2, dst=None, mask=None, dtype=None) -> dst
1) src1 : 첫 번째 영상 또는 스칼라
2) src2 : 두 번째 영상 또는 스칼라
3) dst : 뺄셈 연산 결과 영상
4) mask : 마스크 영상
5) dtype : 출력 영상의 타입
cv2.absdiff(src1, src2, dst=None) -> dst
1) src1 : 첫 번째 영상 또는 스칼라
2) src2 : 두 번째 영상 또는 스칼라
3) dst : 차이 연산 결과 영상
import sys
import numpy as np
import cv2
from matplotlib import pyplot as plt
src1 = cv2.imread('lenna256.bmp', cv2.IMREAD_GRAYSCALE)
src2 = cv2.imread('square.bmp', cv2.IMREAD_GRAYSCALE)
if src1 is None or src2 is None:
print('Image load failed!')
sys.exit()
dst1 = cv2.add(src1, src2, dtype=cv2.CV_8U)
dst2 = cv2.addWeighted(src1, 0.5, src2, 0.5, 0.0)
dst3 = cv2.subtract(src1, src2)
dst4 = cv2.absdiff(src1, src2)
plt.subplot(231),plt.axis('off'),plt.imshow(src1, 'gray'),plt.title('src1')
plt.subplot(232),plt.axis('off'),plt.imshow(src2, 'gray'),plt.title('src2')
plt.subplot(233),plt.axis('off'),plt.imshow(dst1, 'gray'),plt.title('add')
plt.subplot(234),plt.axis('off'),plt.imshow(dst2, 'gray'),plt.title('addWeighted')
plt.subplot(235),plt.axis('off'),plt.imshow(dst3, 'gray'),plt.title('subtract')
plt.subplot(236),plt.axis('off'),plt.imshow(dst4, 'gray'),plt.title('absdiff')
plt.show()
matplotlib 라이브러리를 이용하여 출력하는 코드인데, 위의 코드를 돌리면 다음과 같은 이미지가 출력된다.
cv2.bitwise_and(src1, src2, dst=None, mask=None) -> dst
cv2.bitwise_or(src1, src2, dst=None, mask=None) -> dst
cv2.bitwise_xor(src1, src2, dst=None, mask=None) -> dst
cv2.bitwise_not(src1, dst=None, mask=None) -> dst
1) src1 : 첫 번째 영상 또는 스칼라
2) src2 : 두 번째 영상 또는 스칼라
3) dst : 출력 영상
4) mask : 마스크 영상
5) 참고 사항
- 각각의 픽셀 값을 이진수로 표현하고 bit 단위 논리 연산을 수행
: 이전에 언급한 적이 있지만, 빛의 3원색을 보통 RGB라고 알고 있지만, OpenCV에서는 BGR순서를 기본으로 사용한다. (내 생각엔 RGB는 무지개색 순서이고, BGR은 알파벳 순서인듯 싶다.)
img1 = cv2.imread('lenna.bmp', cv2.IMREAD_COLOR)
img2=np.zeros((480,640,3), np.uint8)
img3=cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
img4=cv2.cvtColor(img3, cv2.COLOR_GRAY2BGR)
# img4의 경우 각 픽셀은 B,G,R 색 성분이 모두 같게 설정됨
cv2.split(m, mv=None) -> dst
1) m : 다채널 영상 (B,G,R)로 구성된 컬러 영상
2) mv : 출력 영상
3) dst : 출력 영상의 리스트
cv2.merge(mv, dst=None) -> dst
1) mv : 입력 영상 리스트 또는 튜플
2) dst : 출력 영상
import sys
import numpy as np
import cv2
# 컬러 영상 불러오기
src = cv2.imread('candies.png', cv2.IMREAD_COLOR)
if src is None:
print('Image load failed!')
sys.exit()
# 컬러 영상 속성 확인
print('src.shape:', src.shape) # src.shape: (480, 640, 3)
print('src.dtype:', src.dtype) # src.dtype: uint8
# RGB 색 평면 분할
b_plane, g_plane, r_plane = cv2.split(src)
#b_plane = src[:, :, 0]
#g_plane = src[:, :, 1]
#r_plane = src[:, :, 2]
cv2.imshow('src', src)
cv2.imshow('B_plane', b_plane)
cv2.imshow('G_plane', g_plane)
cv2.imshow('R_plane', r_plane)
cv2.waitKey()
cv2.destroyAllWindows()
: 영상 처리에서는 특정한 목적을 위해 RGB 색 공간을 HSV, YCrCb, GrayScale 등의 다른 색 공간으로 변환하여 처리한다.
cv2.cvtColor(src, code, dst=None, dstCn=None) -> dst
1) src : 입력 영상
2) code : 색 변환 코드
3) dstCn : 결과 영상의 채널 수, 0이면 자동 결정
4) dst : 출력 영상
cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None) -> hist
1) images : 입력 영상 리스트
2) channels : 히스토그램을 구할 채널을 나타내는 리스트
3) mask : 마스크 영상, 입력 영상 전체에서 히스토그램을 구하려면 None 지정
4) histSize : 히스토그램 각 차원의 크기 (bin의 개수)를 나타내는 리스트
5) ranges : 히스토그램 각 차원의 최솟값과 최댓값으로 구성된 리스트
6) hist : 계산된 히스토그램
7) accumulate : 기존의 hist 히스토그램에 누적하려면 True, 새로 만드려면 False
import sys
import numpy as np
import matplotlib.pyplot as plt
import cv2
# 그레이스케일 영상의 히스토그램
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
hist = cv2.calcHist([src], [0], None, [256], [0, 256])
cv2.imshow('src', src)
cv2.waitKey(1)
plt.plot(hist)
plt.show()
# 컬러 영상의 히스토그램
src = cv2.imread('lenna.bmp')
if src is None:
print('Image load failed!')
sys.exit()
colors = ['b', 'g', 'r']
bgr_planes = cv2.split(src)
for (p, c) in zip(bgr_planes, colors):
hist = cv2.calcHist([p], [0], None, [256], [0, 256])
plt.plot(hist, color=c)
cv2.imshow('src', src)
cv2.waitKey(1)
plt.show()
cv2.destroyAllWindows()
: 밝은 곳과 어두운 곳 사이에 드러나는 밝기 정도의 차이
import sys
import numpy as np
import cv2
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
alpha = 1.0
dst = np.clip((1+alpha)*src - 128*alpha, 0, 255).astype(np.uint8)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.normalize(src, dst, alpha=None, beta=None, norm_type=None,
dtype=None, mask=None) -> dst
1) src : 입력 영상
2) dst : 결과 영상
3) alpha : (노름 정규화인 경우) 목표 노름 값, (원소 값 범위 정규화인 경우) 최솟값
4) beta : (원소 값 범위 정규화인 경우) 최댓값
5) norm_type : 정규화 타입. NORM_INF, NORM_L1, NORM_L2, NORM_MINIMAX
6) dtype : 결과 영상의 타입
7) mask : 마스크 영상
: 히스토그램이 그레이스케일 전체 구간에서 균일한 분포로 나타나도록 변경하는 명암비 향상 기법
=> 히스토그램 균등화, 균일화, 평탄화
cv2.equalizeHist(src, dst=None) -> dst
1) src : 입력 영상. 그레이스케일 영상
2) dst : 결과 영상
-> 밝기 성분에 대해서만 히스토그램 평활화 수행 (색상 성분은 불변)
src=cv2.imread('field.bmp')
src_ycrcb=cv2.ctvColor(src,cv2.COLOR_BGR2YCrCb)
ycrcb_planes=cv2.split(src_ycrcb)
# 밝기 성분에 대해서만 히스토그램 평활화 수행
ycrcb_planes[0]=cv2.equalizeHist(ycrcb_planes[0])
dst_ycrcb=cv2.merge(ycrcb_planes)
dst=cv2.cvtColor(dst_ycrcb, cv2.COLOR_YCrCb2BGR)
cv2.inRange(src, lowerb, upperb, dst=None) -> dst
1) src : 입력 행렬
2) lowerb : 하한값 행렬 또는 스칼라
3) upperb : 상한값 행렬 또는 스칼라
4) dst : 입력 영상과 같은 크기의 마스크 영상. 범위 안에 들어가는 픽셀은 255, 나머지는 0으로 설정
import sys
import numpy as np
import cv2
src = cv2.imread('candies.png')
if src is None:
print('Image load failed!')
sys.exit()
src_hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
def on_trackbar(pos):
hmin = cv2.getTrackbarPos('H_min', 'dst')
hmax = cv2.getTrackbarPos('H_max', 'dst')
dst = cv2.inRange(src_hsv, (hmin, 150, 0), (hmax, 255, 255))
cv2.imshow('dst', dst)
cv2.imshow('src', src)
cv2.namedWindow('dst')
cv2.createTrackbar('H_min', 'dst', 50, 179, on_trackbar)
cv2.createTrackbar('H_max', 'dst', 80, 179, on_trackbar)
on_trackbar(0)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None) -> dst
1) images : 입력 영상 리스트
2) channels : 역투영 계산에 사용할 채널 번호 리스트
3) hist : 입력 히스토그램
4) ranges : 히스토그램 각 차원의 최솟값과 최댓값으로 구성된 리스트
5) scale : 출력 역투영 행렬에 추가적으로 곱할 값
6) dst : 출력 역투영 영상. 입력 영상과 동일 크기
import sys
import numpy as np
import cv2
# 입력 영상에서 ROI를 지정하고, 히스토그램 계산
src = cv2.imread('cropland.png')
if src is None:
print('Image load failed!')
sys.exit()
x, y, w, h = cv2.selectROI(src)
src_ycrcb = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
crop = src_ycrcb[y:y+h, x:x+w]
channels = [1, 2]
cr_bins = 128
cb_bins = 128
histSize = [cr_bins, cb_bins]
cr_range = [0, 256]
cb_range = [0, 256]
ranges = cr_range + cb_range
hist = cv2.calcHist([crop], channels, None, histSize, ranges)
hist_norm = cv2.normalize(cv2.log(hist+1), None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
# 입력 영상 전체에 대해 히스토그램 역투영
backproj = cv2.calcBackProject([src_ycrcb], channels, hist, ranges, 1)
dst = cv2.copyTo(src, backproj)
cv2.imshow('backproj', backproj)
cv2.imshow('hist_norm', hist_norm)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
크로마키 합성 - 녹색 영역에 다른 배경 영상을 합성
import sys
import numpy as np
import cv2
# 녹색 배경 동영상
cap1 = cv2.VideoCapture('woman.mp4')
if not cap1.isOpened():
print('video open failed!')
sys.exit()
# 비오는 배경 동영상
cap2 = cv2.VideoCapture('raining.mp4')
if not cap2.isOpened():
print('video open failed!')
sys.exit()
# 두 동영상의 크기, FPS는 같다고 가정
w=round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
h=round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_cnt1 = round(cap1.get(cv2.CAP_PROP_FRAME_COUNT))
frame_cnt2 = round(cap2.get(cv2.CAP_PROP_FRAME_COUNT))
print('w x h: {} x {}'.format(w,h))
print('frame_cnt1:', frame_cnt1)
print('frame_cnt2:', frame_cnt2)
fps = cap1.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps)
# 출력 동영상 객체 생성
fourcc=cv2.VideoWriter_fourcc(*'DIVX')
out=cv2.VideoWriter('output.avi',fourcc,fps,(w,h))
# 합성 여부 플래그
do_composit = False
# 전체 동영상 재생
while True:
ret1, frame1 = cap1.read()
if not ret1:
break
# do_composit 플래그가 True일 때에만 합성
if do_composit:
ret2, frame2 = cap2.read()
if not ret2:
break
frame2=cv2.resize(frame2,(w,h))
# HSV 색 공간에서 녹색 영역을 검출하여 합성
hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (50, 150, 0), (70, 255, 255))
cv2.copyTo(frame2, mask, frame1)
out.write(frame1);
cv2.imshow('frame', frame1)
key = cv2.waitKey(delay)
# 스페이스바를 누르면 do_composit 플래그를 변경
if key == ord(' '):
do_composit = not do_composit
elif key == 27:
break
cap1.release()
cap2.release()
cv2.destroyAllWindows()
오늘은 여기까지이다. 진짜진짜 메리크리스마스