F# でKinectプログラミング(はじめのいっぽ)
このたび、諸事情によりKinectセンサーを扱うことになったので勉強がてらブログに貼り付ける。
私はC#をほとんど知らないので、コードはひたすらF#で記述されていく予定です。
なお、Kinect for Windows SDKを使います。
今回ははじめにということで、先人のお力を借りることにしました。
Kinect SDK and F# - a standard library in a non-standard language | .NET Zone
ここに書かれているコードをもとに、RGB情報をそのまま表示させてみます。
必要知識
といっても、上記ページのコード少しの知識でなんとかなる感じになっていました。
そのまま写すのはアレなので、ここではさらに
を追加しました。単に書くのが面倒になったという噂もありますが…
とりあえずコード全貌
まずXAMLコード
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MyKinectApplication" Height="600" Width="800"> <Grid x:Name="grid" /> </Window>
次にプログラム
open System open System.Windows open System.Windows.Controls open System.Windows.Media.Imaging open Microsoft.Research.Kinect.Nui type MyKinectApplication(window : Window) = let nui = Runtime.Kinects.[0] let application = new Application() let winImage = new System.Windows.Controls.Image() do winImage.Height <- 480.0 winImage.Width <- 640.0 let grid = window.FindName "grid" :?> Grid do winImage |> grid.Children.Add |> ignore do nui.VideoFrameReady |> Observable.subscribe begin fun args -> let image = args.ImageFrame.Image let source = BitmapSource.Create(image.Width, image.Height, 96.0, 96.0, Media.PixelFormats.Bgr32, null, image.Bits, image.Width * image.BytesPerPixel) winImage.Source <- source end |> ignore do window.Loaded |> Observable.subscribe begin fun _ -> nui.Initialize(RuntimeOptions.UseColor ||| RuntimeOptions.UseDepth) nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color) end |> ignore do window.Unloaded |> Observable.subscribe (fun _ -> nui.Uninitialize() ) |> ignore member this.Run() = window |> application.Run [<STAThread>] [<EntryPoint>] let main _ = let window = Application.LoadComponent(new System.Uri("/SampleKinectApplication;component/Window.xaml", System.UriKind.Relative)) :?> Window new MyKinectApplication(window) |> fun app -> app.Run()
勢いがあれば30分弱で作れます。
ちょっとした解説
まず参照設定にWPF関連のものを追加します。
Presentation PresentationFramework WindowsBase System.Xaml
さらにKinect for Windows SDKに含まれているライブラリも追加。
Microsoft.Research.Kinect
MyKinectApplicationクラスですが、生成時にWindowオブジェクトを受け取ります。
Kinectランタイムの取得方法は下記のとおり。
let nui = Runtime.Kinects.[0]
KinectDeviceCollectionの先頭要素から取得します。本当はランタイムが存在するかどうかで処理を変えるように
let nui = if Runtime.Kinects.Count = 0 then Some Runtime.Kinects.[0] else None
とやったほうがいいと思いますが、今回はちょっと省略します。
次にImageコントロールの生成とサイズ設定。
let winImage = new System.Windows.Controls.Image() do winImage.Height <- 480.0 winImage.Width <- 640.0
さらに、Windowから"grid"という名前のGridコントロールを取得しgrid変数に束縛、Imageコントロールをgridの子として追加します。
let grid = window.FindName "grid" :?> Grid do winImage |> grid.Children.Add |> ignore
ここからFRPが登場
do nui.VideoFrameReady |> Observable.subscribe begin fun args -> let image = args.ImageFrame.Image let source = BitmapSource.Create(image.Width, image.Height, 96.0, 96.0, Media.PixelFormats.Bgr32, null, image.Bits, image.Width * image.BytesPerPixel) winImage.Source <- source end |> ignore
VideoFrameReadyイベントが発生したらimageを取得してWPFのImageコントロールに表示。
あとはWindowがloadされたときにランタイムの初期設定を、WindowがunloadされたときにランタイムのUninitializeを行っています。
main関数ではXAMLからコンテンツをロードしてWindowを取得し、MyKinectApplicationを生成してWPFアプリケーションを実行と。
ちょっと汚い感じにクラス化してしまっているので、次回以降はもう少しきれいにします。