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 |