Skip to content

Latest commit

 

History

History
289 lines (222 loc) · 9.16 KB

220128.md

File metadata and controls

289 lines (222 loc) · 9.16 KB

Day 108

OpenCV(Computer Vision)

17. 이미지 검출 (경계선)

Canny Edge Detection

import cv2
img = cv2.imread('snowman.png')

canny = cv2.Canny(img, 150, 200)
# (대상 이미지, minVal, maxVal)

cv2.imshow('img', img)
cv2.imshow('canny', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

minVal은 하위 임계값, maxVal은 상위 임계값이다. 변화(기울기)가 상위 임계값보다 크면 경계선으로 인식한다.

canny1

Trackbar 적용

import cv2

def empty(pos):
    pass

img = cv2.imread('snowman.png')

name = "Trackbar"
cv2.namedWindow(name)
cv2.createTrackbar('threshold1', name, 0, 255, empty) # minVal
cv2.createTrackbar('threshold2', name, 0, 255, empty) # maxVal

while True:
    threshold1 = cv2.getTrackbarPos('threshold1', name)
    threshold2 = cv2.getTrackbarPos('threshold2', name)

    canny = cv2.Canny(img, threshold1, threshold2)
    # (대상 이미지, minVal, maxVal)

    cv2.imshow('img', img)
    cv2.imshow(name, canny)
    
    if cv2.waitKey(1) == ord('q'):
        break
        
cv2.destroyAllWindows()

canny_trackbar

18. 이미지 검출 (윤곽선)

import cv2
img = cv2.imread('card.png')
target_img = img.copy() # 사본 이미지

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 윤곽선 검출
# (이미지, 윤곽선 찾는 모드, 윤곽선 찾을 때 사용하는 근사치 방법)

COLOR = (0, 200, 0)
cv2.drawContours(target_img, contours, -1, COLOR, 2) # 윤곽선 그리기
# (대상 이미지, 윤곽선 정보, 인덱스 (-1이면 전체), 색깔, 두께)

cv2.imshow('img', img)
cv2.imshow('gray', gray)
cv2.imshow('otsu', otsu)
cv2.imshow('contour', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

윤곽선을 검출할 때는 먼저 binary 처리를 해줘야 한다

cv2.findContour는 2개의 정보(윤곽선 정보, 윤곽선 계층 구조)를 반환한다.

cv2.drawContours는 대상 이미지에 그리기 때문에 원본 이미지에 그리면 안된다. 따라서 사본을 준비해두는 것이 좋다.

find_contours

윤곽선 찾기 모드

  1. cv2.RETR_EXTERNAL : 가장 외곽의 윤곽선만 찾음
  2. cv2.RETR_LIST : 모든 윤곽선 찾음 (계층 정보 없음)
  3. cv2.RETR_TREE : 모든 윤곽선 찾음 (계층 정보를 트리 구조로 생성)
import cv2
img = cv2.imread('card.png')
target_img1 = img.copy()
target_img2 = img.copy()
target_img3 = img.copy()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

contours1, hierarchy1 = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours2, hierarchy2 = cv2.findContours(otsu, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours3, hierarchy3 = cv2.findContours(otsu, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)



COLOR = (0, 200, 0)
cv2.drawContours(target_img1, contours1, -1, COLOR, 2)
cv2.drawContours(target_img2, contours2, -1, COLOR, 2)
cv2.drawContours(target_img3, contours3, -1, COLOR, 2)

cv2.imshow('img', img)
cv2.imshow('RETR_LIST', target_img1)
cv2.imshow('RETR_EXTERNAL', target_img2)
cv2.imshow('RETR_TREE', target_img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

contours_mode

근사치 방법

  • CHAIN_APPROX_NONE : 윤곽선의 모든 좌표 반환
  • CHAIN_APPROX_SIMPLE : 윤곽선의 꼭짓점 좌표만 중복을 제거하고 반환

경계 사각형

윤곽선의 경계면을 둘러싸는 사각형

boundingRect()

import cv2
img = cv2.imread('card.png')
target_img = img.copy()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

COLOR = (0, 200, 0)

for cnt in contours:
    x, y, width, height = cv2.boundingRect(cnt)
    cv2.rectangle(target_img, (x, y), (x + width, y + height), COLOR, 2) # 사각형 그림

cv2.imshow('img', img)
cv2.imshow('gray', gray)
cv2.imshow('otsu', otsu)
cv2.imshow('contour', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

boundingRect()를 사용하면 윤곽선을 둘러싸고 있는 사각형 정보를 반환한다.

boundingRect1

면적

contourArea() 어떤 이미지 내에서 특정 크기를 초과하는 윤곽선을 구하고 싶을 때 사용할 수 있다.

import cv2
img = cv2.imread('card.png')
target_img = img.copy()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

COLOR = (0, 200, 0)

for cnt in contours:
    if cv2.contourArea(cnt) > 25000: # 면적이 25000 이상인 윤곽선만 그림
        x, y, width, height = cv2.boundingRect(cnt)
        cv2.rectangle(target_img, (x, y), (x + width, y + height), COLOR, 2)

cv2.imshow('img', img)
cv2.imshow('contour', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

contourArea

미니 프로젝트 : 개별 카드 추출해서 파일 저장

import cv2
img = cv2.imread('card.png')
target_img = img.copy()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, otsu = cv2.threshold(gray, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(otsu, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

COLOR = (0, 200, 0)

idx = 1
for cnt in contours:
    if cv2.contourArea(cnt) > 25000:
        x, y, width, height = cv2.boundingRect(cnt)
        cv2.rectangle(target_img, (x, y), (x + width, y + height), COLOR, 2)
    
        crop = img[y:y+height, x:x+width]
        cv2.imshow(f'car_crop_{idx}', crop)
        cv2.imwrite(f'card_crop_{idx}.png', crop) # 파일 저장
        idx += 1

cv2.imshow('img', img)
cv2.imshow('contour', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

mini_project2

19. 퀴즈

OpenCV를 이용해서 가로로 촬영된 영상을 세로로 회전하는 프로그램 작성

조건

  1. 회전 : 시계 반대방향으로 90도
  2. 재생속도 (FPS) : 원본 x 4배
  3. 출력 파일명 : city_output.avi (코덱 : DIVX)
import cv2

cap = cv2.VideoCapture('city.mp4')

fourcc = cv2.VideoWriter_fourcc(*'DIVX')

width = round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
height = round(cap.get(cv2.CAP_PROP_FRAME_WIDTH))

fps = cap.get(cv2.CAP_PROP_FPS)

out = cv2.VideoWriter('city_output.avi', fourcc, fps * 4, (width, height))
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    rotate_270 = cv2.rotate(frame, cv2.ROTATE_90_COUNTERCLOCKWISE)
    out.write(rotate_270)
    cv2.imshow('video', rotate_270)
    
    if cv2.waitKey(1) == ord('q'):
        break
        
out.release()
cap.release()
cv2.destroyAllWindows()

프로젝트 : 얼굴을 인식하여 캐릭터 씌우기

Face Detection vs Face Recognition

  • Face Detection : 얼굴은 인식하는 데 누구인지 알 필요 없을 때
  • Face Recognition : 얼굴을 인식해서 누구인지까지 알아야 할 때
import cv2
import mediapipe as mp
mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils

cap = cv2.VideoCapture('face_video.mp4')
with mp_face_detection.FaceDetection(
    model_selection=0, min_detection_confidence=0.5) as face_detection:
    while cap.isOpened():
        success, image = cap.read()
        if not success:
            break

        # To improve performance, optionally mark the image as not writeable to
        # pass by reference.
        image.flags.writeable = False
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        results = face_detection.process(image)

        # Draw the face detection annotations on the image.
        image.flags.writeable = True
        image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
        if results.detections:
            for detection in results.detections:
                mp_drawing.draw_detection(image, detection)
                
        cv2.imshow('MediaPipe Face Detection', cv2.resize(image, None, fx=0.5, fy=0.5))
        if cv2.waitKey(1) == ord('q'):
            break
            
cap.release()
cv2.destroyAllWindows()

코드는 MediaPipe의 Face Detection의 예제 코드를 가져와서 일부를 수정한 것이다.

실행하면 얼굴을 인식하여 동영상에 점이 찍히는 것을 확인할 수 있다.

face_detection1