개요

  • 이번 프로젝트에서는 ①클래스를 상속 받아 기능 확장하여, ②Tensorflow-models 모델의 전형적인 구조에 따라 핵심 코드를 작성하였음
  • 상속 
    • 의미 : 부모 클래스의 프로퍼티, 메서드를 자식 클래스가 물려받는 것
    • 기능 : 부모 클래스 기능을 자식 클래스에서 확장시킬 수 있음.
    • ES6 모듈 개발 전 : 프로토타입 체인 방식으로 상속, 그러나 이는 가독성 떨어짐.
    • ES6 모듈 개발 후 : Class + extends 키워드를 사용하여 상속, 상속하는 것 확실히 티 낼 수 있게 됨
  • 이번 프로젝트에서의 상속
    • Detector 클래스
class Detector {
  constructor () { }

// 그 외 내용: 자바스크립트에서의 getter and setter
// https://ko.javascript.info/property-accessors
  static get DIMENSIONS () {  // 
      return [480, 360];
  }
  enable () {
      this._enable = true;
  }
  disable () {
      this._enable = false;
      this._result = null;
  }
  detect (imageData) { }
  isExistContent (result) {
      return result && result.length > 0;
  }
  draw (canvas) { }
}
module.exports = Detector;

 

  • HandposeDetector 클래스
class HandposeDetector extends Detector {
  constructor() {
      super();
      this._result;
  }

  enable() {
      super.enable();
      this._canvas = document.createElement("canvas");
      this._canvas.width = Detector.DIMENSIONS[0];
      this._canvas.height = Detector.DIMENSIONS[1];
      this._context = this._canvas.getContext("2d");
  }

  disable() {
      super.disable();
      delete this._context;
      delete this._canvas;
      this._context = null;
      this._canvas = null;
  }

  _createDetector() {
      const model = SupportedModels.MediaPipeHands;
      const detector = createDetector(model, {
          runtime: "tfjs",
          modelType: "lite",
          maxHands: 2, // or 2~10.
          flipHorizontal: false,
          staticImageMode: false,
          detectorModelUrl:
              "/static/tensorflow-models/tfjs-model_handpose_3d_detector_lite_1/model.json",
          landmarkModelUrl:
              "/static/tensorflow-models/tfjs-model_handpose_3d_landmark_lite_1/model.json",
      });

      console.log("model loading success!, detector: ", this._detector);
      return detector;
  }
  
  detect(imageData) {
      if (!this._detector) {
          this._createDetector().then(detector => {
              this._detector = detector;
              console.log("model loading success!, detector: ", this._detector);
          })
      }

      return new Promise((resolve, reject) => {   
          this._detector.estimateHands(imageData).then(result => {
              this._result = result;
              console.log(`this._result: `, this._result);

              this._result.forEach((res) => {
                  console.log(`${res.handedness} hand keypoints:`);
                  res.keypoints.forEach((keypoint, i) => {
                      let x = keypoint.x - 320;
                      let y = keypoint.y - 240;
                      console.log(`Keypoint ${i}: [${x}, ${y}]`);
                  })
              })
              resolve(this._result);
          }).catch(e => {
              reject(e);
          });
      })
  }
/**
중략
**/
}
module.exports = HandposeDetector;

 


 

개념 정리

출처 : https://ko.javascript.info/class-inheritance

1. class와 prototype

  • 부모 클래스 Animal과 객체 animal
class Animal {
  constructor(name) {
    this.speed = 0;
    this.name = name;
  }
  run(speed) {
    this.speed = speed;
    alert(`${this.name} 은/는 속도 ${this.speed}로 달립니다.`);
  }
  stop() {
    this.speed = 0;
    alert(`${this.name} 이/가 멈췄습니다.`);
  }
}

let animal = new Animal("동물");
  • 객체 animal과 클래스 Animal의 관계

  • Animal vs Animal.prototype
    Animal : Class Definition Animal.prototype : Prototype-Based Definition
    class 키워드로 정의한 클래스 객체의 프로토타입을 확장하여 메서드와 속성을 추가한 것
    ES6 이후 문법 ES6 이전 문법
    클래스 = 메서드(run, stop) + 속성(speed, name)  
    클래스는 생성자(constructor)를 가질 수 있음  
    • constructor
      • 함수 자신, 따라서 위 그림에서 constructor : Animal 로 표시됨
        (∵ 자바스크립트에서 클래스⊂함수, 클래스는 생성자 함수로써 내부적으로 생성자 함수와 프로토타입을 생성하기 때문)
      • 만약 Animal 함수의 프로퍼티 ‘prototype’에 constructor 객체 하나만 있다면 ‘디폴트 프로퍼티가 있다’고 표현 가능
        (디폴트 프로퍼티 : 개발자가 별도로 할당하지 않아도 기본적으로 가지는 프로퍼티)
      • 기능적으로 클래스에서 객체를 생성하고 초기화하기 위해 사용하는 메서드라고 볼 수 있음. 클래스를 통해 새로운 객체를 생성할 때 자동 호출됨

 


 

2. extends키워드로 상속 받기

  • 자식 클래스 Rabbit
class Rabbit extends Animal {
  hide() {
    alert(`${this.name} 이/가 숨었습니다!`);
  }
}

let rabbit = new Rabbit("흰 토끼");

rabbit.run(5); // 흰 토끼 은/는 속도 5로 달립니다.
rabbit.hide(); // 흰 토끼 이/가 숨었습니다!
  • 클래스 Rabbit을 이용하여 만든 객체 rabbit
    : rabbit은 rabbit.hide() 로 Rabbit 클래스의 메서드에도, rabbit.run() 으로 Animal의 메서드에도 접근 가능
  • extends는 프로토타입을 기반으로 동작
    • 따라서 extends는 Rabbit.prototype.[[Prototype]]Animal.prototype으로 설정함
    • Rabbit.prototype에서 메서드를 찾지 못하면 Animal.prototype에서 메서드를 가져옴

 

  • 프로젝트에 적용
class HandposeDetector extends Detector { }

 


 

3. 메서드 오버라이딩(Method Overriding) : super 키워드 활용

  • 의미 : 부모 클래스의 메서드재정의하여 자식 클래스에서 사용하는 것
    → 재정의 : 일부 기능만 변경 or 기능 확장
  • super 키워드 활용
    • super(…) : 부모 생성자 자체 호출, 따라서 자식 생성자 내부에서만 사용 가능
    • super.method명(…) : 부모 클래스의 method를 호출
  • 핵심 코드 : 부모 클래스의 stop() method를 오버라이딩한 rabbit.stop() 정의
class Rabbit extends Animal {
  hide() {
    alert(`${this.name}가 숨었습니다!`);
  }

  stop() {
    super.stop(); // 부모 클래스의 stop을 호출해 멈추고,
    this.hide(); // 숨습니다.
  }
}

let rabbit = new Rabbit("흰 토끼");
rabbit.run(5); // 흰 토끼가 속도 5로 달립니다.
rabbit.stop(); // 흰 토끼가 멈췄습니다. 흰 토끼가 숨었습니다!
  • 프로젝트에 적용
enable() {
      super.enable();
      this._canvas = document.createElement("canvas");
      this._canvas.width = Detector.DIMENSIONS[0];
      this._canvas.height = Detector.DIMENSIONS[1];
      this._context = this._canvas.getContext("2d");
  }

 


 

4. 생성자 오버라이딩(Constructor Overriding)

  • 의미 : 부모 클래스의 생성자재정의하여 자식 클래스에서 사용하는 것
  • super 키워드 활용
    • super 키워드가 상속 클래스의 생성자 함수가 실행되면, 부모 클래스의 생성자가 ①빈 객체를 만들고 ②this에 이 객체가 할당되도록 함
    • 따라서 super 키워드가 없으면 this가 될 객체가 생성되지 않아 자식 클래스 생성자 실행 시 오류 발생함
  • 핵심 코드
class Rabbit extends Animal {
  constructor(name, earLength) {
		super(name);
    this.earLength = earLength;
  }
  // ...
}
  • 프로젝트에 적용
class HandposeDetector extends Detector {
  constructor() {
      super();
      this._result;
  }
}

 


 

배운점 (요약)

  • 이번 프로젝트에서는 ①클래스를 상속 받아 기능 확장하여, ② Tensorflow-models 모델의 전형적인 구조 에 따라 핵심 코드를 작성하였음
  • 실제 코드를 작성할 때는 정확히 무슨 뜻인지 모르고, 용례를 보고 이런 느낌이구나 라고 생각하며 사용했음
  • 그러나 프로젝트를 마무리하며 개념 정리를 하니, 밑그림만 있던 것이 구체적인 채색까지 되는 느낌이었음. 따라서 향후 활용할 수 있는 자신감이 생겼음. 또한 효율적, 효과적인 코드를 위해 상속 및 오버라이딩은 필수 요소라고 생각했음.

 

개요

회사에서 처음으로 프로젝트를 부여받았다. 손 이미지 좌표를 예측하는 AI를 개발하는 것이었고, 예측 과정은 다음과 같다. 

  1. 웹캠으로 손 영상이 들어옴
  2. 프레임 단위로 캡쳐된 이미지를 텐서* 형태로 변환
    * 텐서
     - 데이터가 3차 이상으로 들어있는 것; 3차원인 경우 x(row), y(column), z(depth)로 구성됨
     - 3차원 이상의 정보를 담을 수 있어 일반 테이블 구조보다 많은 정보를 담을 수 있음. 그러나 데이터 해석 시 데이터 구조에 대한 기초 지식이 요구됨
  3. 텐서 형태로 인식된 손의 좌표(x, y, z(깊이) 축)를 예측

위와 같은 과정을 수행하기 위해 차장님께 TensorflowHandpose, Handpose detection 라이브러리를 사용하면 된다고 전달받았다. 그러나  모르는 것 투성이었으므로 꼬리 문제 풀듯이 꼬리 개념으로 정리하고자 한다.

 


 

TensorFlow 란?

텐서플로(TensorFlow)는 구글(Google)에서 만든 데이터 흐름 프로그래밍을 위한 아파치 2.0 오픈소스 소프트웨어 라이브러리이다. 특히 머신러닝, 딥러닝 프로그램을 쉽게 구현할 수 있도록 해준다. 기본적으로 C++로 구현되어 있으며, Python, Java, Go 등 다양한 언어를 지원한다. 그러나 대부분의 편한 기능들이 Python 라이브러리로 구현되어 있어 언어로 개발하는 것이 편하다. 텐서플로의 라이브러리들은 깃헙에 정리 되어 있다. 이번 프로젝트를 수행하기 위해 나는 그중에서도 tfjs-models 라이브러리handpose, hand-pose-detection 패키지를 참고해야 했다. 그러나 각 패키지의 차이가 무엇인지, 둘 중 무엇을 더 중점적으로 사용해야 하는지 의문이 있었다.

 

Handpose 라이브러리 vs Handpose detection 패키지의 차이점
  Handpose Handpose detection
사용 예시  3D 손 부위 key points(landmarks) 감지를 위한 Media pipe hands 모델 구현  - Google's Real-time Hand pose Detection with Media pipe 모델 구현 
- TensorFlow Lite Micro Speech 예제에서 사용된 모델을 구현 
특징  - 손바닥, 손가락, 손목을 합친 21개의 key points 감지 
- 이미지 또는 비디오에서 손 추적 가능 
- 웹 어플리케이션에서 복잡한 3D key points 감지 기능이 필요한 경우 사용 
- 임베디드 시스템(마이크로 컨트롤러)에서 음성 명령과 함께 실시간으로 손 동작을 감지하는데에 사용하기 좋음

 

위와 같은 특징들로 인해 나는 프로젝트에서 Handpose 패키지를 중점적으로 사용하되, 웹캠 구현 등 기타  사항에서는 Handpose detection 패키지를 적극적으로 활용하기로 결정했다!

 


 

Human pose Estimation 이란?

현재 내가 하고 있는 프로젝트 내용, 텐서플로의 Handpose 및 Handpose detection 패키지는 모두 Human pose Estimation에 속한다.  이에 대한 이론적인 내용은 방대하므로 별도의 글에서 보다 구체적으로 정리하도록 하고, 이 글에서는 의미와 프로젝트와 관련된 내용만 간략하게 정리하고 넘어가고자 한다. 

 

의미

Human pose Estimation(& Tracking)은 Semantic key points*를 검출하고 ②key points 사이의 관련성을 찾고 ③지속적으로 추적하는 컴퓨터 비전**의 과제이다. 나는 Human pose Estimation 중에서도 첫 번째로 손 위치 추적에 대한 프로젝트를 부여받은 것이다. 명칭에서도 알 수 있듯 Human pose Estimation은 Pose Estimation의 한 종류이다. Pose Estimation(포즈 추정)은 컴퓨터 비전에서 유명한 과제 중 하나이다. 
  * Semantic key points : 의미 있는 점; 즉 사람 신체의 오른쪽 어깨, 왼쪽 무릎 등을 예로 들 수 있음
  **  컴퓨터 비전 (vision) : 사람의 시각을 모방하여 기계가 컴퓨터 영상을 처리할 수 있도록 도와줌

 

원리

대부분의 Pose Estimator는 2개 과정으로 위치를 추정한다. 

  • bounding box로 사람 또는 물체를 탐색한다.
  • 각 박스에서 탐색 대상의 key points를 찾아낸다. 사람의 경우 key points는 팔꿈치, 무릎, 손목 등이 될 수 있다. Single-pose estimation 의 경우 주어진 영상에서 하나의 물체의 pose를 추정하는 것이 목적이고, Multi-pose estimation의 경우 여러 물체를 탐지하는 것이 목적이 된다. 

 

Handpose 패키지를 이용한 AI 개발이 속하는 method의 범위

딥러닝의 빠른 발전으로 딥러닝 기반 Pose Estimation이 고전 방식에 비해 우월한 성능을 보이고 있으며 그 종류가 다양하다. 이번 프로젝트는 Node.js 기반 서버에서 동작하는 자사 제품에 추가될 기능이므로, 내 생각에는 Handpose 패키지를 이용한 프로젝트는 PoseNet 모델을 이용한 것이라고 볼 수 있을 것 같다. 

PoseNet
  - 경량으로 모바일 또는 웹 브라우저에서 작동하기 위한 모델 
  - TensorFlow.js 를 기반으로 구축된 사전 학습 모델

 

 


 

 

참고 자료

TensorFlow 란?

https://ko.wikipedia.org/wiki/%ED%85%90%EC%84%9C%ED%94%8C%EB%A1%9C

 

텐서플로 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 텐서플로(TensorFlow) 또는 텐서플로우는 다양한 작업에대해 데이터 흐름 프로그래밍을 위한 오픈소스 소프트웨어 라이브러리이다. 심볼릭 수학 라이브러리이자,

ko.wikipedia.org

https://excelsior-cjh.tistory.com/148

 

[러닝 텐서플로]Chap01 - 텐서플로 란?

Chap01 - 개요1.1 텐서플로 란? 텐서플로(TensorFlow)는 구글(Google)에서 만든, 딥러닝 프로그램을 쉽게 구현할 수 있도록 다양한 기능을 제공해주는 라이브러리다. 텐서플로 자체는 기본적으로 C++로 구

excelsior-cjh.tistory.com

 

Human pose Estimation 이란?

https://supermemi.tistory.com/entry/Human-Pose-Estimation-%EC%9D%B4%EB%9E%80-2022

 

Human Pose Estimation 이란? (2022)

Human Pose Estimation Ultimate Overview in 2022 Human Pose Estimation with Deep Learning - Ultimate Overview in 2022 - viso.ai Pose Estimation is a computer vision technique to predict and track the location of a person or object. List of use cases and arc

supermemi.tistory.com

https://viso.ai/deep-learning/pose-estimation-ultimate-overview/

 

Human Pose Estimation with Deep Learning - Ultimate Overview in 2023 - viso.ai

Pose Estimation is a computer vision technique to predict and track the location of a person or object. List of use cases and architectures.

viso.ai

 

+ Recent posts