본문 바로가기
공부공부/2023 쌓여가는 나의 지식~

MediaPipe와 Yolo모델을 이용한 사람 관절 오토 라벨링 [Labelme Tool 사용 및 수정(3)]

by Lee_story_.. 2023. 12. 21.
728x90

 

 

 

이미지 인식 라벨링을 위한 Labelme Tool 사용 및 수정(1)

특정 이미지에 대해서 학습을 시키기 위해선 모델도 중요하지만 정확히 라벨링 된 이미지파일들도 매우 중요하기에 직접 제작 해보려 했으나 구현해야할 기능들이 너무 많아.... 포기.. 그래서

ljhyunstory.tistory.com

 

 

 

Python 영상 프레임 단위 분할 [Labelme Tool 사용 및 수정(2)]

이번엔 라벨미툴에서 영상을 받아, 프레임 단위의 이미지들로 만들기 위한 함수들을 만들어 보았습니다. 기본적으로 opencv를 이용하여 아래와 같은 방법으로 이미지를 분할 저장해주었습니다. w

ljhyunstory.tistory.com

 

 

 

 

지금까지, Labelme를 커스터마이징하여 영상관련 처리와 필요한 기능만을 남겨주었습니다.

이제 제가 할 일은 라벨링....

 

 

처음보다는 훨씬 수월해졌지만 그래도 라벨링을 사람이 직접하게 되니까 속도 측면에서 문제가 있는것 같습니다.

 

그래서 이번엔 반 자동으로 라벨링해주는 기능도 추가해보았습니다. 

 

현재 사람의 상반신 관절, 손 관절 부분데이터가 필요하기에 

아래와 같이 기능을 개발해 보았습니다. 

 

 

 

 

 

변경기능!


기존 Labelme에서 변경된 내용은 아래와 같습니다.

  1. 영상을 읽어와 프레임 단위의 이미지로 나누어 저장 (전체/ 일부 로 저장하는 방식의 차이를 두어 개발)
  2. 원활한 레이블링을 위한 오토 라벨링 기능 개발
  3. 액션 레이블링을 위한 기능 개발
  4. 밝기, 파일 읽기등의 활용도가 낮은 기능 제거

영상 프레임 처리

  • opencv2를 이용하여, 변수의 조절을 통해 원하는 fps로 이미지 수를 조절할 수 있도록 개발
  • 영상 전체를 프레임단위로 분할하여 저장하는 방법과 현재까지 읽어들인 이미지의 끝에 도달하면 새로운 이미지를 읽어오는 2가지 방식을 개발

오토 레이블링

  • 사람의 경우 Mediapipe와 Detectron2, yolo모델을 각각 사용해본 결과 yolo모델이 속도 측면에서 앞서, 채택하여 개발
  • 손의 경우 Yolo에서 인식하여 저장해놓은 관절 데이터중 손목 부근의 사각 범위를 지정하여, Mediapipe를 통해 각 오른/왼 손의 관절데이터를 저장
  • 기타기능으로 손 방향 변경, 사람 재탐색, 앞선 레이블링 데이터 불러오기 등의 기능 또한 개발

 -상반신의 관절데이터만 레이블링하는 기능에서, 전신 관절데이터를 저장하는 기능까지 추가

(AutoTab >> AutoBodySkeleton)

 

 


액션 레이블링

  • 액션 라벨링의 부분은 현재 손 동작에 따른 부분만 개발되었기에, 라벨링된 오른/왼 손에 대한 동작만 저장가능하게 개발
  • 현재는 단순히 손에 어떤것이 있는지, 어떤 행동을 하고 있는지를 레이블링 가능하지만, 추후 레이블링 클래스에 대한 의논이 필요
  • 손 동작에 대해 학습시킨 모델을 만들게 되면 이를 통해 손동작 또한 자동 라벨링 가능할 것으로 보임

 

 

 

 

 

여기까지가 요약!

 

 

코드는 모두 깃허브에 업로드 해 놓았습니다!

(불친절한 코드지만..)

 

https://github.com/jhyun-lee/Auto_Labelme

 

GitHub - jhyun-lee/Auto_Labelme

Contribute to jhyun-lee/Auto_Labelme development by creating an account on GitHub.

github.com

 

사용방법이나 어떤 기능이 있는지는 해당 깃허브의 자동 라벨링 툴 -20231205.pdf에 잘 정리 되어있습니다. 

(용량부족으로 못올리네요;;)

 

 

 

 

 

구현 방법에 대해서는 모든 코드를 설명할 순 없지만, 이어 설명하겠습니다. 

 

 

인식


 

 

인식은 총 3개의 단계를 거치도록 구성해 주었습니다. 

1. 전체 이미지에서 사람을 인식 / 상반신 관절 인식

2. 각각의 상반신 관절을 토대로 손의 대략적인 위치에 각 박스 레이블링

3. 생성된 손 박스 레이블링 내부에서 손 관절 인식 실행

 

동시에 진행 할 수도 있지만 상반신의 관절의 경우 약간의 틀어짐이 발생함으로,

각 단계를 실행하며 약간의 수정을 진행하여, 최적의 데이터를 만들어 낼 수 있기에 단계를 구분지어 놓았습니다.  

 

 

 

 

사람의 인식부분에서는 yolo모델이 가장 최적의 효율을 보이기에 선택해주었습니다. 

모델명은 YOLOv8 pose!

 

 

Pose

Learn how to use Ultralytics YOLOv8 for pose estimation tasks. Find pretrained models, learn how to train, validate, predict, and export your own.

docs.ultralytics.com

 

 

 

 

아래와 같은 키포인트를 가집니다.

 

 

 

라벨툴에서는 LineStrip으로 표현을 해야하기에 10,8,6,5,7,9 순으로 라벨을 구성해 주었습니다. 

{
      "label": "P3_Skeleton",
      "points": [
        [
          1660.0,
          460.0
        ],
        [
          1792.0,
          192.0
        ],
        [
          1731.0,
          0.0
        ],
        [
          1281.0,
          54.0
        ],
        [
          1224.0,
          259.0
        ],
        [
          1436.0,
          486.0
        ]
      ],
      "group_id": null,
      "description": "",
      "shape_type": "linestrip",
      "flags": {}
    },

 

 

 

 

그후 팔꿈치 지점과 손목지점의 거리를 일정 비율 만큼 연장한 부분에 사각 박스 라벨링을 생성해 주었습니다. 

def RHHand_Line_extens(point10,point8,point9,point7): ## 오른쪽, 왼쪽 손 박스 관련
    
    DetectPoint_R=None
    DetectPoint_L=None

     ## 손의 좌표
    def cal(point):
        
        dx = point[0][0] - point[1][0]
        dy = point[0][1] - point[1][1]

        length = math.sqrt(dx**2 + dy**2)

        if length==0:
            return point[0]


        unit_vector_x = dx / length
        unit_vector_y = dy / length
        
        Ax = point[0][0] + 100 * unit_vector_x
        Ay = point[0][1] + 100 * unit_vector_y

        return [Ax,Ay]
    

    DetectPoint_R=cal([point10,point8])
    DetectPoint_L=cal([point9,point7])



    return DetectPoint_R,DetectPoint_L

 

 

 

그 후 라벨링 된 각각의 손 박스에서 각각의 손을 인식하는 부분을 만들어 주었습니다.

def dectect(point): ## 손 인식 부분
                img = image[int(point[1]):int(point[3]), int(point[0]):int(point[2])]  # [min_y:max_y, min_x:max_x]

                checkbool=0
                hand=""

                results = _hands.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

                wrists = []


                if results.multi_hand_landmarks:

                    handedness = results.multi_handedness
                    hand_landmarks = results.multi_hand_landmarks
                    
                    if(len(hand_landmarks)==1):## 한쪽손만 인식됨
                        checkbool=1

                    elif(len(hand_landmarks)>=2):
                        checkbool=2


                    for i in range(len(hand_landmarks)):
                        all_x = []
                        all_y = []
                        all_point=[]

                        for hnd in mp_hands.HandLandmark:
                            all_x.append(hand_landmarks[i].landmark[hnd].x)
                            all_y.append(hand_landmarks[i].landmark[hnd].y)
                            
                            all_point.append([hand_landmarks[i].landmark[hnd].x* img.shape[1]+point[0]
                                            ,hand_landmarks[i].landmark[hnd].y* img.shape[0]+point[1],hnd])

                        hand_x1 = int(np.min(all_x) * img.shape[1] + point[0])
                        hand_y1 = int(np.min(all_y) * img.shape[0] + point[1])
                        hand_x2 = int(np.max(all_x) * img.shape[1] + point[0])
                        hand_y2 = int(np.max(all_y) * img.shape[0] + point[1])

                        hand_x1 = 0 if hand_x1 - 10 < 0 else hand_x1 - 10
                        hand_y1 = 0 if hand_y1 - 10 < 0 else hand_y1 - 10
                        hand_x2 = width - 1 if hand_x2 + 10 >= width else hand_x2 + 10
                        hand_y2 = height - 1 if hand_y2 + 10 >= height else hand_y2 + 10

                        wrist_x, wrist_y = hand_landmarks[i].landmark[mp_hands.HandLandmark.WRIST].x, hand_landmarks[i].landmark[mp_hands.HandLandmark.WRIST].y


                        x, y = int(wrist_x * img.shape[1] + point[0]), int(wrist_y * img.shape[0] + point[1])
                        wrists.append([x, y])


                        # print(handedness[i].classification[0].label)
                        hand = handedness[i].classification[0].label

                        
                        Hands_List.append(all_point)
                        Hands_Box_List.append([hand_x1,hand_y1,hand_x2,hand_y2])
                        Hands_Log_List.append(handedness[i].classification[0].score)
                        Hands_Label_List.append(hand)

                else:
                    print("인식된 정보 없음!")
                    
                return hand,checkbool

            hand,checkbool=dectect([min_x,min_y,max_x,max_y])

 

 

 

 

액션 라벨링은 인식된 손에 대해 직접 이름을 부여하여 레이블링하는 방식!

 

 

 

 

실행 

 

 

 

 

 

 

전신 레이블링도 가능하게 개발하였습니다. 

 

 

 

 

 

끝! 

 

 

 

 

틀린 점이 있다면 댓 달아주세요!

 

 

 

 

 

 

 

 

댓글