728x90

 

2021/02/25 - [기록 note] - 2021-02-25(OpenCV_7)

### grabcut1

import sys
import numpy as np
import cv2


# 입력 영상 불러오기
src = cv2.imread('nemo.jpg')

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

# 사각형 지정을 통한 초기 분할
rc = cv2.selectROI(src)
mask = np.zeros(src.shape[:2], np.uint8)

#포그라운드,백그라운드 둘다 None을 줘도 함수 내부에서 알아서 생성
#계속 업데이터를 하면서 사용해야한다면 강제로 값을 줘야한다
#iteration:5 
#mask를 내부적으로 계속 업데이트 해준다 0~3 사이의 숫자로 마스크값을 채워준다
#0과2: 백 그라운드 인것과 백 그라운드 인 것같은 것을 0,2로 각각표시
#1과3: 포그라운도 인것과 포그라운드 인것같은 것을 1,3으로 각각표시
#mask는 입력&출력
cv2.grabCut(src, mask, rc, None, None, 5, cv2.GC_INIT_WITH_RECT)

# 0: cv2.GC_BGD, 2: cv2.GC_PR_BGD : 확신하는 백그라운드, 백그라운드로 생각되는 것
#0또는 2이면 0으로 셋팅, 1또는3이면 1로 셋팅
mask2 = np.where((mask == 0) | (mask == 2), 0, 1).astype('uint8')

print(mask2)
print(mask2.shape)
print(mask2[:, :, np.newaxis])
print(mask2[:, :, np.newaxis].shape)
print(src.shape)

#mask2는 0과1로 구성된 행렬
dst = src * mask2[:, :, np.newaxis]

#mask 보기
mask = mask*64 #최대값이 3이니까 3*64 = 최대 192 밝기

# 초기 분할 결과 출력
cv2.imshow('dst', dst)
cv2.imshow('mask', mask)
cv2.waitKey()
cv2.destroyAllWindows()

 

### grabcut2

import sys
import numpy as np
import cv2


# 입력 영상 불러오기
src = cv2.imread('nemo.jpg')

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

# 사각형 지정을 통한 초기 분할
mask = np.zeros(src.shape[:2], np.uint8)  # 마스크
bgdModel = np.zeros((1, 65), np.float64)  # 배경 모델, 무조건 1행 65열로 구성
fgdModel = np.zeros((1, 65), np.float64)  # 전경 모델, 무조건 1행 65열로 구성

rc = cv2.selectROI(src)

cv2.grabCut(src, mask, rc, bgdModel, fgdModel, 1, cv2.GC_INIT_WITH_RECT)

# 0: cv2.GC_BGD, 2: cv2.GC_PR_BGD
mask2 = np.where((mask == 0) | (mask == 2), 0, 1).astype('uint8')
dst = src * mask2[:, :, np.newaxis]

# 초기 분할 결과 출력
cv2.imshow('dst', dst)

# 마우스 이벤트 처리 함수 등록
def on_mouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN: #왼쪽버튼을 눌렀을때는 포그라운드를 지정
        cv2.circle(dst, (x, y), 3, (255, 0, 0), -1)
        cv2.circle(mask, (x, y), 3, cv2.GC_FGD, -1)
        cv2.imshow('dst', dst)
    elif event == cv2.EVENT_RBUTTONDOWN:#오른쪽버튼을 눌렀을때는 백그라운드를 지정
        cv2.circle(dst, (x, y), 3, (0, 0, 255), -1)
        cv2.circle(mask, (x, y), 3, cv2.GC_BGD, -1)
        cv2.imshow('dst', dst)
    elif event == cv2.EVENT_MOUSEMOVE: 
        if flags & cv2.EVENT_FLAG_LBUTTON: #왼쪽버튼이 눌러져 있는 상태로 움직인다면 포그라운드
            cv2.circle(dst, (x, y), 3, (255, 0, 0), -1)
            cv2.circle(mask, (x, y), 3, cv2.GC_FGD, -1)
            cv2.imshow('dst', dst)
        elif flags & cv2.EVENT_FLAG_RBUTTON:#오른쪽버튼이 눌러져 있는 상태로 움직인다면 백그라운드
            cv2.circle(dst, (x, y), 3, (0, 0, 255), -1)
            cv2.circle(mask, (x, y), 3, cv2.GC_BGD, -1)
            cv2.imshow('dst', dst)


cv2.setMouseCallback('dst', on_mouse)

while True:
    key = cv2.waitKey()
    if key == 13:  # ENTER
        # 사용자가 지정한 전경/배경 정보를 활용하여 영상 분할
        cv2.grabCut(src, mask, rc, bgdModel, fgdModel, 1, cv2.GC_INIT_WITH_MASK)
        mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        dst = src * mask2[:, :, np.newaxis]
        cv2.imshow('dst', dst)
    elif key == 27:
        break

cv2.destroyAllWindows()

 

### 모멘트 기반 객체 검출

import sys
import numpy as np
import cv2


# 영상 불러오기
obj = cv2.imread('spades.png', cv2.IMREAD_GRAYSCALE)
src = cv2.imread('symbols.png', cv2.IMREAD_GRAYSCALE)

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

# 객체 영상 외곽선 검출
#obj가 애초에 0과 255로 구성된 이진 영상이긴 한데 반전을 하는김에
#128값으로 이진화를 다시한번 해주고 반전 값을 준다(128보다 작으면 0, 크면 255)
#obj의 객체모양이 0으로 구성된 객체라서 반전을 함으로써 배경은 0, 객체는 255로 바꾼다
_, obj_bin = cv2.threshold(obj, 128, 255, cv2.THRESH_BINARY_INV)
obj_contours, _ = cv2.findContours(obj_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
obj_pts = obj_contours[0] #외곽선 좌표정보를 obj_pts 저장

# 입력 영상 분석
_, src_bin = cv2.threshold(src, 128, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(src_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# 결과 영상
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)

# 입력 영상의 모든 객체 영역에 대해서
for pts in contours:
    if cv2.contourArea(pts) < 1000:
        continue

    rc = cv2.boundingRect(pts) #바운딩 박스 좌표를 구한다 
    cv2.rectangle(dst, rc, (255, 0, 0), 1) #구한 좌표를 통해 사각형 박스를 그린다

    # 모양 비교
    #obj_pts, pts간의 모양을 비교한다. 결과값은 두 객체간의 거리값이다.
    #거리값이 작을수록 모양이 비슷하다고 보면된다
    #matchShapes 함수는 객체 모양의 변형이 심하면 성능이 떨어진다
    #대칭,회전 같은 변형은 상관없다
    dist = cv2.matchShapes(obj_pts, pts, cv2.CONTOURS_MATCH_I3, 0)

    #각각의 객체 위에다가 거리값이 보이도록 한다
    cv2.putText(dst, str(round(dist, 4)), (rc[0], rc[1] - 3),
                cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 1, cv2.LINE_AA)

    if dist < 0.1:
        cv2.rectangle(dst, rc, (0, 0, 255), 2)

cv2.imshow('obj', obj)
cv2.imshow('dst', dst)
cv2.waitKey(0)

 

### 템플릿매칭 

import sys
import numpy as np
import cv2


# 입력 영상 & 템플릿 영상 불러오기
src = cv2.imread('circuit.bmp', cv2.IMREAD_GRAYSCALE)
templ = cv2.imread('crystal.bmp', cv2.IMREAD_GRAYSCALE)

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

# 입력 영상 밝기 50증가, 가우시안 잡음(sigma=10) 추가
noise = np.zeros(src.shape, np.int32)
cv2.randn(noise, 50, 10) #randn: 가우시간 값을 반환, 평균이 50,시그마 10인 형태의 노이즈 추가

# CV_8UC3: 채널 3, 8비트
src = cv2.add(src, noise, dtype=cv2.CV_8UC3)

# 템플릿 매칭 & 결과 분석
res = cv2.matchTemplate(src, templ, cv2.TM_CCOEFF_NORMED)
#받은 res는 실수형 행렬-> 최대값 위치를 찾는다
#res는 TM_CCOEFF_NORMED의 영향에 따라 -1~1값을 가진다
#이값을 스케일링해서 아래 res_norm 영상으로 출력

res_norm = cv2.normalize(res, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) #CV_8U : 8-bit unsigned integer: uchar ( 0..255 )
#NORM_MINMAX값을 줘서 최소가 0되고 최대가  255가 되도록 스케일링
#출력을 CV_8U 그레이스케일 형식으로 설정


#최소값,최대값,최소값위치,최대값위치 순으로 출력
_, maxv, _, maxloc = cv2.minMaxLoc(res)
print('maxv:', maxv)
print('maxloc:', maxloc)

# 매칭 결과를 빨간색 사각형으로 표시
th, tw = templ.shape[:2]
dst = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
cv2.rectangle(dst, maxloc, (maxloc[0] + tw, maxloc[1] + th), (0, 0, 255), 2)

# 결과 영상 화면 출력
cv2.imshow('res_norm', res_norm)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

 

### 템플릿 매칭2

import sys
import numpy as np
import cv2


def load_digits():
    img_digits = []

    for i in range(10):
        filename = './digits/digit{}.bmp'.format(i)
        img_digits.append(cv2.imread(filename, cv2.IMREAD_GRAYSCALE))

        if img_digits[i] is None:
            return None

    return img_digits


#img : 부분영상
def find_digit(img, img_digits):
    max_idx = -1
    max_ccoeff = -1

    # 최대 NCC 찾기
    for i in range(10):
        #img : 짤려진 부분영상
        img = cv2.resize(img, (100, 150))

        #img_digits: 10영상이 들어있는 리스트
        #img와 img_digits의 각 영상의 크기가 같으므로 res는 1*1
        #res 값은 하나씩 출력, (1,1) 행렬
        res = cv2.matchTemplate(img, img_digits[i], cv2.TM_CCOEFF_NORMED)

        #값이 가장 큰 값으로 최신화
        if res[0, 0] > max_ccoeff:
            max_idx = i
            max_ccoeff = res[0, 0]

    return max_idx #인덱스 리턴


def main():
    # 입력 영상 불러오기
    src = cv2.imread('digits_print.bmp')

    if src is None:
        print('Image load failed!')
        return

    # 100x150 숫자 영상 불러오기
    img_digits = load_digits()  # list of ndarray

    if img_digits is None:
        print('Digit image load failed!')
        return

    # 입력 영상 이진화 & 레이블링
    src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

    #받은 영상을 자동 이진화진행(글씨가 검정색이므로 invert 해준다)
    #반전 없이 이진화하면 0픽셀 객체를 볼수 없다
    #이진화: 기준값을 기준으로 작으면 0으로, 크면 255로 이진화
    _, src_bin = cv2.threshold(src_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    
    #레이블링이나 또는 findContours를 이용해준다-> 각 객체마다 레이블링 
    #총 객체 갯수(cnt),각 객체의 바운딩박스 정보(stats)
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(src_bin)

    # 숫자 인식 결과 영상 생성
    dst = src.copy()
    for i in range(1, cnt): #0은 배경이므로 제외
        (x, y, w, h, s) = stats[i] #s: 픽셀갯수

        if s < 1000:
            continue

        # 가장 유사한 숫자 이미지를 선택

        #digit안에는 가장 유사도가 높은 값의 인덱스 
        #영상을 짜른다-> 입력영상은 숫자가 이어져있으므로 짤라줘서 비교 해야한다
        digit = find_digit(src_gray[y:y+h, x:x+w], img_digits)
        cv2.rectangle(dst, (x, y, w, h), (0, 255, 255))
        cv2.putText(dst, str(digit), (x, y - 4), cv2.FONT_HERSHEY_SIMPLEX,
                    1, (0, 255, 255), 2, cv2.LINE_AA)

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


if __name__ == '__main__':
    main()

 

### 캐스케이드

import sys
import numpy as np
import cv2


src = cv2.imread('lenna.bmp')

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

classifier = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml')

if classifier.empty():
    print('XML load failed!')
    sys.exit()

tm = cv2.TickMeter()
tm.start()

faces = classifier.detectMultiScale(src, scaleFactor=1.2, minSize=(100,100))

tm.stop()
print(tm.getTimeMilli())

for (x, y, w, h) in faces:
    cv2.rectangle(src, (x, y, w, h), (255, 0, 255), 2)

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

 

### 캐스케이드2

import sys
import numpy as np
import cv2


src = cv2.imread('lenna.bmp')

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

face_classifier = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml')
eye_classifier = cv2.CascadeClassifier('haarcascade_eye.xml')

if face_classifier.empty() or eye_classifier.empty():
    print('XML load failed!')
    sys.exit()

faces = face_classifier.detectMultiScale(src)

for (x1, y1, w1, h1) in faces:
    cv2.rectangle(src, (x1, y1), (x1 + w1, y1 + h1), (255, 0, 255), 2)

    faceROI = src[y1:y1 + h1 // 2, x1:x1 + w1] #얼굴부분의 윗면~반쪽 부분만 짜름(머리~인중)
    eyes = eye_classifier.detectMultiScale(faceROI) #짜른 박스에서 눈 찾기

    for (x2, y2, w2, h2) in eyes:
        center = (x2 + w2 // 2, y2 + h2 // 2)
        cv2.circle(faceROI, center, w2 // 2, (255, 0, 0), 2, cv2.LINE_AA)

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

 

### HOG 보행자 검출

import sys
import random
import numpy as np
import cv2


# 동영상 불러오기
cap = cv2.VideoCapture('vtest.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 보행자 검출을 위한 HOG 기술자 설정
hog = cv2.HOGDescriptor()

#보행자를 검출하기 위해 미리 학습되어 있는 svm coefficient 값들을 불러온다
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

while True:
    ret, frame = cap.read()

    if not ret:
        break

    # 매 프레임마다 보행자 검출
    #weight(신뢰도)정보는 사용 안함
    detected, _ = hog.detectMultiScale(frame)

    # 검출 결과 화면 표시
    for (x, y, w, h) in detected: #(N,4)인 detected 
        c = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        cv2.rectangle(frame, (x, y, w, h), c, 3)

    cv2.imshow('frame', frame)
    if cv2.waitKey(10) == 27:
        break

cv2.destroyAllWindows()

 

 

 

 

 

 

 

728x90

'실습 note' 카테고리의 다른 글

OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
OpenCV_8(특징점 검출&매칭)  (0) 2021.02.26
OpenCV_6(이진 영상 처리)  (0) 2021.02.24
OpenCV_5(영상의 특징추출)  (0) 2021.02.23
OpenCV_4(기하학적 변환)  (0) 2021.02.22

+ Recent posts