読者です 読者をやめる 読者になる 読者になる

Kinect距離画像を8bitに変換してopenCVSで使う

Kinect(V2じゃないです)で取得した距離画像は16bit(正確にはプレイヤーインデックスを含んでいたりしますが...)なので、こんな感じになります。
f:id:katosunmemo:20150617224604j:plain

でもopenCVSで処理するためにIplimageに入れるとこうなっちゃう。
f:id:katosunmemo:20150617224454j:plain


今回は16bitの画像を8bitに落としてIplimageに格納するメモです。
(変換に次ぐ変換で、ほんとにこれでいいの?って感じはしますが...)


1.KinectからDepthImageFrame型で入力
2.short型配列にピクセルデータをコピー(この段階ではまだ16bit)
3.先ほどのピクセル配列をBitmapSource型の画像化する(ここでピクセルフォーマットを8bitにする)
4.再びbyte型配列にピクセルとして格納
5.BitmapData画像をメモリにロック
6.4のピクセルを Marshal.Copyを使ってBitmapData型画像にコピー
7.先ほどのBitmapData画像のロックを解除してBitmap画像に格納している?(ゴメンナサイ、ここについてはよくわかりません)
8.Iplimageに変換

と言った流れになっています。
最初のDepthImageFrame型の入力は保存しておいて、openCVSで処理した座標の値をオリジナルから読み出すという風にしておけば分解能が下がってしまうというのも防げるのではないかなと思います。

        //距離画像取得イベント
        void kinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame frame = e.OpenDepthImageFrame())
            {
                if (frame == null)
                {
                    return;
                }
                
                short[] depthPixel = new short[frame.PixelDataLength];
                frame.CopyPixelDataTo(depthPixel);
                

                // DepthImagePixel で取得すると、16bitの距離データ+プライヤーインデックス
                // が取得できる(480x640)
                DepthImagePixel[] depth = new DepthImagePixel[frame.PixelDataLength];

                //距離画像をピクセルにバラす(中身は距離情報)
                //原点から右にナンバリング
                //距離を表示する時にアクセスする
                frame.CopyDepthImagePixelDataTo(depth);

                //距離画像を8bitに変換してIplImageにする
                BitmapSource convertedFrame_BS = BitmapSource.Create(frame.Width, frame.Height, 96, 96,
                    PixelFormats.Gray8, null, ConvertDepthFrame(depthPixel, ((KinectSensor)sender).DepthStream),
                    frame.Width * PixelFormats.Gray8.BitsPerPixel / 8);
                int width = (int)convertedFrame_BS.Width;
                int height = (int)convertedFrame_BS.Height;
                int stride = width;
                byte[] datas = new byte[stride * height];
                convertedFrame_BS.CopyPixels(datas, stride, 0);

                Bitmap convertedData_BM = new Bitmap(
                    width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

                System.Drawing.Imaging.BitmapData convertedBits_BD = convertedData_BM.LockBits(
                    new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly,
                    System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

                Marshal.Copy(datas, 0, convertedBits_BD.Scan0, datas.Length);

                convertedData_BM.UnlockBits(convertedBits_BD);

                depthImageforCV_8bit = convertedData_BM.ToIplImage();

                Cv.ShowImage("処理画像", depthImageforCV_8bit);

                
            }
        }