본문 바로가기
AI 컴퓨터 비전프로젝트/[ML,DL]머신러닝,딥러닝

[DL] 영상이어붙이기, 키이벤트, 사진 효과(add,blending...)

by 바다의 공간 2024. 8. 9.
영상 2개를 이어붙였습니다.
import cv2
import sys

cap1 = cv2.VideoCapture('./sea.mp4')
cap2 = cv2.VideoCapture('./213026_tiny.mp4')

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))
fps1 = cap1.get(cv2.CAP_PROP_FPS)
fps2 = cap2.get(cv2.CAP_PROP_FPS)

# print(w)
# print(h)
# print(frame_cnt1)
# print(frame_cnt2)
# print(fps1)
# print(fps2)

fourcc = cv2.VideoWriter.fourcc(*'DIVX')
out = cv2.VideoWriter('mix.avi', fourcc, fps1, (w, h))

for i in range(frame_cnt1):
    ret, frame = cap1.read()
    cv2.imshow('output', frame)
    out.write(frame)
    if cv2.waitKey(10) == 27:
        break

for i in range(frame_cnt2):
    ret, frame = cap2.read()
    cv2.imshow('output', frame)
    out.write(frame)
    if cv2.waitKey(10) == 27:
        break

cap1.release()
cap2.release()
out.release()

 


1.키보드 이벤트
cv2.waitkey(delay값을 넣음)
delay : 밀리초 단위 대기하기(0보다 작거나 같으면 무한정 기다립니다. 기본값은 0)
반환값: 눌려진 키의 아스키 코드값(ESC: 27, ENTER:13, TAP: 9...)

import cv2

img = cv2.imread('./dog.bmp')
cv2.imshow('img', img)
cv2.waitKey()


while True:
    keyvalue = cv2.waitKey()
    if keyvalue == ord('i') or keyvalue == ord('I'):
        img = ~img
        cv2.imshow('img', img)

    elif keyvalue == 27:
        break

를 하게되면 i, I를 누르면 이미지 반전이 될 수 있는것을 확인할 수 있습니다.

 

 

화면 녹화 중 2024-08-07 194341.mp4
2.35MB

 


2. 마우스 이벤트

callback = 어떤 이벤트에 의해서 자동으로 불려지는 함수 입니다.


cv2.setMouseCallbakc(윈도우이름, 콜백함수)
윈도우 이름 : 마우스 이벤트를 처리할 창의 이름
콜백함수 : 마우스 이벤트가 발생할 때 자동으로 호출 될 함수를 설정


*아무함수나 사용하면 되지 않습니다.

콜백함수를 만드는 방법
    def 함수명(event, x, y, flags, param):
        pass

    event: 이벤트 객체

 

이렇게 되면 콜백함수가 위의 콜백함수 인자에 들어가게 됩니다.

콜백함수에는 이름은 상관 없지만 순서는 맞아야합니다.

 

event: 이벤트 객체
    x, y: 마우스 x, y좌표
    flags: 마우스 버튼이 눌리고 있는지, 떼졌는지 여부

    param:  추가적인 정보가 필요할 때 전달

 

import cv2
import numpy as np


img = np.ones((500, 500, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.waitKey()

 

크기는 500, 500

import cv2
import numpy as np

def on_mouse(event, x, y, flags, param):
    print('호출됨!')


img = np.ones((500, 500, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

 

 

호출됨이 계속 나오고 print(event)를 사용하면 마우스 커서의 숫자가 나옴


def on_mouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print('왼쪽 버튼이 눌렸어요: %d, %d' % (x, y))


img = np.ones((500, 500, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

 

 

 

 


def on_mouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print('왼쪽 버튼이 눌렸어요: %d, %d' % (x, y))
    elif event == cv2.EVENT_LBUTTONUP:
        print('왼쪽 버튼이 떼졌어요: %d, %d' % (x, y))

img = np.ones((200, 200, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

 


 

import cv2
import numpy as np

def on_mouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print('왼쪽 버튼이 눌렸어요: %d, %d' % (x, y))
    elif event == cv2.EVENT_LBUTTONUP:
        print('왼쪽 버튼이 떼졌어요: %d, %d' % (x, y))
    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            print('드레그중이에요: %d, %d' % (x, y))



img = np.ones((200, 200, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 


 

global 함수를 이용해서 선(라인) 그려보기

 

import cv2
import numpy as np


oldx= oldy = 0
def on_mouse(event, x, y, flags, param):
    global oldx, oldy
    if event == cv2.EVENT_LBUTTONDOWN:
        print('왼쪽 버튼이 눌렸어요: %d, %d' % (x, y))
        oldx, oldy = x, y
    elif event == cv2.EVENT_LBUTTONUP:
        print('왼쪽 버튼이 떼졌어요: %d, %d' % (x, y))
    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            # print('드레그중이에요: %d, %d' % (x, y))
            cv2.line(img, (oldx, oldy), (x, y), (255, 51, 255), 3)
            cv2.imshow('img', img)
            oldx, oldy = x, y



img = np.ones((200, 200, 3), dtype=np.uint8) *255
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

 

 


3. 영상의 화소철

영상의 특정 좌표 픽셀값을 변경하여 출력 영상의 좌표 픽셀을 설정하는 모든 연산

 

할 수 있는 연산 설명 함수, 메소드
밝기 조절 영상을 전체적으로 밝게하거나 어둡게하는 연산 cv.add(), cv2.subtract(), cv2.multiply(), cv.divide()

cv2.addWeighted(), cv2.absdiff()
import cv2

img1= cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)
img2= cv2.imread('./dog.bmp')

dst1 = cv2.add(img1, 100)
dst2 = cv2.add(img2, (100, 100, 100, 0))
dst3 = cv2.subtract(img1, 100)
dst4 = cv2.multiply(img1, 10)
dst5 = cv2.divide(img1, 10)


cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)
cv2.imshow('dst4', dst4)
cv2.imshow('dst5', dst5)
cv2.waitKey()

 

 

 

이렇게 dst1~5까지의 각 add, 옵션, subsract, miltiply, divide등 다양하게 옵션을 주어서 이미지 변경을 할 수 있습니다.

 

 


#4_blending

import cv2
import matplotlib.pyplot as plt

img1= cv2.imread('./man.jpg')
img2= cv2.imread('./turkey.jpg')

# img1 + img2 : 255를 넘어갈 경우 해당값의 256을 빼서 표현
dst1 = img1 +img2
# cv2.add(): 255를 넘어갈 경우 255로 고정
dst2 = cv2.add(img1, img2)

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

 

 

 

 

img = {'img':img1, 'img2':img2, 'dst1':dst1, 'dst2':dst2}

#이미지 갯수 4개만큼 반복하게 됩니다.
for i, (k,v) in enumerate(img.items()):
    plt.subplot(2, 2, i+1)
    plt.imshow(v[:, :, ::-1])
    plt.title(k)
plt.show()

여기서 v[:, :, ::-1] 중   -1는  rgb를 역순으로 맞춰주려고 한겁니다.

 

위 사진 4개를 반복문으로 이미지를 넣어주었고 v에 모든 값들을 넣어주었고 title은 k 로 찍어주면 됩니다.

 

3번은 255가 넘어가는경우 4번은 실제로 원하는 영상이 됩니다.


#5_addWeighted

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

img1= cv2.imread('./man.jpg')
img2= cv2.imread('./turkey.jpg')

alpha = 0.7
dst1 = cv2.addWeighted(img1,alpha, img2, (1-alpha), 0)
dst2 = img1 * alpha + img2 * (1-alpha)
dst2 = dst2.astype(np.uint8)

img = {'img':img1, 'img2':img2, 'dst1':dst1, 'dst2':dst2}

#이미지 갯수 4개만큼 반복하게 됩니다.
for i, (k,v) in enumerate(img.items()):
    plt.subplot(2, 2, i+1)
    plt.imshow(v[:, :, ::-1])
    plt.title(k)
plt.show()

 

 


# 6_arithmetic

***간단한 예제***

#add, addWeighted, subtract, absdiff
# matplobtilib sumplot를 이용하여 4가지 연산 결과를 출력
# absdiff(img1, img2)

#add, addWeighted, subtract, absdiff
# matplobtilib sumplot를 이용하여 4가지 연산 결과를 출력
# absdiff(img1, img2)

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

img1 = cv2.imread('./babydog.jpg')
img2 = cv2.imread('./square.bmp')

dst1 = cv2.add(img1, img2)
dst2 = cv2.addWeighted(img1, 0.5, img2, 0.5, 0)
dst3 = cv2.subtract(img1, img2) #영상 빼기
dst4 = cv2.absdiff(img1, img2) #영상 빼고 혹시 -면 절대값 취함

cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)
cv2.imshow('dst4', dst4)
cv2.waitKey()

img = {'dst1':dst1, 'dst2':dst2, 'dst3':dst3, 'dst4':dst4}

#이미지 갯수 4개만큼 반복하게 됩니다.
for i, (k,v) in enumerate(img.items()):
    plt.subplot(2, 2, i+1)
    plt.imshow(v[:, :, ::-1])
    plt.title(k)
plt.show()

 

dst1는 square에 255를 넣으니 흰색일 수 밖에 없습니다. 

dst2는 addWeighted에 알파 베타에 0.5씩만 주니까 절반만 집어넣으니 밝은수준으로 영상이 믹스되어 보이게됩니다.

dst3 subtract에 255를 빼니까 검정색이 됩니다.

dst2는 adsdiff에 값이 반대값이 되니까 보수값을 취한 결과가 나오게 됩니다.


 

4. 컬러 영상과 색

- 컬러영상은 3차원 배열

- numpy.ndarray

- img.shape: (h, w, 3) -> openCV에서는 BGR, (높이, 너비 채널)

- 색상 채널 분리가능 : cv2.split(영상) ▶ bgr채널 분리가 되고 변경할 수 있음

- 색상 채널 결합 가능 :cv2.merge(입력 영상 채널의 리스트 또는 튜플)

import cv2

img = cv2.imread('./candies.png')
print('shape: ', img.shape)
print('dtype: ', img.dtype)

b, g, r = cv2.split(img)

cv2.imshow('img', img)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('r', r)
cv2.waitKey()

 

 

각각 색을 분리해서 볼 수 있습니

#파이썬 문법을 활용하여 분리해보기

print(img.shape) #(480, 640, 3)
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]

cv2.imshow('img', img)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('r', r)
cv2.waitKey()

위와 같은 사진이 나오게 됩니다.

설명을 하자면

이미지를 저장한 img는 3차원 배열(혹은 3D 배열)이라고 생각할 수 있습니다. 이는 여러 겹의 2차원 배열(혹은 2D 배열)이 쌓여 있는 형태입니다. 각 2차원 배열은 이미지의 색상 채널 중 하나를 나타냅니다.

배열 이해하기

먼저 3차원 배열을 시각화해봅시다:

  • img는 480 x 640 x 3 크기의 배열입니다.
  • 여기서 480은 이미지의 높이, 640은 너비, 3은 색상 채널입니다.

색상 채널은 다음과 같이 순서대로 배열되어 있습니다:

  1. 첫 번째 채널 (img[:, :, 0])은 파란색 (B: Blue)
  2. 두 번째 채널 (img[:, :, 1])은 초록색 (G: Green)
  3. 세 번째 채널 (img[:, :, 2])은 빨간색 (R: Red)

배열 슬라이싱

배열 슬라이싱은 전체 배열에서 필요한 부분만 선택하는 방법입니다. 예를 들어 img[:, :, 0]은 파란색 채널만 선택하는 슬라이싱 방법입니다. 여기서 :는 전체 범위를 의미합니다.

 


5.histogram(히스토그램)
-영상의 픽셀값 분포를 그래프 형태로 표현
-예) 그레이스케일 영상에서 밝기정보에 해당하는 픽셀 개수를 구하고 막대그래프로 표현
- 만드는 방법
cv2.calcHist(영상, 채널, None, 빈의 개수를 나타내는 리스트, 각 차원의 최소값과 최대값으로 구성된 리스트)
    채널  : 히스토그램을 계산할 채널 (0번을 집어넣으면 0번채널 ...)
    None : 특정 영역만 히스토그램을 계산할 때 사용할 마스크. None을 설정하면 전체 이미지에 대해 계산
    빈의 개수를 나타내는 리스트: 빈의 수를 지정. 256으로 거의 지정되어있음.
    이유는 0~255이기 때문입니다.
    각 차원의 최소값과 최대값으로 구성된 리스트 : 범위를 지정, 보통 [0, 255] 사용

 

 

#8_hist1

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)

hist = cv2.calcHist([img], [0], None, [256], [0, 256])


cv2.imshow('img', img)
plt.plot(hist)
plt.show()
cv2.waitKey()

 

 

 

 

 

 

 


9_hist2

-선명도를 판단하는 기준이 될 수 있습니다.

# dog.bmp 영상을 컬러로 불러와 3채널을 계산하여 히스토그램 그리기
# 단 하나의 plot에서 BGR 그래프를 그리기(색상을 다르게 표현)

import cv2
import matplotlib.pyplot as plt

img= cv2.imread('../dog.bmp')

colors = ['b', 'g', 'r']
bgr = cv2.split(img)

for (b, c) in zip(bgr, colors):
    hist = cv2.calcHist([b], [0], None, [256], [0, 256])
    plt.plot(hist, color=c)

cv2.imshow('img', img)
plt.show()
cv2.waitKey()





 

채널 밝기정보를 알 수 있습니다.

color=c는 이미지 컬러 자체를 스프릿하는거기떄문에 b,g,r,이 각각 들어가게 됩니다.

그래서 b,g,r채널 각각 3가지가 되고 그 부분이 for를 돌면서 들어가게됩니다.

 

 


여기까지가 8월 4일까지 수업했던 파이토치를 활용해서 만든 이미지 cv2입니다.

 

밝기정보가 어떻게 분포되어있는지 확인할 수 있고 어느정도의 선명도를 확인하고 판단할 수 있는 기준이 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

순서 함수,메소드 설명

1
ord(i) i에 대한 아스키코드
2 ~ 반전(보수값을 얻음)
3 cv2.setMouseCallbakc(윈도우 창 이름, 콜백함수) 이벤트 발생하면 뭐 불러줄래..? 라는 함수
4 global 외부에있는함수도 내부에서도 쓸 수 있게 만들어줌
5 cv2.addWeighted() 두 영상의 같은 위치에 존재하는 픽셀값에 대하여 가중합을 계산해서 결과 영상의 픽셀값으로 설정(가중치의 합은 1)
6 cv2.absdiff() 두 영상의 픽셀 값을 뺴면 음수가 나올 수 있는데 해당 값에 절대값을 취한 값