728x90

 

2021.02.18 - [기록 note] - 2021-02-18(OpenCV_2)

 

2021-02-18(OpenCV_2)

어제에 이어 오늘도 기초공부를 진행했습니다 조금씩 내용 난이도가 올라가면서 강의 포즈 하고 생각해야할 것들이 생기기 시작했습니다 그래서 하루에 강의를 몇개를 목표로 정해야 할지 난

ghdrldud329.tistory.com

 

키보드 키를 이용한 영상 조작

import sys
import numpy as np
import cv2


img = cv2.imread('cat.bmp', cv2.IMREAD_GRAYSCALE)

if img is None:
    print('Image load failed!')
    sys.exit()

cv2.namedWindow('image')
cv2.imshow('image', img)

while True:
    keycode = cv2.waitKey()
    if keycode == ord('i') or keycode == ord('I'):
        img = ~img
        cv2.imshow('image', img)
    elif keycode == 27:
        break

cv2.destroyAllWindows()

 

 

마우스 이벤트

import sys
import numpy as np
import cv2

oldx = oldy=-1 
def on_mouse(event,x,y,flags,param): #event: ==, flags: & 사용하기
    global img,oldx,oldy

    if event == cv2.EVENT_LBUTTONDOWN: #눌렀을때 좌표
        oldx,oldy=x,y
        print('EVENT_LBUTTONDOWN:{},{}'.format(x,y))
    elif event== cv2.EVENT_LBUTTONUP: #뗐을때 좌표
        print('EVENT_LBUTTONUP:{},{}'.format(x,y))
    elif event == cv2.EVENT_MOUSEMOVE:
        #  cv.EVENT_FLAG_LBUTTON: 마우스 왼쪽 버튼이 눌려져 있음
        if flags & cv2.EVENT_FLAG_LBUTTON: #마우스가 움직이면서 왼쪽버튼이 눌러져 있다면 빨간선을 그려라
            # print('EVENT_FLAG_LBUTTON:{},{}'.format(x,y))

            #원 그림 그리기_문제점: 빠르게 이동하면 간격이 벌어짐-> line으로 그리기
            # cv2.circle(img,(x,y),5, (0,0,255), -1)

            #line 으로 그림 그리기
            cv2.line(img, (oldx,oldy),(x,y),(0,0,255),5, cv2.LINE_AA)
            cv2.imshow('image',img)
            oldx,oldy=x,y



img = np.ones((480, 640, 3), dtype=np.uint8) * 255

cv2.namedWindow('image')
cv2.setMouseCallback('image', on_mouse)

cv2.imshow('image', img)
cv2.waitKey()

cv2.destroyAllWindows()

 

트랙바 생성

### trackbar

import numpy as np
import cv2

# def on_level_changed(pos): #개선 하기 전 코드
    # global img
    #print(pos) #현재 레벨 값을 보여주기
    
    #img:uint8타입이라서 0~255값 밖에 가지지 못한다
    #pos가 16일때는 256이므로 255보다 크기 때문에 0으로 초기화된다
    #밑에 개선 후 코드로 작성한다
#    img[:,:]=pos*16 #1일때16,2일때 32, ~ 

    # cv2.imshow('image',img)

def on_level_changed(pos): #개선 후 코드
    global img
    
    # 방법1
    # level=pos*16
    # if level>=255:
    #     level=255
    # img[:,:]=level

    #방법2
    level= pos*16
    level= np.clip(level,0,255) #범위를 0~255로 지정, 음수가 나와도 0, 256이 나와도 255
    img[:,:]=level
    cv2.imshow('image',img)   

img = np.zeros((480, 640), np.uint8)
# cv2.namedWindow('image')

#트랙바-> 창이 생성된 이후에 createTrackbar를 호출해야한다
# cv2.createTrackbar() <- namedWindow밑에 삽입, namedWindow가 없다면 imshow밑에 삽입

cv2.imshow('image', img)

                #(트랙바이름,생성할 창이름,초기값,최대값,콜백함수)
                # 최대값16-> 256을 16단계로 쪼개서 나타낸다
                #level값이 변경되었을때 on_level_changed함수를 실행해라 라는 의미
cv2.createTrackbar('level','image',0,16,on_level_changed)

cv2.waitKey()
cv2.destroyAllWindows()

 

시간측정

### time_check

import sys
import time
import numpy as np
import cv2


img = cv2.imread('hongkong.jpg')

tm = cv2.TickMeter() #객체생성

tm.reset() #초기화 
tm.start() #실행할 edge 위아라 각각 start, stop 배치
t1 = time.time()

edge = cv2.Canny(img, 50, 150)

tm.stop() #실행할 edge 위아라 각각 start, stop 배치
print('time:', (time.time() - t1) * 1000)
print('Elapsed time: {}ms.'.format(tm.getTimeMilli()))

 

두 비디오 전환

### video_effect

# ==========================합성하기 전 데이터 준비==============================
import sys
import numpy as np
import cv2

# 두 개 동영상열어서 각 객체에 지정하기
cap1= cv2.VideoCapture('video1.mp4') #원숭이 영상
cap2= cv2.VideoCapture('video2.mp4') #코끼리 영상

#예외처리 코드
if not cap1.isOpened() or not cap2.isOpened(): #둘중에 하나라도 열리지 않을경우
    print('video open failed!')
    sys.exit()

# 두 동영상의 크기, FPS는 같다고 가정(FPS:초당 24.75프레임, 초당 정지 사진을 24개씩 보여준다는 의미)
frame_cnt1=round(cap1.get(cv2.CAP_PROP_FRAME_COUNT)) #1번 영상의 전체 프레임수
frame_cnt2=round(cap2.get(cv2.CAP_PROP_FRAME_COUNT)) #2번 영상의 전체 프레임수
fps= cap1.get(cv2.CAP_PROP_FPS) #24 출력됨

#첫번째영상 끝부분 2초,두번째 앞부분 2초 영상을 합성이 되게끔 
effect_frames= int(fps*2) #초당 24프레임 곱하기 2 = 48프레임을 가진다(합성부분)

print('frame_cnt1',frame_cnt1)
print('frame_cnt2',frame_cnt2)
print('FPS',fps)

delay= int(1000/fps) #두 영상 사이의 시간 간격을 계산, 두 영상 재생시간(저장할때 실제 영상시간이 저장된다)

#영상크기 뽑아내기
w= round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH)) #반올림해서 정수로 만듦
h= round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc= cv2.VideoWriter_fourcc(*'DIVX') #영상 압축

#출력 동영상 객체 생성
#영상 저장하기 위해서는 가로세로크기, 압축방식, fps 
out= cv2.VideoWriter('output.avi', fourcc,fps, (w,h)) #영상저장

# ==============================두영상을 단순히 이어붙이기==============================
#첫번째 영상
'''
while True:
    ret1,frame1 = cap1.read()

    if not ret1: #영상이 끝나면 while문을 빠져 나오기
        break
    out.write(frame1) #1번째 영상 고대~로 저장

    cv2.imshow('frame',frame1)
    cv2.waitKey(delay)

#두번째 영상
while True:
    ret2,frame2 = cap2.read()

    if not ret2: #영상이 끝나면 while문을 빠져 나오기
        break
    out.write(frame2) #2번째 영상 고대~로 저장

    cv2.imshow('frame',frame2) #frame이라는 창을 이어쓰기
    cv2.waitKey(delay)   
'''
# ============================밀어내기 합성================================
#첫번째 영상 나오고->합성영상-> 두번째 영상으로 마무리 순

#첫번째 영상
for i in range(frame_cnt1- effect_frames): #1번영상의 48프레임은 남겨두고 out영상에 그대로 저장된다
    ret1, frame1 =cap1.read()

    if not ret1:
        break

    out.write(frame1) #1번영상 저장

    cv2.imshow('frame',frame1) #1번영상 보여준 후 합성된 영상 2초짜리 보여준다
    cv2.waitKey(delay)

#합성영상
for i in range(effect_frames): #effect_frames: 1번 영상 2번 영상 겹치는 프레임(48프레임=2초동안)
    ret1, frame1=cap1.read() 
    ret2, frame2=cap2.read()

    #합성
    # 첫번째 영상 밀어낼때 얼만큼 간격으로 영상을 바꿀건지 정하기
    #dx = (w*i//effect_frames) w:1280
    dx = int(w*i/effect_frames) # 1280/48 = 가로가 약27개 픽셀단위로 밀어낸다
                           #for문이 실행되면서 27*i 만큼 점차 픽셀이 늘어나는 것
    #0,27,54,81,~ 합성할 부분의 픽셀이 늘어난다 -> ppt의 밀어내기 기능과 유사, 2번째 영상으로 전환 되어 간다
    #몇초간? 2초(48프레임=effect_frame)동안,
    frame = np.zeros((h,w,3), dtype=np.uint8) #컬러영상에 맞게 설정하여 두 영상을 대입한다
    frame[:,0:dx]= frame2[:,0:dx] #영상앞부분 부터 서서히 2번째 영상으로 채워진다 왜? dx의 픽셀이 for돌아갈수록 늘어나니까
    frame[:,dx:w] =frame1[:,dx:w] #앞부분에 채워진 두번영상 이후 첫번째 영상을 넣어야 한다. w:1280(가로 끝까지)

   # ============================디졸브합성================================

    #두 영상 디졸브로 합성하기: 두번째영상을 서서히 나타나게 함, 합성영상에서 두 영상의 가중치를 다르게 조정
    
    # alpha=1.0-i/effect_frames #frame1 가중치를 서서히 낮춘다. effect_frames가 48이니까 i가 증가할수록 가중치가 낮아지는 것.

                        #alpha:frame1의 가중치
    # frame= cv2.addWeighted(frame1, alpha, frame2, 1-alpha,0) #0: gamma-> 전체 가중치에 추가로 더하는 가중치

    # =====================================================================
    out.write(frame)
    cv2.imshow('frame',frame)
    cv2.waitKey(delay)

cap1.release()
cap2.release()
out.release()
cv2.destroyAllWindows()

 

영상 밝기 조절

### 영상의 밝기 조절

import sys
import numpy as np
import cv2

#src: 입력을 의미, dst: 출력을 의미
src= cv2.imread('lenna.bmp',cv2.IMREAD_GRAYSCALE)


#grayscale 영상을 100만큼 밝게 하는 경우
'''
dst=cv2.add(src,100) 

dst=src+100 #src가 ndarray이기 때문에 브로드캐스팅으로 덧셈이 가능
            #하지만 255보다 큰 값은 0에 가까운 값으로 변하게 되는 문제점발생
#numpy 개선코드
            #100. : 점.을찍어서 실수 단위로 연산이 되게 해야한다
            #결과가 실수 단위로 계산이 된다
            #그 후 astype으로 다시 컨버트해준다
dst=np.clip(src+100.,0,255).astype(np.uint8) #결과가 0보다 작으면 0으로,255보다 크면 255로 만들기
'''

#컬러로 불러와서 100만큼 밝게 하는 경우
'''
src= cv2.imread('lenna.bmp')
#아래결과는 블루색깔이 많아진다 왜일까?
dst=cv2.add(src,100)  #여기서 100은 사실 네개의 실수값 네개로 구성된 스칼라 값이다
                      #따라서 실제 컴퓨터는(100,0,0,0)로 구성이된다 순서 상 100이 블루이므로 블루색이 100만큼 더 증가
'''

#동일하게 모두 밝게 할때
dst=cv2.add(src, (100,100,100,0))            

cv2.imshow('src',src)
cv2.imshow('dst',dst)
cv2.waitKey()

cv2.destroyAllwindows()

 

산술연산

### 영상의 산술연산 

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) #두 가중치 0.50 => 두 입력영상의 윤곽을 골고루 가지는 평균영상
dst3 = cv2.subtract(src1, src2) #두 영상을 뺄셈
dst4 = cv2.absdiff(src1, src2) #두영상 중 가장 차이가 나는 곳을 표현 ex)틀린그림 찾기에서 틀린 부분만 부각되어 표현될것이다

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()

 

컬러영상

### 컬러 영상과 색 공간

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

#컬러 공간 변환
'''
src_hsv=cv2.cvtColor(src, cv2.COLOR_BGR2HSV) 
plane=cv2.split(src_hsv)
'''

#채널분리
plane=cv2.split(src)#3개의 영상이 들어있는 리스트가 반환


cv2.imshow('src', src)
cv2.imshow('plane[0]',plane[0]) #블루
cv2.imshow('plane[1]',plane[1]) #그린
cv2.imshow('plane[2]',plane[2]) #레드
cv2.waitKey()

cv2.destroyAllWindows()

 

히스토그램_1

### 히스토그램1

import sys
import numpy as np
import matplotlib.pyplot as plt
import cv2


# 그레이스케일 영상의 히스토그램
src= cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE) #채널이 하나 ->[0]

if src is None:
    print('IMAGE load failed')
    sys.exit()
                         #[0]:gray채널     #bin의 수256      #gray 범위가 0부터256까지
hist = cv2.calcHist([src], [0], mask=None, histSize=[256], ranges=[0,256])
cv2.imshow('src',src)
cv2.waitKey(1) #이 구간에서 1ms 대기 후 아래 코드로 넘어가라는 의미

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) #bgr 각 채널을 따로 분리해서 아래 for문을 돌린다

#세개의 색상성분의 히스토그램을 계산하는데,
#각각을 일차원 그레이스케일 형태로 생각하고 계산하는 것임
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()

 

히스토그램_2

### 히스토그램2

import sys
import numpy as np
import matplotlib.pyplot as plt
import cv2

#cv2를 이용해서 히스토그램을 만드는 함수
def getGrayHistImage(hist):
                    #세로100, 가로256, 밝기 255의  흰 창 
    imgHist = np.full((100, 256), 255, dtype=np.uint8)

    #흰 창에 하나씩 그림을 그리는 것
    histMax = np.max(hist) #세로가 창을 벗어나가는 것을 제한 하기 위함
    print("histMax:",histMax)
    for x in range(256):
        pt1 = (x, 100)      
                            #hist[x, 0]: 높이를 뜻함, 2745가 가장 큰값  100-int(2745*100/2745))=0 
        pt2 = (x, 100 - int(hist[x, 0] * 100 / histMax)) #가장 높은 값이 100이 되도록(공부필요)
        print('hist[x, 0]',hist[x, 0], 'pt2', pt2) # 최고치 hist[x, 0] 2745.0 일때 pt2는 (155, 0) 즉 155픽셀이 2745개가 있다
                                                #x축을 나타내는 pt1=(x,100)이다. 기존 좌표는 (1,0), (2,0)으로 y값이 0으로 고정이 되는데
                                                #이 그래프는 y=100이 0의 역할을 한다 즉(1,0)=(1,100)
                                                #따라서 최대높이인 2745값을 pt2를 이용해 높이를 계산하면 0이 나온다 (가장 높은 높이 0)
                                                #0과100이 반대개념이라 생각하면 된다
        
        cv2.line(imgHist, pt1, pt2, 0) #pt1 부터 pt2까지 그림을 그린다
                                     #pt1이 가로 좌표,pt2가 세로좌표, 이 둘의 좌표를 이은다
                                     #밑바닥에서 시작해서 위로 뻗어가는 직선의 선들을 쭉 생성하면 히스토그램 그림이 된다  

    return imgHist


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])
histImg = getGrayHistImage(hist)

cv2.imshow('src', src)
cv2.imshow('histImg', histImg)
cv2.waitKey()

cv2.destroyAllWindows()

 

Contrast_1

### 명함비1

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 #값이 커질수록 더 급격한 기울기를 갖는다= 급격한 명도

#np.clip 쓰는이유: sturate용도
#아래 공식은 강의에서 제시한 명함비 공식
#(128,128)을 지나고 y절편이 -128인 직선이다
#장점:영상에서 가장 많이 분포하는 픽셀부분에 명함 부여하기가 좋다
#단점: 아주 밝은 영상이나 어두운 영상의 픽셀은 주로 양끝단에 위치하므로 sturate로 인해 0 또는 255로 고정이된다
#다시말해 아주 밝거나 어두운 영상에는 명함을 주지 못한다
#alpha가 실수형, dst도 실수형으로 계산하기 때문에 마지막에는 astype(np.uint8)로 변경
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()

 

Contrast_2

### 명함비2 

import sys
import numpy as np
import cv2

def getGrayHistImage(hist):
    imHist= np.full((100,256), 255, dtype=np.uint8)

    histMax=np.max(hist)
    for x in range(256):
        pt1=(x,100)
        pt2=(x,100-int(hist[x,0]*100/histMax))
        cv2.line(imHist,pt1,pt2,0)
    return imHist

src = cv2.imread('Hawkes.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    print('Image load failed!')
    sys.exit()

#히스토그램 스트레칭: 명도 자동 조절해준다
                    # None:dst를 None로 해주면된다
                    # 0:alpha, 255:beta
#함수 적용한 경우
# dst= cv2.normalize(src,None,0,255, cv2.NORM_MINMAX)

#numpy로 계산한 경우_공식은 책 참고(p222)
gmin= np.min(src)
gmax= np.max(src)
                    #255.: 실수형으로 계산 후 마무리는 uint8
                    #src: 픽셀값
dst= np.clip((src-gmin)*255./(gmax-gmin),0,255).astype(np.uint8)

#정리1:입력영상의 최소값을 0(알파)이 되게 하고, 최대값을 255(베타)로 만든다. (늘려준다)
#정리2:만일 입력영상의 최소값이 애초에 0이고, 최대값이 애초에 255라면 늘려봤자 그대로 일것이다
#정리3:최소값 픽셀이 만일50이고 최대값이 230이라면 스트레칭의 명함효과를 볼수 있다

# ==============================
#히스토그램 시각화하기
#입력영상에 대한 히스토그램
hist = cv2.calcHist([src], [0], None, [256], [0,256])
histImg=getGrayHistImage(hist)

#명함효과 넣은 영상 히스토그램
hist2 = cv2.calcHist([dst],[0],None,[256],[0,256])
histImg2= getGrayHistImage(hist2)

# ==============================

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.imshow('histImg', histImg)
cv2.imshow('histImg2', histImg2)
cv2.waitKey()

cv2.destroyAllWindows()

 

히스토그램 평활화

### 평활화

import sys
import numpy as np
import cv2


# 그레이스케일 영상의 히스토그램 평활화
src = cv2.imread('Hawkes.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    print('Image load failed!')
    sys.exit()

'''
dst = cv2.equalizeHist(src)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()

cv2.destroyAllWindows()
'''
# 컬러 영상의 히스토그램 평활화(348p)
src = cv2.imread('field.bmp')

if src is None:
    print('Image load failed!')
    sys.exit()

#src_ycrcb를 각 채널로 분리후 밝기 정보를 가진 Y만을 평활화 한다
src_ycrcb = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
planes = cv2.split(src_ycrcb) #Y,Cr,Br =>planes는 세개짜리의 영상을 가진 리스트이다 

#Y성분만 평활화진행
planes[0]=cv2.equalizeHist(planes[0])

#YCrCR-> BGR 변환 후 imshow()에 넣는다. imshow는 BGR만 취급한다
dst_ycrcb=cv2.merge(planes) #분리한 채널을 다시 합친다
dst= cv2.cvtColor(dst_ycrcb, cv2.COLOR_YCrCb2BGR)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()

cv2.destroyAllWindows()

 

특정컬러추출_1

### 특색영상추출

import sys
import numpy as np
import cv2


src = cv2.imread('candies.png') #밝은 영상
#src = cv2.imread('candies2.png') #어두운 영상

if src is None:
    print('Image load failed!')
    sys.exit()

#HSV로 변환
src_hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

                        #그레이 영상이라면 스칼라 하나씩 
                        #(B,G,R)          (B,G,R)
                        #ex)블루 성분은 0~100까지 성분을 고른다
                        #lowerb,          opperb
                        #하한값 상한값 사이의 값만 골라서 dst리턴해줌(0 or 255인 마스트영상이다(이진영상))
dst1 = cv2.inRange(src, (0, 128, 0), (100, 255, 100)) #어두운 영상은 색구별 성능 떨어짐
 
                            #(H,S,V)          (H,S,V)
dst2 = cv2.inRange(src_hsv, (50, 150, 0), (80, 255, 255)) #어두운 영상에도 색 구분 성능 좋음(권장)

cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()

cv2.destroyAllWindows()

 

특정컬러추출_1

### 트랙바를 이용한 색상 영역 추출

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):
            #getTrackbarPos: dst창에 있는 h_min 트랙바의 위치를 받는 함수
    hmin= cv2.getTrackbarPos('H_min','dst') #H_min 트랙바 값의 위치값(사용자가 지정할수 있음)
            #getTrackbarPos: dst창에 있는 h_max 트랙바의 위치를 받는 함수
    hmax= cv2.getTrackbarPos('H_max','dst') #H_min 내용과 같음

    dst= cv2.inRange(src_hsv, (hmin,150,0),(hmax,255,255))
    cv2.imshow('dst',dst)

cv2.imshow('src', src)
cv2.namedWindow('dst')
                                #50:시작값, 179:트랙바 범위
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()

 

히스토그램 역투영_1

### 히스토그램 역투영

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 사각형 형태의 정보로 저장된다
x, y, w, h = cv2.selectROI(src) #찾고 싶은 색깔 영역을 드래그 & 스페이스바,enter key

#히스토그램 계산(18~30번줄 까지)
src_ycrcb = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
crop = src_ycrcb[y:y+h, x:x+w] #사용자가 선택한 사각형 영역의 부분 영상
                               #x,y는 시작점 좌표

channels = [1, 2] #Ycrcb에서 Y를 쓰지 않는다. 1:Cr, 2:Cb, Y는 밝기정보, 조명에 대한 영향을 무시하기 위해서 Y를 사용X 
cr_bins = 128 #원래는 256써야하지만 단순화 시킴
cb_bins = 128
histSize = [cr_bins, cb_bins]
cr_range = [0, 256] #256이라고 써야 256를 제외한 255까지로 인식한다
cb_range = [0, 256]
ranges = cr_range + cb_range #[0,256,0,256] => Cr1이 0~255,Cb2는 0~255 인식하는 코드 
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()

 

히스토그램 역투영_2

### 히스토그램 역투영2

import sys
import numpy as np
import cv2


# CrCb 살색 히스토그램 구하기
ref = cv2.imread('kids1.png', cv2.IMREAD_COLOR)
mask = cv2.imread('kids1_mask.bmp', cv2.IMREAD_GRAYSCALE)

if ref is None or mask is None:
    print('Image load failed!')
    sys.exit()

ref_ycrcb = cv2.cvtColor(ref, cv2.COLOR_BGR2YCrCb)

#Y:0, Cr:1, Cb:2
channels = [1, 2]

#앞의 0,256은 Cr범위, 뒤에 0,256은 Cb
ranges = [0, 256, 0, 256]

#mask에 대해서 히스토그램을 구할때는 mask를 적어 넣고
#입력영상 전체에 대해서 히스토그램을 구할때는 None주면 된다
#구하고자 하는 색상의 mask영상을 먼저 히스토그램으로 계산한 후 
#계산된 히스토그램을 통해서 역투영 한다 
#histSize=[128,128]
hist = cv2.calcHist([ref_ycrcb], channels, mask,[128,128], ranges)#계산된 hist는 이차원 형태(x,y) 
print('hist',hist)

#화면으로 보기위해서 로그 그레이스케일로 변환하는 코드
#log 왜 사용한걸까: 히스토그램에서 가장 큰 값을 가지는 것들은 다른 것에 비해 너무 큰 값이 나오면
#정규화 한 후에는 큰 거 몇개의 픽셀만 돋보이고 나머지는 0에 가까운 검정색이 된다
#즉, 비율을 맞춰주기 위해서
#hist값이 0이 나올수 있으므로 +1을 해줌으로써 최소값이 0이 되게끔 설정한다
hist_norm= cv2.normalize(cv2.log(hist+1), None,0,255,cv2.NORM_MINMAX,cv2.CV_8U)

# 입력 영상에 히스토그램 역투영 적용
src = cv2.imread('kids2.png', cv2.IMREAD_COLOR) #역투영 할 이미지

if src is None:
    print('Image load failed!')   
    sys.exit()

src_ycrcb = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)

#역투영
#backproj는 그레이스케일이기 때문에 타입변경없이 바로 imshow하면된다  
backproj= cv2.calcBackProject([src_ycrcb], channels, hist, ranges,1)


cv2.imshow('src', src)
cv2.imshow('hist_norm', hist_norm) #단지 히스토그램을 보기위해서 hist_norm을 구함
cv2.imshow('backproj', backproj)
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_fourcee(*'DIVX')
# out = cv2.VideoWriter('output.avi', fourcc, fps, (w,h))

# 합성 여부 플래그
#경우에 따라 원본을 보여줄지, 합성한 영상을 보여줄지를 결정하는 변수
#True이면 합성영상 on 
do_composit = False

# 전체 동영상 재생
while True:
    ret1, frame1 = cap1.read() #woman 영상

    if not ret1: #맨 마지막 까지가게 되면 불러올 프레임이 없기 때문에
        break      #break가 걸린다.  ret1=False, frame1=None 값이 저장된다
    
    # do_composit 플래그가 True일 때에만 합성
    if do_composit:
        ret2, frame2 = cap2.read()

        if not ret2:
            break
        
        #만일사이즈가 다를경우 resize를 해준다
        # frame2= cv2.resize(frame2, (w,h)) #w,h는 cap1의 크기

        # HSV 색 공간에서 녹색 영역을 검출하여 합성
        hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv, (50, 150, 0), (70, 255, 255))
        
        #두번째 영상에서 마스크가 흰색으로 되어 있는 부분만 frame1쪽으로 복사한다
        cv2.copyTo(frame2, mask, frame1)

    # out.write(frame1) #저장
    cv2.imshow('frame', frame1)
    key = cv2.waitKey(delay) #41ms를 기다리고 다음영상을 받아온다
 
    # 스페이스바를 누르면 do_composit 플래그를 변경
    if key == ord(' '):
        do_composit = not do_composit
    elif key == 27:
        break

cap1.release()
cap2.release()
# out.release()
cv2.destroyAllWindows()

 

 

 

 

 

 

728x90

+ Recent posts