지금까지, Labelme를 커스터마이징하여 영상관련 처리와 필요한 기능만을 남겨주었습니다.
이제 제가 할 일은 라벨링....
처음보다는 훨씬 수월해졌지만 그래도 라벨링을 사람이 직접하게 되니까 속도 측면에서 문제가 있는것 같습니다.
그래서 이번엔 반 자동으로 라벨링해주는 기능도 추가해보았습니다.
현재 사람의 상반신 관절, 손 관절 부분데이터가 필요하기에
아래와 같이 기능을 개발해 보았습니다.
변경기능!
기존 Labelme에서 변경된 내용은 아래와 같습니다.
- 영상을 읽어와 프레임 단위의 이미지로 나누어 저장 (전체/ 일부 로 저장하는 방식의 차이를 두어 개발)
- 원활한 레이블링을 위한 오토 라벨링 기능 개발
- 액션 레이블링을 위한 기능 개발
- 밝기, 파일 읽기등의 활용도가 낮은 기능 제거
영상 프레임 처리
- opencv2를 이용하여, 변수의 조절을 통해 원하는 fps로 이미지 수를 조절할 수 있도록 개발
- 영상 전체를 프레임단위로 분할하여 저장하는 방법과 현재까지 읽어들인 이미지의 끝에 도달하면 새로운 이미지를 읽어오는 2가지 방식을 개발
오토 레이블링
- 사람의 경우 Mediapipe와 Detectron2, yolo모델을 각각 사용해본 결과 yolo모델이 속도 측면에서 앞서, 채택하여 개발
- 손의 경우 Yolo에서 인식하여 저장해놓은 관절 데이터중 손목 부근의 사각 범위를 지정하여, Mediapipe를 통해 각 오른/왼 손의 관절데이터를 저장
- 기타기능으로 손 방향 변경, 사람 재탐색, 앞선 레이블링 데이터 불러오기 등의 기능 또한 개발
-상반신의 관절데이터만 레이블링하는 기능에서, 전신 관절데이터를 저장하는 기능까지 추가
(AutoTab >> AutoBodySkeleton)
액션 레이블링
- 액션 라벨링의 부분은 현재 손 동작에 따른 부분만 개발되었기에, 라벨링된 오른/왼 손에 대한 동작만 저장가능하게 개발
- 현재는 단순히 손에 어떤것이 있는지, 어떤 행동을 하고 있는지를 레이블링 가능하지만, 추후 레이블링 클래스에 대한 의논이 필요
- 손 동작에 대해 학습시킨 모델을 만들게 되면 이를 통해 손동작 또한 자동 라벨링 가능할 것으로 보임
여기까지가 요약!
코드는 모두 깃허브에 업로드 해 놓았습니다!
(불친절한 코드지만..)
https://github.com/jhyun-lee/Auto_Labelme
사용방법이나 어떤 기능이 있는지는 해당 깃허브의 자동 라벨링 툴 -20231205.pdf에 잘 정리 되어있습니다.
(용량부족으로 못올리네요;;)
구현 방법에 대해서는 모든 코드를 설명할 순 없지만, 이어 설명하겠습니다.
인식
인식은 총 3개의 단계를 거치도록 구성해 주었습니다.
1. 전체 이미지에서 사람을 인식 / 상반신 관절 인식
2. 각각의 상반신 관절을 토대로 손의 대략적인 위치에 각 박스 레이블링
3. 생성된 손 박스 레이블링 내부에서 손 관절 인식 실행
동시에 진행 할 수도 있지만 상반신의 관절의 경우 약간의 틀어짐이 발생함으로,
각 단계를 실행하며 약간의 수정을 진행하여, 최적의 데이터를 만들어 낼 수 있기에 단계를 구분지어 놓았습니다.
사람의 인식부분에서는 yolo모델이 가장 최적의 효율을 보이기에 선택해주었습니다.
모델명은 YOLOv8 pose!
아래와 같은 키포인트를 가집니다.
라벨툴에서는 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])
액션 라벨링은 인식된 손에 대해 직접 이름을 부여하여 레이블링하는 방식!
실행
전신 레이블링도 가능하게 개발하였습니다.
끝!
틀린 점이 있다면 댓 달아주세요!
'공부공부 > 2023 쌓여가는 나의 지식~' 카테고리의 다른 글
(FastApi & Tree view)를 이용한 디렉토리 관리 웹 페이지 구축 (2) - 디렉토리 기능 관련 (1) | 2023.12.22 |
---|---|
블렌더를 이용해 간단한 3D 모델 만들기 (0) | 2023.12.09 |
(FastApi & Tree view)를 이용한 디렉토리 관리 웹 페이지 구축 (1) - GUI 관련 (0) | 2023.12.08 |
Fastapi를 이용한 웹페이지 구성 (2) - 웹 페이지 연결 및 구성 & Get/Post (1) | 2023.12.07 |
Fastapi를 이용한 웹페이지 구성 (1) - 설치 및 사용 (1) | 2023.12.06 |
댓글