I'm trying to display number of players detected by Kinect sensor using an WPF application. In addition to displaying number of player I have also coloured the pixels based on their distance from the Kinect. Original goal was to measure the distance of the pixels and display the distance but I would also like to display how many people are in the frame. Here is the code snippets that I'm using now.
PS I have borrowed the idea from THIS tutorial and I'm using SDK 1.8 with XBOX 360 Kinect (1414)
private void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame==null)
{
return;
}
byte[] pixels = GenerateColoredBytes(depthFrame);
int stride = depthFrame.Width * 4;
image.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height,
96, 96, PixelFormats.Bgr32, null, pixels, stride);
}
}
private byte[] GenerateColoredBytes(DepthImageFrame depthFrame)
{
//get the raw data from kinect with the depth for every pixel
short[] rawDepthData = new short[depthFrame.PixelDataLength];
depthFrame.CopyPixelDataTo(rawDepthData);
/*
Use depthFrame to create the image to display on screen
depthFrame contains color information for all pixels in image
*/
//Height * Width *4 (Red, Green, Blue, Empty byte)
Byte[] pixels = new byte[depthFrame.Height * depthFrame.Width * 4];
//Hardcoded loactions for Blue, Green, Red (BGR) index positions
const int BlueIndex = 0;
const int GreenIndex = 1;
const int RedIndex = 2;
//Looping through all distances and picking a RGB colour based on distance
for (int depthIndex = 0, colorIndex = 0;
depthIndex < rawDepthData.Length &&
colorIndex<pixels.Length; depthIndex++, colorIndex+=4)
{
//Getting player
int player = rawDepthData[depthIndex] & DepthImageFrame.PlayerIndexBitmask;
//Getting depth value
int depth =rawDepthData[depthIndex]>>DepthImageFrame.PlayerIndexBitmaskWidth;
//.9M or 2.95'
if (depth <=900 )
{
//Close distance
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 255;
//textBox.Text = "Close Object";
}
//.9M - 2M OR 2.95' - 6.56'
else if (depth >900 && depth<2000)
{
//Bit further away
pixels[colorIndex + BlueIndex] = 255;
pixels[colorIndex + GreenIndex] = 0;
pixels[colorIndex + RedIndex] = 0;
}
else if (depth > 2000)
{
//Far away
pixels[colorIndex + BlueIndex] = 0;
pixels[colorIndex + GreenIndex] = 255;
pixels[colorIndex + RedIndex] = 0;
}
//Coloring all people in Gold
if (player > 0)
{
pixels[colorIndex + BlueIndex] = Colors.Gold.B;
pixels[colorIndex + GreenIndex] = Colors.Gold.G;
pixels[colorIndex + RedIndex] = Colors.Gold.R;
playersValue.Text = player.ToString();
}
}
return pixels;
}
Current goal is to--
Detect total number of players detected and display them in a textBox
Colour them according to the distance logic i.e depth <=900 is red.
With current code I can detect player and color them in Gold but as soon as a player is detected the image freezes and when the player is out of the frame the image unfreezes and acts normal. Is it because of the loop?
Ideas, guidance, recommendation and criticism all are welcome.
Thanks!
Screenshots:
Get a static variable inside your form code
Then set this variable using your video frame routine (dont define it there).
And then update the textbox view, probaply in your _sensor_AllFramesReady
As the arrival of new frames runs in a different thread
I dont see all code maybe to update call textbox.show
the main loop looks a bit strange though, too complex.
basicly you use it to color every pixel in your image.
as the kinect360 has 320x240 pixels so that makes a depth array of size 76800
You might simply create 2 for next loops loops for X and Y and then inside this loop have a variable increase to pick the proper depth value.
Related
int numFrames = 5; //Number of animation frames
int frame = 0;
PImage[] images = new PImage[numFrames]; //Image array
void setup()
{
size(800, 800);
background(180, 180, 180);
frameRate(15); //Maximum 30 frames per second
}
void draw()
{
images[0] = loadImage("Ayylmfao.0001.png");
images[1] = loadImage("Ayylmfao.0002.png");
images[2] = loadImage("Ayylmfao.0003.png");
images[3] = loadImage("Ayylmfao.0004.png");
images[4] = loadImage("Ayylmfao.0005.png");
frame++;
if (frame == numFrames)
{
frame = 0;
}
image(images[frame], 0, 0);
}
So my problem is this: I keep getting an artifact from previous frames when I try to run this animation. I'm using an array to store the images in the animation because I'm trying to practice using arrays in general.
The animation is of an eyeball that blinks. The problem is, when it blinks all of the previous frames are drawn over. The iris of the eyeball disappears and the eyeball starts collecting artifacts from the previous frames.
As Kevin points out, you shouldn't load the images over and over again, multiple times per second in draw(). You should load them once in setup(), then render them in draw():
int numFrames = 5; //Number of animation frames
int frame = 0;
PImage[] images = new PImage[numFrames]; //Image array
void setup()
{
size(800, 800);
background(180, 180, 180);
frameRate(15); //Maximum 30 frames per second
images[0] = loadImage("Ayylmfao.0001.png");
images[1] = loadImage("Ayylmfao.0002.png");
images[2] = loadImage("Ayylmfao.0003.png");
images[3] = loadImage("Ayylmfao.0004.png");
images[4] = loadImage("Ayylmfao.0005.png");
}
void draw()
{
frame++;
if (frame == numFrames)
{
frame = 0;
}
image(images[frame], 0, 0);
}
I want to extract gif frames to raw BGRA data, I used giflib to parse format. I've got first frame (I suppose it's like a key frame in video) that looks good and second (it's 15 frames actually, but let's simplify it) that looks like diff frame. Here is samples:
It seems to be simple to restore second full frame using diff data, but here is the problem: I have no idea what color index means "Not changed". Black pixels on diff frame is actually black – its index in color map is 255, which is rgb(0,0,0). I printed whole color table and didn't found any other black entries. It's here if interested. "BackgroundColor" index is 193, so it makes no sense either.
So, I can't separate "black" color from "no" color. What if second frame will really contain some new black pixels (it contains indeed because left eye moves on animation)? But program should handles it differently: get previous frame color for "no" color and get rgb(0,0,0) for "black" color.
UPD: here is my code. Subframes handling and memory cleanup is ommited. Here I supposed that "no" color index is last in colortable. It works actually for my test file, but I'm not sure it will work in general.
DGifSlurp(image);
int* master = malloc(image->SWidth * image->SHeight * sizeof(int));
for (int i = 0; i < image->ImageCount; i++) {
SavedImage* frame = &image->SavedImages[i];
ColorMapObject* cmap = frame->ImageDesc.ColorMap ? frame->ImageDesc.ColorMap : image->SColorMap;
int nocoloridx = cmap->ColorCount - 1;
IplImage* mat = cvCreateImage(cvSize(frame->ImageDesc.Width, frame->ImageDesc.Height), IPL_DEPTH_8U, 4);
mat->imageData = malloc(frame->ImageDesc.Width * frame->ImageDesc.Height * 4);
for (int y = 0; y < frame->ImageDesc.Height; y++)
for (int x = 0; x < frame->ImageDesc.Width; x++) {
int offset = y * frame->ImageDesc.Width + x;
int coloridx = frame->RasterBits[offset];
if (coloridx == nocoloridx) {
coloridx = master[offset];
} else {
master[offset] = coloridx;
}
GifColorType color = cmap->Colors[coloridx];
cvSetComponent(mat, x, y, 0, color.Blue);
cvSetComponent(mat, x, y, 1, color.Green);
cvSetComponent(mat, x, y, 2, color.Red);
cvSetComponent(mat, x, y, 3, 100);
}
cvNamedWindow("t", CV_WINDOW_AUTOSIZE);
cvShowImage("t", mat);
cvWaitKey(0);
}
I am creating a document based application and i want to draw a horizontal line underlying the text. But, line should not be straight. i want to draw a line like this.
Currently i am using System.Graphics object to draw any object.
private void DrawLine(Graphics g, Point Location, int iWidth)
{
iWidth = Convert.ToInt16(iWidth / 2);
iWidth = iWidth * 2;
Point[] pArray = new Point[Convert.ToInt16(iWidth / 2)];
int iNag = 2;
for (int i = 0; i < iWidth; i+=2)
{
pArray[(i / 2)] = new Point(Location.X + i , Location.Y + iNag);
if (iNag == 0)
iNag = 2;
else
iNag = 0;
}
g.DrawLines(Pens.Black, pArray);
}
UPDATED:
Above code is working fine and line draws perfectly but, this code effects on application performance. Is there another way to do this thing.
If you want fast drawing just make a png image of the line you want, with width larger than you need and then draw the image:
private void DrawLine(Graphics g, Point Location, int iWidth)
{
Rectangle srcRect = new Rectangle(0, 0, iWidth, zigzagLine.Height);
Rectangle dstRect = new Rectangle(Location.X, Location.Y, iWidth, zigzagLine.Height);
g.DrawImage(zigzagLine, dstRect, srcRect, GraphicsUnit.Pixel);
}
zigzagLine is the bitmap.
valter
First of all Ill explain what I try to do, just in the case that someone comes up with a better approach
I need to blend too images using the "color" stile from photoshop (you know, the blending methods: Screen, hard light, color ... )
So, I have my base image (a png) and WriteableBitmap generated on execution time (lets call it color mask). Then I need to blend this two images using the "color" method and show the result in a UI component.
So far what Im trying is just to draw things on the WriteableBitmap but I'm facing unexpected behavior with the alpha channel.
My code so far:
// variables declaration
WriteableBitmap img = new WriteableBitmap(width, height, 96,96,PixelFormats.Bgra32,null);
pixels = new uint[width * height];
//function for setting the color of one pixel
private void SetPixel(int x, int y, Color c)
{
int pixel = width * y + x;
int red = c.R;
int green = c.G;
int blue = c.B;
int alpha = c.A;
pixels[pixel] = (uint)((blue << 24) + (green << 16) + (red << 8) + alpha);
}
//function for paint all the pixels of the image
private void Render()
{
Color c = new Color();
c.R = 255; c.G = 255; c.B = 255; c.A = 50;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
SetPixel(x, y, c);
img.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
image1.Source = img; // image1 is a WPF Image in my XAML
}
Whenever I run the code with the color c.A = 255 I get the expected results. The whole Image is set to the desired color. But if I set c.A to a different value I get weird things.
If I set the color to BRGA = 0,0,255,50 I get a dark blue almost black. If I set it to BRGA = 255,255,255,50 I get a yellow ...
Any clue !?!?!
Thanks in advance !
Change the order of your colour components to
pixels[pixel] = (uint)((alpha << 24) + (red << 16) + (green << 8) + blue);
I was following this tutorial on how to make a Silverlight audio recorder. I thought it would be great to add a volume bar indicator to provide user with a feedback on what's happening. However, I can't seem to get this to work properly.
OnSamples method of AudioSink class provides raw PCM data as one of the arguments. Also, I set the AudioFrameSize property of AudioCaptureDevice to 40 (1000/40 == 25fps), so OnSamples is triggered every 40ms.
My question is how to extract the sound volume information from PCM data and display it as percentage in a progress bar [0-100]?
This is what I have so far:
double average = 0;
for (int a = 0; a < sampleData.Length; ++a)
{
average += Math.Abs(sampleData[a]);
}
average /= sampleData.Length;
double volume = 20 * Math.Log10(average);
Value of the progress bar is then set to volume:
progressBar.Value = volume;
My code doesn't work, apparently, since the volume value is almost always at the same level.
Any help is appreciated!
try this...this is for (8000,8,1) if you are using 2 channels replace "index+=1" with "index+=2"
for (int index = 0; index < sampleData.Length; index += 1)
{
short sample = (short)((sampleData[index + 1] << 8) | sampleData[index + 0]);
//short sample = (short)(sampleData[index + 0]);
float sample32 = sample / 32768f;
float maxValue = 0;
float minValue = 0;
maxValue = Math.Max(maxValue, sample32);
minValue = Math.Min(minValue, sample32);
float lastPeak = Math.Max(maxValue, Math.Abs(minValue));
this.MicLevel = (100 - (lastPeak * 100)) * 10;
//System.Diagnostics.Debug.WriteLine("Mic Level: " + this.MicLevel.ToString());
}