I followed the code provided by Robert Levy at this link:
http://channel9.msdn.com/coding4fun/kinect/Display-Kinect-color-image-containing-only-players-aka-background-removal
私はそれを私の既存のコードに実装しようとしましたが、矛盾した結果がありました。プログラムの起動時にユーザがkinectの視界にいる場合、時間の一部をバックグラウンドで削除します。ユーザが視界に入ると、それを拾いません。
namespace KinectUserRecognition
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//Kinect Runtime
Runtime kinect = Runtime.Kinects[0];
PlanarImage colorImage;
PlanarImage depthImage;
bool isDepthImage;
WriteableBitmap player1;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
isDepthImage = false;
//UseDepthAndPlayerIndex and UseSkeletalTracking
kinect.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseColor);// | RuntimeOptions.UseSkeletalTracking);
//register for event
kinect.VideoFrameReady += new EventHandler(nui_VideoFrameReady);
kinect.DepthFrameReady += new EventHandler(nui_DepthFrameReady);
//Video image type
kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480,
ImageType.Color);
//DepthAndPlayerIndex ImageType
kinect.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240,
ImageType.DepthAndPlayerIndex);
}
void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
{
colorImage = e.ImageFrame.Image;
image1.Source = BitmapSource.Create(colorImage.Width, colorImage.Height, 96, 96,
PixelFormats.Bgr32, null, colorImage.Bits, colorImage.Width * colorImage.BytesPerPixel);
if (isDepthImage)
{
player1 = GeneratePlayerImage(e.ImageFrame, 1);
image3.Source = player1;
}
}
void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)
{
//Convert depth information for a pixel into color information
byte[] ColoredBytes = GenerateColoredBytes(e.ImageFrame);
depthImage = e.ImageFrame.Image;
image2.Source = BitmapSource.Create(depthImage.Width, depthImage.Height, 96, 96, PixelFormats.Bgr32, null,
ColoredBytes, depthImage.Width * PixelFormats.Bgr32.BitsPerPixel/8);
isDepthImage = true;
}
private WriteableBitmap GeneratePlayerImage(ImageFrame imageFrame, int playerIndex)
{
int depthWidth = kinect.DepthStream.Width;
int depthHeight = kinect.DepthStream.Height;
WriteableBitmap target = new WriteableBitmap(depthWidth, depthHeight, 96, 96, PixelFormats.Bgra32, null);
var depthRect = new System.Windows.Int32Rect(0, 0, depthWidth, depthHeight);
byte[] color = imageFrame.Image.Bits;
byte[] output = new byte[depthWidth * depthHeight * 4];
//loop over each pixel in the depth image
int outputIndex = 0;
for (int depthY = 0, depthIndex = 0; depthY < depthHeight; depthY++)
{
for(int depthX = 0; depthX < depthWidth; depthX++, depthIndex +=2)
{
short depthValue = (short)(depthImage.Bits[depthIndex] | (depthImage.Bits[depthIndex + 1] << 8));
int colorX, colorY;
kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(
imageFrame.Resolution,
imageFrame.ViewArea,
depthX, depthY, //depth coordinate
depthValue, //depth value
out colorX, out colorY); //color coordinate
//ensure that the calculate color location is within the bounds of the image
colorX = Math.Max(0, Math.Min(colorX, imageFrame.Image.Width - 1));
colorY = Math.Max(0, Math.Min(colorY, imageFrame.Image.Height - 1));
output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 0];
output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 1];
output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 2];
output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) == playerIndex ? (byte)255 : (byte)0;
}
}
target.WritePixels(depthRect, output, depthWidth * PixelFormats.Bgra32.BitsPerPixel/8, 0);
return target;
//return output;
}
private static int GetPlayerIndex(byte firstFrame)
{
//returns 0 = no player, 1 = 1st player, 2 = 2nd player...
//bitwise & on firstFrame
return (int)firstFrame & 7;
}
}
}
– 編集1-
私は問題を絞り込んだと思うが、それを解決する方法は不明だ。私はkinectの視野に1人しかいないと、私の
“GetPlayerIndex”メソッドから1の値を返すと仮定しました。これはそうではありません。背景を取り除いた人物ごとに別々のイメージを作りたいと思っていました。私が受け取るべき値のタイプ:
– 編集2-
私のテストから、私はプレーヤーのインデックスの最大値は6になることに気付きましたが、私が得たインデックスは一貫していません。どのプレイヤーのインデックスがスケルトンに割り当てられるのか知る方法があれば?たとえば、私が唯一の邦人だったら、自分の選手インデックスが常に1であることを知る方法がありますか?
プレーヤーのインデックスは何も保証されていません。スケルトンをキャッチすると、そのスケルトンが見えなくなるまでインデックスは同じままになりますが、最初のプレイヤーが1で、2番目のプレイヤーが2であると仮定することはできません。
あなたがする必要があることは、 player1 =
GeneratePlayerImage(e.ImageFrame、1);
コールの前に有効なスケルトンインデックスを決定するか、またはGeneratePlayerImage関数を変更してインデックスを見つけることです。背景を取り除き、フレーム内のすべての人々のピクセルをそのままにしたい場合は、これを変更してください:
output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) == playerIndex ? (byte)255 : (byte)0;
特定のプレイヤーではなく、どんなプレイヤーかをチェックするだけです。
output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) != 0 ? (byte)255 : (byte)0;
私が考えることができる他の2つの方法は、すべてのプレーヤーではなく特定のプレーヤーのためにこれを行うことです。
- Kinectのスケルトンフィードを開き、有効なインデックスを見つけるためのスケルトンの配列をループします。このインデックスを保持するグローバル整数を作成し、このグローバル整数でGeneratePlayerImageメソッドを呼び出します。
- 各ピクセルのプレーヤーインデックスを確認するGeneratePlayerImageメソッドを変更し、見つかった場合はそのインデックスを使用して画像全体の背景を削除します(見つかった他のインデックスは無視します)。