본문 바로가기

8. OpenCV | CV

7/26(수) IT K-DT(98일차) / 12.inRange함수~17.지역이진화

 

 

12. inRange()

영상에서 index값을 추출해주는 함수
이미지에서 지정된 범위 안에 픽셀을 선택
    cv2.inRange(영상, min값, max값)

 

# 녹색계열의 색상만 추출하려는 경우

import cv2

src = cv2.imread('./candies.png')
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) # HSV를 사용하여 색상을 추출하려 함
'''
RGB 녹색계열 추출값
0 <= B <= 100
128 <= G <= 255
0 <= R <= 100

HSV 녹색계열 추출값
50 <= H <= 80 // 색상
150 <= S <= 255 // 채도
0 <= V <= 255 // 명도
'''
dst = cv2.inRange(hsv, (50, 150, 0), (80, 255, 255))
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()

 

 

13. copyTo()

마스크 연산을 지원하는 픽셀값 복사 함수
    cv2.copyTo(영상, 마스크, 출력영상=None)

 

 

# 영상 2개를 합성하는 예제

import cv2

src = cv2.imread('./airplane.bmp')
mask = cv2.imread('./mask_plane.bmp', cv2.IMREAD_GRAYSCALE)
dst = cv2.imread('./field.bmp')

# 출력 영상을 넣지 않으면 새로 영상을 만듦
# 입력 영상과 마스크, 출력 영상의 크기가 동일해야 함
cv2.copyTo(src, mask, dst)
cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()

 


문제1

woman.mp4와 임의의 비디오파일을 이용하여 크로마키 프로그램을 만들어보자.
(단, woman.mp4 플레이 중 spacebar를 누르면 합성)

 

import cv2

cap1 = cv2.VideoCapture('./woman.mp4')
cap2 = cv2.VideoCapture('./sky.mp4')

print('가로 사이즈:', int(cap1.get(cv2.CAP_PROP_FRAME_WIDTH)))
print('세로 사이즈:', int(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print('1번 프레임 수:', int(cap1.get(cv2.CAP_PROP_FRAME_COUNT)))
print('2번 프레임 수:', int(cap2.get(cv2.CAP_PROP_FRAME_COUNT)))
print('1번 fps:', int(cap1.get(cv2.CAP_PROP_FPS)))

isKeypress = False

while True:
    ret1, frame1 = cap1.read()
    if not ret1:
        break
    if isKeypress:
        ret2, frame2 = cap2.read()
        if not ret2:
            break
        hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)
        mask = cv2.inRange(hsv, (50, 150, 0), (80, 255, 255))
        cv2.copyTo(frame2, mask, frame1)
    cv2.imshow('frame1', frame1)
    key = cv2.waitKey(10)
    if key == ord(' '):
        isKeypress = not isKeypress
    elif key == 27:
        break
cap1.release()
cap2.release()

 

 

스페이스바 클릭

 

 

 

14. 관심영역(ROI; Region of Interest)

영상 내에서 관심이 있는 영역을 의미
    cv2.selectROI(창이름, 영상, 중앙에서시작할지의여부=False)
    중앙에서시작할지의여부: True일 경우 선택한 ROI의 중앙좌표로 계산
    (기본값은 False, 왼쪽상단좌표로 계산)

 

import cv2

img = cv2.imread('./sun.jpg')
x=182
y=21
w=122
h=114
roi = img[y:y+h, x:x+w]
img2 = roi.copy()
# print(roi.shape)
img[y:y+h, x+w:x+w+w] = roi

cv2.rectangle(img, (x,y), (x+w+w, y+h), (0,255,255),3)
cv2.imshow('img', img)
cv2.waitKey()

 

 

문제2 - 1

 

# sun.jpg 사진에서 원하는 ROI부분을 마우스로 선택하고 선택된 ROI를 창으로 출력하는 예제

import cv2

isDrag = False
oldx = oldy = w = h = 0
color = (255, 0, 0)
img_copy = None

def on_mouse(event, x, y, flags, param):
    global oldx, oldy, w, h, isDrag, img_copy
    if event == cv2.EVENT_LBUTTONDOWN:
        isDrag = True
        oldx = x
        oldy = y
    elif event == cv2.EVENT_MOUSEMOVE:
        if isDrag:
            img_copy = img.copy()
            cv2.rectangle(img_copy, (oldx, oldy), (x, y), color, 3)
            cv2.imshow('img', img)
    elif event == cv2.EVENT_LBUTTONUP:
        if isDrag:
            isDrag = False
            w = x - oldx
            h = y - oldy
            if w > 0 and h > 0:
                cv2.rectangle(img_copy, (oldx, oldy), (x, y), color, 3)
                cv2.imshow('img', img)
                roi = img[oldy:oldy+h, oldx:oldx+w]
                cv2.imshow('roi', roi)
        else:
            cv2.imshow('img', img)
            print('영역이 잘못되었음.')

img = cv2.imread('./sun.jpg')
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

문제 2 - 2

 

import cv2

img = cv2.imread('./sun.jpg')
x, y, w, h = cv2.selectROI('img', img, False)
if w and h:
    roi = img[y:y+h, x:x+w]
    cv2.imshow('roi', roi)
cv2.waitKey()

 

 

임의의 범위를 마우스로 드래그해서 드롭한 경우

 

 

15. 영상 이진화(Binarization)

- 픽셀을 검은색 또는 흰색과 같이 두 개의 값으로 나누는 작업
- 영상에서 의미있는 관심영역(ROI)과 비관심영역으로 구분할 때 사용
- 배경과 객체를 나눌 때 사용
- 영상의 이진화 연산을 할 때 나누는 특정값을 임계값이라고 함
    cv2.threshold(영상, 임계값, 최대값, 플래그)
    플래그
        cv2.THRESH_BINARY: 픽셀값이 임계값을 넘으면 최대값으로 지정하고, 넘지 못하면 0으로 지정
        cv2.THRESH_BINARY_INV: THRESH_BINARY의 반대
        cv2.THRESH_TRUNC: 픽셀값이 임계값을 넘으면 최대값으로 지정하고, 넘지 못하면 원래값을 유지
        cv2.THRESH_TOZERO: 픽셀값이 임계값을 넘으면 원래값을 유지, 넘지 못하면 0으로 지정
        cv2.THRESH_TOZERO_INV: THRESH_TOZERO의 반대

 

import cv2
import matplotlib.pyplot as plt

src = cv2.imread('./cells.png', cv2.IMREAD_GRAYSCALE)
hist = cv2.calcHist([src], [0], None, [256], [0, 255])

a, dst1 = cv2.threshold(src, 100, 255, cv2.THRESH_BINARY)
b, dst2 = cv2.threshold(src, 210, 255, cv2.THRESH_BINARY)
print(a)
print(b)

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

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

 

 

16. 오츠 이진화

=자동이진화
자동으로 임계값을 구하는 알고리즘. 임계값을 구하는 가장 좋은 방법으로 많이 사용됨
    cv2.threshold(영상, 임계값, 최대값, 플래그 | cv2.THRESH_OTSU)
임계값을 임의로 정해 픽셀을 두 부류로 나누고 두 부류의 명암 분포를 구하는 작업을 반복하여
모든 경우의 수 중에서 두 부류의 명암 분포가 가장 균일할 때의 임계값을 선택

 

# 두 사진을 명확하게 구별하기 위해 자동으로 적절한 임계값을 설정해주는 예제

import cv2

src = cv2.imread('./rice.png', cv2.IMREAD_GRAYSCALE)
th, dst = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
print('otsu: ', th) # otsu가 설정한 자동임계값

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

 

 

17. 지역 이진화

균일하지 않은 조명 환경에서 사용하는 이진화 방법
전체 구역을 N등분하고, 각각의 구역에 이진화를 한 뒤 이어붙이는 방법. (자주 이용하는 방법은 아님.)

# 4행 4열로 지역을 구분하여 이진화하는 예제

import cv2
import numpy as np

img = cv2.imread('./rice.png', cv2.IMREAD_GRAYSCALE)

# 전체적으로 이진화 # dst1: '자동이진화'
_, dst1 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

# 지역 이진화
dst2 = np.zeros(img.shape, np.uint8) # dst2라는 새로운 영상을 만듦. '지역이진화'
bw = img.shape[1] // 4
bh = img.shape[0] // 4
for y in range(4):
    for x in range(4):
        img_ = img[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
        dst_ = dst2[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
        cv2.threshold(img_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()