9/19 과제 제출 - AI 서비스 완성! AI 웹개발 취업캠프 [NIPA/정보통신산업진흥원]

Alicia·2023년 9월 21일
0

AI_Web_nipa

목록 보기
31/31

자세인식과 객체 추적

  • Mediapipe
  • SimpleHRNet
  • DeepSORT

Mediapipe

  • Mediapipe는 구글에서 개발한 AI 라이브러리 서비스로, 인체를 대상으로 한 비전인식에 특화

  • Skeleton(관전 대표점) 추출, 얼굴 인식, 손인식, 자세 구분 등의 라이브러리 포함

  • 이번 강의에선 Human Pose를 중심으로 학습

    Human Pose Estimation이란?

    • 사람의 자세 인식을 나타냄
    • 좀 더 정확히는 사람의 몸의 관절의 길이와 방향을 댚하는 Skeleton을 연구

    human segmantaion: 사람의 픽셀을 트래킹

    Mediapipe Skeleton : Google의 MediaPipe 라이브러리를 사용하여 제공되는 컴퓨터 비전 솔루션 중 하나입니다. 이것은 주로 실시간 비디오 스트림 내에서 인체나 객체의 구조를 감지하고 표현하는 데 사용됩니다.

    적용: 인체 포즈 추정 동작 인식 게임 및 상호 작용

    pip install mediapipe

import cv2
import mediapipe as mp

# MediaPipe Pose 모델 초기화
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()

# 이미지 로드
image_path = 'your_image.jpg'  # 이미지 파일 경로
image = cv2.imread(image_path)

# 이미지를 RGB 포맷으로 변환
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# MediaPipe Pose를 사용하여 포즈 추출
with mp_pose.Pose() as pose:
    results = pose.process(image_rgb)

    if results.pose_landmarks:
        # 결과에서 포즈 관절 정보 추출
        landmarks = results.pose_landmarks.landmark
        for idx, landmark in enumerate(landmarks):
            h, w, c = image.shape  # 이미지 높이, 너비, 채널 정보
            cx, cy = int(landmark.x * w), int(landmark.y * h)  # 포즈 관절 위치 좌표
            cv2.circle(image, (cx, cy), 5, (0, 255, 0), -1)  # 관절 위치에 원 그리기

# 이미지에 그린 포즈를 저장
cv2.imwrite('output_image.jpg', image)

# 결과 이미지 보기
cv2.imshow('Pose Image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

U-Net(유넷)

주로 의료 영상 분야에서 사용되는 딥 러닝 아키텍처 중 하나로, 이미지 분할 (Image Segmentation) 작업에 매우 효과적입니다. U-Net은 의료 이미지에서 종종 작은 구조체 및 오브젝트를 감지하고 분할하는 데 사용됩니다.

인코더-디코더 구조: U-Net은 인코더(encoder)와 디코더(decoder)라고 불리는 두 부분으로 구성됩니다. 이러한 구조는 입력 이미지를 다운샘플링하여 중요한 기능을 추출하는 인코더와, 추출된 특성 맵을 업샘플링하여 원래 입력 크기로 복원하는 디코더로 나뉩니다.

스킵 연결: U-Net의 중요한 특징 중 하나는 인코더와 디코더 사이에 스킵 연결(skip connection)을 사용한다는 것입니다. 이 스킵 연결은 특정 레이어에서 추출된 특성 맵을 디코더의 동일한 레이어로 전달합니다. 이렇게 하면 디코더에서 원본 해상도로 복원하는 동안 중요한 세부 정보가 손실되지 않게 됩니다.

손실 함수: U-Net은 주로 픽셀별 분할 작업을 수행하기 때문에 픽셀 단위의 손실 함수를 사용합니다. 일반적으로 교차 엔트로피 손실(Cross-Entropy Loss)을 사용하여 예측된 분할과 실제 분할 사이의 차이를 최소화합니다.

활성화 함수: U-Net은 인코더에는 일반적으로 ReLU (Rectified Linear Unit) 활성화 함수를 사용하고 디코더에서는 시그모이드 활성화 함수를 사용합니다. 이는 출력을 픽셀 당 0과 1 사이로 스케일링하여 이진 분할을 수행하기 위함입니다.

HRNet

  • HRNet에서는 Pose Estimation Task를 위해, 각 관절 포인트를 뽑기 위해 네트워크를 통해 관절의 Heatmap을 생성
  • 기존의 네트워크는 Encording-Decording 페어 형태인 U-Net 기반 구조였지만, 고해상도 정보를 인코딩 과정에서 잃어버리는 문제가 발생
  • 이를 보완하기 위해 고해상도 저레벨 정보와 저해상도 고레벨 정보를 stage마다 반복적으로 합쳐 높은 인식률을 보이는 네트워크 설계
  • 네트워크의 다양한 해상도와 레벨의 정보를 조합하기 위해, 다음과 같이 convolution Transform과 Pooling으로 stage 단위로 정보를 교환
  • 이전 stage의 저해상도 정보와 고해상도 정보를 조합하여 다음 stage의 feature를 얻을 수 있다!

Object Tracking 알고리즘

  • Object tracking은 이런 연속된 이미지에서 동일한 이미지를 매칭하는 알고리즘입니다.
    자율 주행 자동차, 보안 감시 시스템, 로봇 공학, 의료 영상 처리 등 다양한 응용 분야에서 중요합니다.

원리

물체 감지(Detection): 물체 추적은 먼저 이미지 또는 비디오 프레임에서 물체를 감지해야 합니다. 이 단계에서 주요 물체의 위치를 찾는 기술(물체 감지 알고리즘)을 사용합니다.

물체 특징 추출(Feature Extraction): 감지된 물체에서 중요한 특징을 추출합니다. 이 특징은 물체를 식별하고 추적하는 데 사용됩니다.

물체 추적(Tracking): 추출된 특징을 사용하여 물체를 프레임 간에 추적합니다. 이전 프레임에서 추출한 특징과 현재 프레임에서의 특징을 비교하고, 물체의 위치를 업데이트합니다.

추적 업데이트(Tracking Update): 물체의 움직임을 추적하면서 추적 오차를 보정하고 물체의 새로운 위치를 계산하여 업데이트합니다.

종류
물체 추적 알고리즘은 여러 가지 방식으로 구현됩니다. 일반적인 알고리즘 종류는 다음과 같습니다.

칼만 필터(Kalman Filter) 파티클 필터(Particle Filter) 최적화 기반 추적(Optical Flow) 심층 학습 기반 추적(Deep Learning-based Tracking) 확률적 추적(Probabilistic Tracking)

SORT (Simple Online and Realtime Tracking) 알고리즘

SORT는 실시간으로 동작하며 단순한 추적 알고리즘 중 하나입니다. SORT의 핵심 목표는 각 프레임에서 물체를 감지하고, 프레임 간에 물체를 추적하여 물체 ID를 할당하는 것입니다. SORT는 다음과 같은 단계로 작동합니다:

물체 감지(Detection): SORT는 각 프레임에서 물체 감지 알고리즘(예: YOLO, Faster R-CNN 등)을 사용하여 물체를 감지합니다. 감지된 물체의 위치와 크기 정보를 얻습니다.

칼만 필터(Kalman Filter): SORT는 각 물체에 대해 칼만 필터를 사용하여 예측 모델과 관측 모델을 업데이트합니다. 이를 통해 물체의 현재 위치와 속도를 추정합니다.

물체 추적(Object Tracking): 각 물체에 대한 추적 정보를 관리하며, 프레임 간에 물체의 위치를 추정하고 업데이트합니다. 이러한 추적 정보를 사용하여 물체를 식별하고 추적합니다.

물체 ID 할당(Object ID Assignment): SORT는 프레임 간에 물체 ID를 할당하여 물체를 추적합니다. 물체 감지와 추적 결과를 비교하고, 물체 ID를 할당합니다.

물체 추적 업데이트(Tracking Update): SORT는 물체의 위치를 추정하고 업데이트하며, 물체가 사라지거나 새로운 물체가 나타날 때 적절하게 대응합니다.

칼만 필터(Kalman Filter)

칼만 필터는 동적 시스템에서 노이즈와 불확실성이 있는 상태 추정에 사용되는 선형 시스템 상태 추정 필터입니다. 칼만 필터는 현재 상태의 예측 모델과 관측 모델을 사용하여 상태를 추정하고 업데이트합니다. 물체 추적에서 사용되는 주요 개념은 다음과 같습니다:

상태(State): 추적하려는 물체의 상태(예: 위치, 속도)를 나타냅니다.
예측 모델(Prediction Model): 현재 상태를 예측하는 모델로, 물체의 움직임에 대한 모델입니다.
관측 모델(Observation Model): 관측 결과를 예측 모델과 비교하여 상태를 업데이트하는 모델입니다.
노이즈(Noise): 예측 모델과 관측 모델에서 발생하는 불확실성을 나타냅니다.
칼만 필터는 예측 모델과 관측 모델을 사용하여 현재 상태의 예측을 생성하고, 노이즈를 고려하여 상태를 업데이트합니다.

헝가리안 필터(Hungarian Filter)

헝가리안 필터는 다수의 물체 간의 관계를 추적하는 데 사용되는 알고리즘 중 하나입니다. 주로 물체 추적과 객체 할당(Object Assignment)에 사용됩니다. 헝가리안 필터의 주요 목표는 여러 개의 물체 간에 최적의 관계를 찾는 것입니다.

헝가리안 필터는 다음과 같은 단계로 작동합니다:

비용 행렬(Cost Matrix) 생성: 각 물체 간의 관계를 나타내는 비용 행렬을 생성합니다. 이 비용은 각 물체 간의 거리, 유사성 또는 기타 측정치를 기반으로 생성됩니다.

할당 문제 해결(Solving Assignment Problem): 생성된 비용 행렬을 사용하여 할당 문제를 해결합니다. 이 문제는 각 물체가 다른 물체에 할당되는 방법을 결정하는 문제입니다.

최적 할당(Optimal Assignment): 할당 문제를 해결하여 각 물체에 대한 최적의 할당을 찾습니다. 이로써 물체 간의 관계

HCI 프로젝트

  • 간단한 프로젝트로 박수치는 것을 인식
  • 두 손 사이의 거리가 일정 거리 이하일때 박수라고 가정

mediapipe 설치


❕pip install mediapipe

1. 웹캠 js to cv2 image 변환 함수
function convertImageDataToCV2Image(imageData) {
    const cv2Image = cv.matFromImageData(imageData);
    return cv2Image;
}

2. 웹캠 읽어오기(자바스크립트 사용)
const videoElement = document.createElement('video');
document.body.appendChild(videoElement);

async function setupCamera() {
    const stream = await navigator.mediaDevices.getUserMedia({ 'audio': false, 'video': true });
    videoElement.srcObject = stream;
    return new Promise((resolve) => {
        videoElement.onloadedmetadata = () => {
            resolve(videoElement);
        };
    });
}

setupCamera();


3. 박수를 인식하기 위한 클래스 선언
class ClapDetector {
    constructor() {
        this.handLandmarks = new cv.MatVector();
        this.handLandmarks3D = new cv.MatVector();
        this.handClassifier = new cv.CascadeClassifier();
        this.handClassifier.load('hand_haarcascade.xml');
    }

    detectClap(frame) {
        const gray = new cv.Mat();
        cv.cvtColor(frame, gray, cv.COLOR_RGBA2GRAY);
        const hands = new cv.RectVector();
        const minSize = new cv.Size(40, 40);
        const maxSize = new cv.Size(300, 300);
        this.handClassifier.detectMultiScale(gray, hands, 1.1, 3, 0, minSize, maxSize);

        if (hands.size() >= 2) {
            const hand1 = hands.get(0);
            const hand2 = hands.get(1);

            const distance = Math.sqrt(
                Math.pow(hand1.x - hand2.x, 2) + Math.pow(hand1.y - hand2.y, 2)
            );

            if (distance < 100) {
                return true;
            }
        }
        return false;
    }
}


0개의 댓글