티스토리 뷰

우리가 포토샵으로 이미지를 다룰 때 중요하게 다루는 요소가 있습니다. 바로 색분포에 따른 히스토그램입니다. 물론 저는 이미지처리에 대해서 잘 아는 사람이 아닙니다만 보통 이런 히스토그램을 분석하고 노출량을 조절함으로써 사진을 조금더 선명하고 화사하게 바꿀 수 있다는 걸로 알고 있습니다. 

마침 키넥트의 DepthStream으로 나온 정보를 이런 히스토그램으로 뽑을 수 있는 아티클이 있기에 한번 정리해봅니다.
출처는  http://www.i-programmer.info/ebooks/practical-windows-kinect-in-c/3802-using-the-kinect-depth-sensor.html?start=2 입니다. 이 글의 목적은 버튼을 눌렀을 때의 이미지의 히스토그램을 분석하는 것입니다.

우선 기존에는 WPF 방식으로 구현했었는데 이번에는 Winform방식으로 해보고자 합니다. 그래서 VS2010에서 WinForm형식으로 새 프로젝트를 생성합니다.

 `
물론 키넥트 관련 클래스를 사용하기 위해서는 Kinect reference가 삽입되고 using으로 처리가 되어야 하겠지요?
우선은 가운데 디자인뷰에 횡한 창이 하나 떠 있을텐데 여기에 우리가 원하는 컨트롤을 삽입합니다. 일단은 button과 이미지를 출력하기 위한 PictureBox 그리고 히스토그램을 표현하기 위한 Chart 컨트롤을 창상에 삽입해줍니다.


 참고로 chart 컨트롤은 Data ToolBox에 있습니다. 나머지는 Common Control에서 찾으시면 됩니다. 이렇게 삽입해주신후에 이제 코딩을 해줘야 합니다. 우선 써야 할것은 Using 지시자 처리입니다. 


물론 앞에서 말한 것처럼 Kinect에 관한 래퍼런스가 삽입되어야 하고 WinForm상의 PictureBox상에 그려지는 이미지는 Drawing.Imaging으로 처리되어야 합니다. 그리고 마지막으로 실시간으로 받아오는 이미지에 대한 정보와 그 정보를 차트화 시키기 위해서는 밑의 두개 래퍼런스가 추가로 포함되어야 합니다. 자 다시 디자인뷰로 돌아와서 button을 더블클릭합니다. 물론 WPF와 마찬가지로 버튼을 클릭했을때의 이벤트가 자동으로 형성됩니다.


 우선 KinectSensor를 지정해주고 클릭했을때의 이벤트를 다음과 같이 처리해줍니다.


많이 봐오던 내용이지만 일단 DepthStream을 뽑아오기 위해서는 위처럼 처리해줘야하겠지요. 알다시피 += 후에 탭탭을 해주시면 역시 이벤트가 형성됩니다.

물론 이전의 DepthStream을 뽑는 이벤트도 정상적으로 동작하기는 하지만 이번에는 예제에 나온대로 해보겠습니다. 다음과 같이 코딩합니다.


 여기서 갑자기 왜 distance를 왜 저렇게 구하고 3bit을 왜 shift하는지 의아해 하실겁니다. 그 이유는 원문에 나와있습니다. 간단하게 요약해보자면 다음과 같습니다.
 이전 베타버전에서는 ColorStream이나 DepthStream을 VideoImageFrame이라는 메서드를 통해서 받아왔습니다. 이때는 정보가 정수형 배열로 넘어왔고, 16bit으로 받아왔습니다. 그런데 새 버전으로 넘어오면서 DepthStream을 받아오는 게 생기면서 short 형 배열로만 받아올 수 있게되었습니다. 대신 그렇게 받아온 16비트중 상위 13비트에서 사물과 키넥트사이의 거리를 나타내줍니다. 하지만 이같은 경우는 사물의 골격이 키넥트로 받아왔을때만 활성화되고 이에 대한 정보는 하위 또는 상위 3bit을 통해서 알 수 있습니다.

그럼 우리가 받아올 정보는 바로 그 사물에 대한 정보를 제외한 13bit이 되게 됩니다. 그렇기 때문에 3bit 만큼 이동하게 되는겁니다. 다만 상위를 이동할거냐 하위를 이동할 거냐는 윈도우용 키넥트의 기능과 연관이 있습니다. 아시다시피 윈도우용 키넥트에는 엑박용키넥트와 다르게 NearMode를 기본적으로 제공합니다. 만약 3bit이 왼쪽으로 쉬프트된다면 16bit이 가지는 Maximum값은 0xfff8이고 sign 규격으로 따지면 이값은 -8이 나오게 됩니다.반대로 오른쪽으로 쉬프트되면 Maximum은 -1이 되고 앞의 값과 비교해볼때 distance가 작은쪽이 더 인식범위가 넓게 되는 것입니다. 그래서 >> 쉬프트를 하게됩니다.

아무튼 이부분이 조금 복잡하다면 다시 메서드로 뽑아낼 수 있습니다. 다음과 같이 다시 구성하면 되겠습니다.

 
 자 이번에는 bitmap 이미지를 불러와야 합니다. 다음과 같이 칩니다.

 

우선 ImageFrame을 받아오면서 그걸 새로운 bmpdata에 저장하는 과정이 필요한겁니다. 그 과정이 위와 같이 표현된겁니다. Marshal 클래스에 대한 설명은 링크를 참고하시기 바랍니다. 참고로 이 클래스를 이용하기 위해서는 using 지시자를 사용해서 System.Runtime.InteropServices가 포함되어 있어야 합니다.

여기까지 했으면 일단 Bitmap 이미지로까지 저장이 가능한겁니다. 이제 다시 DepthFrameReady 이벤트에서 이를 이미지로 불러와야 하겠지요.이 과정을 처리해줍니다.


그리고 실행시켜보면 다음과 같이 나오게 됩니다.


물질의 반사도에 따른 Depth가 Bitmap으로 나오고 있는 것이지요. 물론 Message 박스가 뜨면서 distance에 관한 정보도 같이 출력해줍니다.


자 이제 Chart를 구성해보겠습니다. DepthFrameReady 부분이 재구성되어야 합니다.


기존에는 getValue를 통해서 받아왔던 imageFrame에 관한 내용을 DepthFrameReady에서 해와야 합니다. 그래서 밑의 조건문에서 처리하고 있는 과정이 바로 그렇게 받아오는 imageFrame의 PixelData를 임시의 통에 담아놓는 과정입니다.

chart로 데이터로 된 수치를 옮기려면 다음과 같이 짭니다.


물론 imageFrame이 없을때 image를 넣는 줄은 주석처리해줘야 하겠지요? 마지막으로 창을 껐을때의 이벤트도 하나 추가해줍니다. 디버깅이 종료되었을때 키넥트도 같이 종료하게끔 해줘야 하겠지요.

디자인뷰상에서 윈도창을 선택한후 이벤트 설정으로 넘어가시면 FromClosing이라는 항목이 있습니다. 이 부분을 더블 클릭해줍니다.


그러면 코드상으로도 이벤트가 형성되는데 여기야 간단하게


키넥트가 멈추게끔 하면 되겠지요. 다음이 결과물입니다.


실시간으로도 처리할 수 있을까요? 그건 보시는 분도 하실 수 있겠지요?



이번 포스팅을 통해서 이미지의 히스토그램을 알아보는 과정을 확인해보았습니다. 물론 WPF로도 할 수 있는데 Chart라는 컨트롤이 따로 없으므로 이 부분은 적당히 처리해줘야하겠네요.

댓글