티스토리 뷰

Kinect

[kinect 프로젝트] Audio Fundamentals

생각많은 소심남 2012. 2. 11. 01:04
QuickStarts 마지막편인 AudioFundamentals 부분입니다. 여기까지만 제대로 들었으면 기본적인 키넥트의 기능을 코드로 또는 xaml로 간단하게 구현하는 건 쉬울 겁니다.
 

<출처: http://channel9.msdn.com/Series/KinectQuickstart/Audio-Fundamentals>

이번 시간에 다뤄볼 내용은 주로 소리 녹음과 언어 인지에 관한 항목입니다.
기존에 윈도용 키넥트 SDK를 정확히 설치했다면

 
이런게 깔릴거고 여기서 Speech Recognition 항목이 언어 인지를 가능하게끔 합니다. 물론 영어만요..

우선은 키넥트에서 소리를 인지하는 상황을 보겠습니다.

  
 첫번째 시간에도 말했었지만 키넥트에는 총 4개의 Microphone Array가 존재합니다. 
그리고 그 4개를 이용해서 소리의 발원지를 찾아냅니다. 크게 키넥트에서 소리의 위치를 찾는데 이용하는 정보는 두가지입니다. 첫번째는 Sound Source angle로 소리의 위치를 -50부터 +50까지의 범위내의 값으로 표현합니다. 만약 0이란 값을 보이고 있으면 키넥트와 소리의 발원지는 딱 일직선상에 있다는 겁니다. 그런 값은 보통 중심에서의 각도와 신뢰도로써 정의된다고 합니다.
 다음은 Beam Angle이라는 건데 내용을 들어보면 흥미롭습니다. 보통 위의 정보를 통해서 소리의 발원지를 찾을 수 있는데 거기에 대해서 Beam을 쏜후 그 발원지와 맞으면 거기에 소리의 초점을 맞추는 기술이랍니다. 예를 들어서 두명이 키넥트상으로 있을때 소리의 발원지를 찾은 후 그 발원지와 Beam angle과 비교해서 원하는 소리를 얻을 수 있다는 겁니다. 가령 녹음 기능을 쓰려고 할 때 조금 효율적으로 녹음할 수 있는 원리가 아닐까 생각됩니다. 이걸 동영상상에서는 발원지가 마이크앞에 바로 있는 것처럼 이란 의미를 부여해서 Directional Microphone이라고 한답니다.


지난 포스팅에서 다뤘는지는 모르겠지만 키넥트내에는 소리를 녹음할 수 있는 기능이 있습니다. KinectAudioSource내의 Audio buffer를 사용합니다. 그런데 제가 지금까지 촬영한 동영상을 보면 외부소리가 거의 잘 안들리는 걸 느끼실겁니다. 이게 바로 Echo Cancellation을 이용해서 주변의 소리를 상쇄시키는 그런 원리로 보시면 됩니다.


이제 할 부분은 음성 인지 기능인데요.. 사람이 어떻게 말했느냐에 따라서  그 기능을 수행하게끔 코드를 구성할 수 있습니다. 물론 이 음성 인지를 원활히 하기 위해서는 사전에 정해진 문법으로 코드를 구성해야 합니다. 그래서 그 코드내에는 grammarBuilder와 해당 조건에 대한 Choice에 대한 항목들이 들어있습니다. 밑에 AutomaticGainControl을 false로 두라는 건 조금 살펴봐야 할 것 같습니다.
 


위에 나오는 문법은 yes라는 뜻을 인지하기 위해 사전에 만들어진 것들 중 하나입니다. 그래서 하나는 xaml로 하나는 c#으로 구성한겁니다. 그런데 보통 yes라는 뜻을 의미하는 문구는 여러가지 가 있지요. 물론 yes 라는 단어도 있겠지만 yeah, yep ok 같은 단어도 그런 뜻을 같기 때문에 하나의 집합으로 형성할 수도 있습니다. 코드상으로는 그냥 단순히 grammar에 삽입하는 형식을 취해주면 키넥트에서 speech recognition이 이뤄지게 됩니다.어쨌든 위와 같은 연산의 결과물은 out._value = "yes" 라는 형식을 갖추게 됩니다. 이걸 응용하면


와 같은 말로 선택할 수 있는 메뉴를 형성할 수 있게 됩니다. 이건 이번 CES 2012에서도 나타났었지요. 출연자가 "Xbox! show me the channel list"라고 하면 Xbox에선 해당 채널을 선택하고 그에 대한 결과물을 보여줍니다. Xbox의 기능이 아닌 Kinect의 Multi Modal feedback 이란 기능을 활용한 것입니다. 이런 기술은 윈도폰내의 음성 인지에서도 나타나지요. 하나의 Voice Command로 발전해나가는 겁니다.

이제 본격적으로 예제를 따라가고자 합니다. 첫번째 예제는 Audio Recorder입니다.



MainWindow상에 두가지 버튼이 있는데 이중에 Record 버튼을 누르게 되면 여기에 연결된 이벤트로 이동합니다. 당연히 지금 실행해도 정상적으로 동작하기 때문에 완성된 코드로 이동하겠지요.


녹화 버튼에 대한 이벤트입니다. 녹화버튼을 누르게 되면 새로운 쓰레드가 생성되면서 날짜로 이름지어진 wave 파일이 자체적으로 생성되게 됩니다. 만약 버튼을 누르게 되면 chooser에 연결된 쓰레드가 실행되겠지요. 일단 쓰레드에 대해서 하기에 앞서 쓰레드 관련 부분은 주석처리하고 밑의 RecordAudio 부분을 활성화시켜서 정의를 살펴봅니다.


그럼 이제 가서 보는 부분은


 이 부분이 되겠습니다. 여기서 본격적으로 Wav파일을 만들게 됩니다 물론 이전에 있던 변수 선언을 통해서 wav 파일을 임시로 저장할 buffer가 설정되어 있어야 합니다. 여기서는 1kbyte로 배열이 형성되었습니다.

우리가 키넥트를 통해서 입력하는 데이터는 음성이지만 컴퓨터 내에서는 하나의 fileStream으로 이동합니다. 물론 하나의 파일로 이동하기 위해서는 그에 대한 헤더(그 파일임을 알기위한 태그라고 보시면 됩니다.)가 필요하고 이를 만드는 과정이 WriteWavHeader라는 겁니다. 물론 레퍼런스에 포함되어 있습니다.

이제 using 지시자를 활용해서 우리가 쓸 소스를 정해야 하는데 이는 맨처음 포스팅에서 동작에 관한 설정을 지정할 때도 잠깐 나왔던 것이지만 AudioSource를 사용하게 됩니다. 이 게 시작하면 하나의 Audio Stream으로 구성되는 겁니다.
그럼 이걸 기록하는 시간과 시작시점 종료시점, 그리고 이번 프로젝트에서 가장 중요한 해당시간에 대한 정보도 메모리의 어딘가에 저장되고 있겠지요. 이에 대한 정보를 루프를 돌리면서 기록하게 됩니다. 이전에 만들었던 buffer안에 말입니다.

지금 이 모든 동작이 하나의 UI 쓰레드내에서 진행됩니다. 그런데 여러분 상상해보세요.
오디오와 같이 실시간으로 받아와야 할 정보가 다른 영상으로 받아야 할 이미지와 함께 한개의 쓰레드내에서 동작이 되는 것을 말입니다. 이건 최근 대두되고 있는 멀티쓰레드와 연관시켜서 생각해볼 수 있습니다. 한개의 쓰레드내에서 모든 걸 처리하려면 분명 무엇인가는 우선순위에서 밀려 나중에 처리되게 됩니다.
예를 들어 지금과 같이 RecordButton에서 그냥 바로 RecordAudio기능을 수행하게 되면 중간에 다른 동작을 못합니다. 그래서 주석으로 달려있던 내용 중 하나가
 


 UI를 freeze 시킬 수 있다는 내용이었습니다. 분명 실행시키고 창을 이동하려고 하면 잘 안될겁니다. 이게 하나의 쓰레드로 처리하는데 있어서 나타날 수 있는 단점입니다.

그럼 이제 위 부분을 주석 처리하고 아까 쓰레드 부분을 주석을 해제합니다.


그리고 정의로 가보면
 


똑같습니다. 다른게 없습니다. 다른게 있다면 이건 다른 쓰레드에서 수행되기 때문에 UI가 freeze 되는 일은 없다는 것이지요. 실행시켜보면

 
창을 흔들고 있는데도 녹음이 정상적으로 이뤄짐을 볼 수 있습니다.

이제 다음으로 해볼 예제는 첨부파일속 다른 프로젝트에 있는 KinectAudioDemo입니다.


 이 이미지가 뭘 의미할까요? 바로 소리의 위치를 알려주는 레이더의 역할을 합니다. 이 부분에 해당하는 코드를 보면
PollSoundSourceLoacalization에서 수행합니다.
 일단 위 그림에서도 보이듯 가장 중요한 요소는 센서에서 소리의 발원지간의 거리와 이루는 각도이겠지요. 그 부분을


의 SoundSourceAngle에서 받아오고 있습니다. 아까 언급한 값중에 SoundPosition에 관한 항목이 바로 여기 해당됩니다. 그러면 여기로 리턴되는 값은 -50에서 50사이의 값이 되겠지요.
하지만 단순히 SoundSourceAngle만 받아오기에는 값이 튈 확률이 있기 때문에 여기에 신뢰도를 높이기 위해서 AngleChangeSmoothingFactor를 곱한다고 설명하고 있습니다. 만약 센서와 키넥트사이의 각도를 구하실 일이 있으시다면 이 부분을 인용하면 좋을 것 같습니다.

이제 다음으로 볼 부분은 바로 음성인지기능입니다. 요즘에 이 음성인지기능은 정말로 신기술의 극치를 달리고 있습니다. CES 2012에선 Xbox를 음성으로 컨트롤하면서 리모콘이 필요없는 세상을 구현하고 있고, 가까이에는 애플 아이폰 4s의 Siri 정도가 있겠네요. 키넥트에선 앞에서 언급했던 것처럼 그냥 문법에 원하는 문구만 삽입하면 됩니다. 다만 전제 조건이 있습니다.


물론 윈도용 SDK를 설치하신분이라면 Speech Recognition SDK가 같이 설치될겁니다만 베타를 설치하신 분이라면 반드시 이부분을 설치하셔야 됩니다. 기본 SDK에 Speech Recognition에 관한 항목이 없기 때문입니다.


바로 이부분이 문법적으로 인지할 수있는 문구라고 보면 되겠습니다. 보면 앞에서 나온것처럼 grammar에 add시킨것 밖에 없습니다. 이 문법들을 사용하기 위해서는


밑의 LoadGrammar라는 항목을 통해서 이뤄집니다. 그러니 이렇게 Loading을 시켜야 되겠지요. 그중에 맨처음에 있는 SreSpeechRecognized 항목의 정의를 살펴보겠습니다.


우선은 강도에 따라서 인지할 범위를 정해줘야 합니다. 너무 작은 소리는 키넥트의 마이크로폰으로도 감지가 힘들기 때문에 이부분을 인지하면 오류가 발생할 가능성이 큽니다. 그래서 일정 범위 이하의 결과물에 대해서는 수행하지 않는 방향으로 이뤄지겠지요.


여기서 아까 grammar로 삽입했던 것에 대한 동작이 이뤄집니다. 그런데 유의해야할 점은 케이스 구문의 조건이 다 대문자이어야 한다는 겁니다.일단 중간에 notepad가 있는 줄을 주석처리한후 실행시켜보겠습니다.(왜냐면 지금 notepad가 있는 구문은 Camera on이라고 말했을때 notepad가 실행되는 구문이기에 뒤에서 실행시켜보겠습니다.)


인지되는 거보이시나요? 덕분에 저도 영어 발음 연습해봤습니다. 생각보다 잘 인식하더군요.
자이제 아까 주석처리했던 notepad 부분을 주석제거하고 다시 실행시켜봅니다.


이상하게 음성인지할때 카메라가 늘어지는 현상이 발생하네요. 아무튼 정상적으로 인지합니다.
그럼 마지막으로 gammar.add로 notepad를 삽입시킨후 저 부분을 NOTEPAD로 바꾼 후 실행시켜보겠습니다.
제가 삽입한 부분은 





인데 실행결과는 다음과 같습니다.


와 생각보다 발음을 잘 인지합니다.이런 기술이 키넥트로써 구현이 가능하다는게 저에게는 너무나 신기할 따름입니다. 더 공부할 의욕이 생깁니다+_+
여기까지가 Channel 9에서 다룬 Kinect QuickStarts의 내용이었습니다. 물론 동영상에서 다룬 내용에 조금 첨부해서 언급한 부분도 있지만 여기까지 따라오셨다면 기본적인 키넥트의 기능은 이용하실 수 있을걸로 생각됩니다.
이제 다음부터는 개발자가 직접 만든 프로젝트를 하나씩 훑어보면서 코드를 분석해보고자 합니다. 아마 제 기억이 맞다면 첫번째 프로젝트는 키넥트로 그림그리는 Paint Project였던것 같습니다. 담주부터는 키넥트 교육도 있는데 시간날때마다 올리도록 하겠습니다. 읽어주셔서 감사합니다~!

댓글