티스토리 뷰

자 다시 돌아왔습니다만.. 그냥 이 부분은 빨리 끝내야 될거 같아서 정리해봅니다. 아마 이 내용이 끝나고 나면 당분간은 올릴 시간이 없을 듯하네요. 무엇보다도 읽으시는 분들이 자료를 직접 찾으시고 스스로 해보는게 중요한 것 같습니다.

 

지난 시간에 구름을 만드는 것까지 해봤습니다. 그리고 배경으로 KinectVideotexture까지 만들어서 보여지는 걸 해봤지요. 이번에 할일은 사람의 골격을 인식해서 그 주변만 따 오는 과정을 구현하려고 합니다. 물론 변수 선언이 먼저 되어야 하겠지요.

 

 

그 후에 이전에 만들었던 AllFrameReady 이벤트 안에 전에 생성했던 코드 밑으로 skeletalTracking에 관한 구문이 생성되어야 합니다. 이전에 한번 다룬적이 있지요.

 

 

이렇게 하면 카메라로부터 받아오는 정보중에 SkeletonFrame에 관한 정보가 들어오면 배열로 저장이 될겁니다. 그런데 받아오는 골격정보를 모두 이용해서는 안됩니다. 키넥트를 쓰다보면 아시겠지만 오차가 발생합니다. 간혹 의자의 골격(?)이 잡혀버리는 경우도 발생하기도 합니다. 따라서 우리가 잡아야 할 것은 활성화된 골격, 즉 골격 포인트가 모두 감지된 개체만을 따라잡아야 합니다. 먼저 이를 골라낼 변수를 지정해줍니다. 아참 추가적으로 활성화된 골격의 정보도 있어야 하므로 그 변수를 Skeleton형으로 잡습니다.

 

 

그 후에 활성화된 정보를 찾기 위한 코드를 앞에서 작성한 SkelParam을 구하는 과정 밑에 작성합니다.

 

 

이전에도 말씀드린 적이 있지만 골격을 인지할 수 있는 상태는 총 3개로 나눠집니다. 하나는 전혀 탐지하지 않는 것, 하나는 그냥 위치 정보만 가져오는 것, 마지막으로 있는 Tracked가 골격이 탐지됬을 경우입니다. 당연히 우리의 조건은 탐지됬을때 활성화가 되야 하므로 Tracked를 선택해줘야 하겠지요. 그러고 나서 활성화된 골격을 Skeletons로부터 받아오면 됩니다. 그에 해당하는 코드는 다음과 같습니다.

 

 

그러고나서 탐지가 된다면 그냥 break에 의해서 for 루프가 빠져나가게 될겁니다. 그대신 생각해보면 속도적인 문제는 발생할 것 같네요. 왜냐면 SkeletalFrame이 하나 감지될때마다 State를 확인하는데 걸리는 시간을 고려해야 하기 때문입니다. 이 부분은 나중에 조금더 고민해봐야 할 부분인 것 같습니다.

 

자 이제 언급해야 될 것은 Mask 기법입니다. Mask란 말은 말 그대로 가리는 겁니다. 그런데 공학적인 의미로는 가린 부위를 제외하고 처리한다는 의미가 더 큽니다. 보통 반도체 공정에서는 이런 마스킹 기법을 이용해서 원하는 곳에 전자우물을 팝니다. 우선 그런 의미로만 받아들이시고 일단은 이미지하나를 다운받아주세요.

 

 

이게 바로 Backgound로 쓸 이미지입니다. 크기는 640x480, 즉 딱 KinectVideoTexture의 크기입니다. 이걸 프로젝트에 삽입하고 LoadContent를 통해서 불러옵니다. 물론 이미지에 대한 변수 정의는 필수 입니다.

 

 

 이제 BackGroundTexture에다가 maskImageColor정보를 받아서 입혀야 하는데 이부분은 조금 뒤에 나옵니다.

자 일단 활성화된 골격정보를 구했으니 이제 그걸 둘러쌀 DepthFrame을 받아와야 합니다. 먼저 변수부터 지정해줍니다.

 

 

그 후에 DepthFrame을 받아올 코드를 작성합니다. 그런데 거의 앞에서 작성한 코드의 구조와 매우 유사합니다.

 

 

이제 이 이미지를 받아온 다음부터 아까 앞에서 언급한 BackgroundTexture와 maskImageColor를 쓰게 됩니다. 바로 밑에 작성하면 됩니다.

 

 

그러고 나서 아까 받았던 ActiveSkeletonNumber를 이용한 조건문을 작성해주면 되겠지요.

 

 

여기서 잠깐 배경지식을 다시 공부해 볼 때입니다.

 

 

 

앞에서도 변수 선언을 했지만 DepthData는 Short형 배열로 선언했습니다. 그 말은 이 DepthData는 16bit로 구성된 정보라는 의미지요. 그리고 기억하실지는 모르겠지만 하위 3bit는 Player에 관한 정보입니다. Player 수에 관한 정보 말입니다. 총 3bit이니까 나올수 있는 경우의 수는 0부터 7까지겠지요. 총 7명까지 Tracking할수 있다는 겁니다.(당연히 0을 빼야 하겠지요.그리고 교재에는 6명까지 DepthTracking을 할 수 있다는데 조금 어폐가 있는거 같네요.)

그러면 Player수 정보를 알기 위해서는 and 연산을 통해서 저 하위 3비트만 따오면 되겠지요. 바이너리로 하든 헥사로 하든 7을 and연산시키면 우리가 원하는 정보를 구할 수 있을 겁니다.

일단 Depth정보를 쭉 읽어오면서 있는 정보를 긁어오면 될겁니다. 그 안에 해당 Player수를 읽어오는 작업을 해주면 되겠습니다.

 

 

그러고나서 이렇게 구한 PlayerNumber와 앞에서 구한 ActiveSkeletonNumber가 일치하면 정확한 정보가 됩니다.

 

 

자 이제 Depth정보에서 실질적으로 Background에 뿌릴 Point를 지정해줘야 합니다. 이 부분은 코드를 그대로 인용해오도록 하겠습니다.

 

 

여기서 주목해야 할 변수와 메서드가 바로 ColorImagePoint와 MapDepthToImagePoint입니다. MapDepthToColorImagePoint는 말그대로 Depth로부터 받은 정보를 토대로 ColorFrame으로 바꿔주는 메서드입니다. 어떻게 보면 마법의 메서드입니다. 이게 한점의 ColorImagePoint로 저장이 되므로 위에서 DepthPos가 증가하면서 해당 정보는 그대로 playerPoint에 저장이 되겠지요. 이 크기를 토대로 gameImagePos가 정해지고 그 해당 배열에 저장된 정보를 변환과정을 거쳐서 넣게끔 하는 겁니다. 마지막에 등장한 Color.FromNonPremultiplied 는 잘 모르겠네요. 궁금하시면 링크 걸어드립니다. 자 일련의 변환과정을 거쳤으니 이 정보를 다시 넣어줘야 합니다.

일단 넣을 판을 만들어주고 거기에 SetData를 통해서 넣어주면 되겠지요.

 

 

 

자 이제 아까 삽입한 하늘색 바탕의 효과를 주려면 Draw에서 불러줘야 하겠지요.

 

 

자 이제 끝났군요. 한번 결과를 봅시다.

 

 

생각보다 거리가 가까울때는 이미지를 읽어오는데 시간이 조금 걸리는것 같습니다. 조금 멀리 떨어지니까 그나마 fps가 제대로 나오는 것 같습니다. 정말 가까이서 하면 거의 게임이 뚝뚝 끊깁니다.

아무튼 이번 포스팅에선 Mask기법을 사용해서 사용자 정보만 Background로 뽑아오는 것에 대해서 다뤄봤습니다. 아마 장시간의 공백이 있을 듯하네요.

댓글