用 F# 和 Kinect +OpenNI 產生 Point Cloud
Posted by tjwei on 星期二, 7月 12, 2011 with No comments
這和前一篇 用 F# 和 Kinect SDK 產生 Point Cloud 是幾乎一樣的程式,只不過改用 OpenNI 而不是用 Kinect SDK beta。 OpenNI 支援將色彩和深度資訊重合,所以出來的結果比之前手工亂搞的正確得多。但是似乎沒有 Kinect SDK 的 ready callback 機制,所以用 background worker 取代。
OpenNI 似乎也不支援 80x60 的解析度。
OpenNI 似乎也不支援 80x60 的解析度。
open System open System.Xaml open System.Windows open System.Windows.Controls open System.Windows.Media open OpenNI open System.Windows.Media.Media3D open System.Threading open System.ComponentModel let input_res_x, input_res_y = 640, 480 //resolution of the camera let step_x, step_y =4, 4 //for down sampling let rx,ry= input_res_x/step_x , input_res_y/step_y //there are rx*ry cubes let screenZ = 100. //on a "screen" let screenX = screenZ * 2.*(Math.Sin (38.5*Math.PI/180.0)) let screenY = screenZ * 2.*(Math.Sin (21.5*Math.PI/180.0)) let dX, dY=screenX /(float rx), screenY /(float ry) //the size of each cube let smallCube (p:Vector3D) = let i,j=Vector3D(dX,0.,0.)/2.0,Vector3D(0.,dY,0.)/2.0 let k=Vector3D(0., 0., dX)/2.0 let g=new MeshGeometry3D() [p-i-j-k;p+i-j-k;p+i+j-k;p-i+j-k;p-i-j+k;p+i-j+k;p+i+j+k;p-i+j+k] |> List.iter (fun v -> Point3D(v.X, v.Y, v.Z) |> g.Positions.Add) [[2;1;0];[2;0;3]; [7;3;0];[7;0;4]; [6;5;1];[6;1;2]; [7;6;2];[7;2;3]; [5;6;7];[5;7;4]; [1;5;4];[0;1;4]] |> Seq.concat |> Seq.iter g.TriangleIndices.Add let mat = new DiffuseMaterial(Brushes.White.Clone()) let st= new ScaleTransform3D(1.0, 1.0, 1.0) GeometryModel3D(Geometry = g, Material=mat, Transform=st) let models = Model3DGroup() //the model group contains cubes and lights let vprt = // 3d viewport which moves periodically let translation = TranslateTransform3D(0., 0., 45.) let rotation = AxisAngleRotation3D(Vector3D(0.,1.,0.), 30.) let rotation2 = AxisAngleRotation3D(Vector3D(1.,0.,0.), 30.) let anim = Animation.DoubleAnimation (-40., 40., Duration(System.TimeSpan.FromSeconds 8.), AutoReverse=true, RepeatBehavior = Animation.RepeatBehavior.Forever) let anim2 = Animation.DoubleAnimation (-20., 20., Duration(System.TimeSpan.FromSeconds 21.), AutoReverse=true, RepeatBehavior = Animation.RepeatBehavior.Forever) let tg=Transform3DGroup() rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, anim) rotation2.BeginAnimation(AxisAngleRotation3D.AngleProperty, anim2) tg.Children.Add (RotateTransform3D rotation) tg.Children.Add (RotateTransform3D rotation2) tg.Children.Add translation Viewport3D(Camera = PerspectiveCamera(Point3D(0.,0., -50.), Vector3D(0., 0., 1.), Vector3D(0., 1., 0.), 60., Transform=tg)) let sqCloud = [for iy in [0 .. (ry-1)] do for ix in [0 .. (rx-1)] do yield Vector3D((float(ix-rx/2))*dX, (float(ry/2-iy))*dY, 100.) |> smallCube ] let context=new Context() let mapMode = new MapOutputMode(XRes=input_res_x, YRes=input_res_y, FPS=30) let color=new ImageGenerator(context, MapOutputMode=mapMode, PixelFormat=PixelFormat.RGB24) let depth=new DepthGenerator(context, MapOutputMode=mapMode) let wnd=Window(Title = "Kinect Depth", Background=Brushes.Black, Content=vprt) let app=new Application() let updateCloud zList= sqCloud |> List.iter2 ( fun (z, argb) p -> ((p.Material :?> DiffuseMaterial).Brush :?> SolidColorBrush).Color <- argb let st=(p.Transform :?> ScaleTransform3D) st.ScaleX <- z st.ScaleY <- z st.ScaleZ <- z ) zList let handleDepth (dmap:UInt16MapData) (cmap:MapData<RGB24Pixel>) = let void_color = Color.FromArgb (byte 0, byte 0,byte 0, byte 0) let zList=[for y in 0 .. step_y .. dmap.YRes-step_y do let yline=y*dmap.XRes for x in 0 .. step_x .. dmap.XRes-step_x do let z=(float dmap.[yline+x])/(float depth.DeviceMaxDepth) let argb = if z=0.0 then void_color else cmap.[yline+x] |> fun c -> Color.FromRgb (c.Red, c.Green, c.Blue) yield (z, argb)] ((new ThreadStart(fun () -> updateCloud zList), null) |> app.Dispatcher.BeginInvoke).Wait() |>ignore let bgWorker=new BackgroundWorker(WorkerSupportsCancellation = true) depth.AlternativeViewpointCapability.SetViewpoint color vprt.Children.Add (ModelVisual3D(Content = models)) sqCloud |> List.iter models.Children.Add AmbientLight() |> models.Children.Add context.StartGeneratingAll() fun _ -> while not bgWorker.CancellationPending do context.WaitAndUpdateAll() handleDepth (depth.GetDepthMap()) (color.GetRGB24ImageMap()) |> bgWorker.DoWork.Add bgWorker.RunWorkerAsync() wnd.Closed.Add (fun e -> do bgWorker.CancelAsync() context.StopGeneratingAll() context.Shutdown() Environment.Exit 0 ) [<STAThread>] do app.Run(wnd) |> ignore
0 意見:
張貼留言