Image displaying using Arduino- Processing connection and ADXL345 sensor - image

I am working on an artistic project that includes an ADXL345 sensor (accelerometer), Arduino Uno R3 Board, Arduino IDE 2.0.3 and Processing 4.1.2.
I want Processing to display images randomly and continuously every time the values of the sensor that are received from the serial communication with the Arduino sketch, go x>5, x<-5, y.5, y.-5, z>1, z<-1.
UPDATE:
A friend helped me with some lines of code and now the image being displayed when I move the sensor.
CHALLENGE:
What I want to be able to do now is run the processing sketch ONCE and let the windows containing the images pop up, close down, open new windows and display new random images from my folder. For this process to repeat on itself so I don't have to run the sketch manually every time.
These are the codes that I am using in Arudino and Processing.
ARDUINO
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
delay(1000);
}
& PROCESSING
import processing.serial.*;
Serial mySerial;
PImage fragment;
int rand;
void setup() {
size(1000, 500);
rand = int(random(0,133));
takerandomimage("C:/Users/user/Documents/Processing/Trial_300123/frag_" + nf(rand, 3) + ".jpg");
String portName = Serial.list()[0];
mySerial = new Serial(this, portName, 9600);
println("Serial port connected: " + portName);
loop();
}
void takerandomimage(String fn) {
fragment = loadImage(fn);
println(fragment);
}
void draw() {
background(255); //clears the screen
if (fragment.width>0 && fragment.height > 0){ //check if image has been loaded
String data = mySerial.readStringUntil('\n');
if (data != null && data != "\n" && data != " " && data != "\r" && data != "\t") {
println("Data received: " + data);
String[] values = data.split(" ",0);
int counter = 0;
int x = 0;
int y = 0;
int z = 0;
for(String w :values){
System.out.println(w);
if (counter == 1)
x = int(w);
if ( counter == 4)
y = int(w);
if ( counter == 7)
z = int(w);
counter++;
}
println(x);
println(y);
println(z);
if (x < 0 || y > 0 || z > 0) {
takerandomimage("C:/Users/user/Documents/Processing/Trial_300123/frag_" + nf(rand, 3) + ".jpg");
image(fragment, 0,0);
delay(1000);
}
}
}
}
Thank you!!

So many things are right with your code (and question)(+1):
your question mentions version of the Arduino/Processing used, Arduino board, sensor and also includes minimal code focused on the issue
checking if data is not null
checking if the split array is right length, etc.
You are so close !
There is one issue throwing off parsing:
your Processing code assumes you have the x, y, z values one line: String data = mySerial.readStringUntil('\n');
your Arduino code is printling mulitple lines instead of one(e.g. Serial.println(x); instead of Serial.print(x))
to double check, you would see x, y, z values (as well as the two "," symbols) in Serial Monitor on separate lines each (instead of all on one line)
I suspect the intention was to use println() only on the last line:
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.println(z);
delay(1000);
}
(The above should print 3 values separated by "," on a single line. Double check if z should be a digitalRead(2) (returning 1 or 0) reading on pin 2 on your Arduino or analogRead(A2) (returning 0 to 1023) reading analog pin A2.)
Update
Another idea is move the accelerometer conditions in the Arduino code and simply output a single byte/character ('i' for example) when you want to trigger loading a random image in Processing.
Here's a rough / untested example:
void setup() {
// initialize serial communication at 9600 baud rate
Serial.begin(9600);
}
void loop() {
// send x, y, and z values over serial
int x = analogRead(A0);
int y = analogRead(A1);
int z = digitalRead(2);
// if the right motion is picked up, send 'i' to Processing to load a random image
if (x > 5 || y > 5 || z > 0) {
Serial.print('i');
}
delay(1000);
}
Note that with the 1000 ms (1s) delay means you can't trigger an image change faster than that. Adjust the delay as needed.
Additionally you say you want to trigger the change when accelerometer values meet these conditions:
x>5, x<-5, y.5, y.-5, z>1, z<-1.
If so, you might want to change:
if (x > 5 || y > 5 || z > 0)
to
if (abs(x) > 5 || abs(y) > 5 || abs(z) > 0)
(where abs() returns the absolute value (e.g. 5 remains 5, but -5 becomes 5))
Hopefully the values you selected make sense for the motion you're trying to capture with the accelerometer (otherwise the Serial Plot tool in Arduino can be helpful).
If you move the condition to Arduino it simplifies the Processing code as you don't need to wait for a full string to parse into an array: you can read just one character.
import processing.serial.*;
Serial mySerial;
PImage fragment;
void setup() {
size(1000, 500);
loadRandomImage();
String portName = Serial.list()[0];
mySerial = new Serial(this, portName, 9600);
}
void loadRandomImage() {
int rand = int(random(0,133));
String filename = "frag_" + nf(rand, 3) + ".jpg"
fragment = loadImage(fn);
}
void draw() {
// if there is a serial data
if(mySerial.available > 0){
// read one byte/char (mask (&) because byte range is -127 to 127 in java, but 0 to 255 in c++)
char data = mySerial.read() & 255;
// optional: print serial to debug
println("received from Arduino", data);
// if the expect char (i) was received, load random image
if(data == 'i'){
loadRandomImage();
}
}
background(255); //clears the screen
if (fragment.width>0){ //check if image has been loaded
image(fragment, 0, 0);
}
}
Notice a few other minor changes:
I've renamed takerandomimage to loadRandomImage() and changed it so each time the function gets called it generates the random number and loads the random image
whenever the 'i' character is received from Ardiuno a new random is loaded
whatever random image has been set gets displayed continuously (decoupling image display from reading serial data). Before you only loaded and displayed an image if the right serial data came through).

Related

How to perform integrals on an arduino

I am new to arduino and I am trying to make a program that calculates the percentage of charge remaining in a battery, using the coulomb countig method (below a picture with the formula). Is it possible to perform this type of calculation from an arduino?
1.) The Model
Assuming CBat is the capacity of a battery and constant (physicist prefer letter Q for electrical charge; CBat may decrease with aging, "State of Health")
By Definition:
SOC(t) = Q(t)/CBat
Differential Equation:
dQ/dt = I(t)
Approximation: "dt=1"
Q(t)-Q(t-1) ~= I(t)
Or
SOC(t) ~= SOC(t-1) + I(t)/Cbat
2.) Ardunio:
Following is a pure virtual script, online compiler would not serve.
// Assume current coming from serial port
const float C_per_Ah = 3600;
// signal adjustment
const float current_scale_A = 0.1; // Ampere per serial step
const int current_offset = 128; // Offset of serial value for I=0A
float CBat_Ah = 94; /* Assumed Battery Capacity in Ah */
float Cbat_C = CBat_Ah * C_per_Ah; /* ... in Coulomb */
float SOC = 0.7; /* Initial State of Charge */
int incomingByte = current_offset; // for incoming serial data, initial 0 Ampere
float I = 0; /* current */
// the setup routine runs once when you press reset:
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
// the loop routine runs over and over again forever:
void loop()
{
delay(1000); // wait for a second
if (Serial.available() > 0)
{
// read the incoming byte:
incomingByte = Serial.read();
}
I = (incomingByte-current_offset) * current_scale_A;
SOC = SOC + I/Cbat_C;
Serial.print("New SOC: ");
Serial.println(SOC, 4);
}

How to read multiple ADC channels using PIC24; can only get AN0

I am using a PIC24 to read data using 3 analog inputs but am only getting 1 to show the right result. I looked everywhere on the internet and am still not able to get the code to work.
I am trying to read 3 analog input signals and am only able to read in AN0.
I am using an accelerometer to obtain the data and show it on the LCD screen for now. I was able to implement 3 different ways to take the data and display it but only an0 works and an1 is not the right value.
void InitADC(int amask) {
AD1PCFG = 0xFFF8; // select AN0, AN1, AN2 as analog inputs
AD1CON1 = 0x00E0; // auto convert # end of sampling, Integer Data out.
// see Text pg. 179 & Sec. 17 on AD1CON1.
//AD1CON2bits.CSCNA = 1;
AD1CON3 = 0x1F01; // Tad = 2xTcy = 125ns. 31*Tad for conversion time.
//AD1CSSL = 0xFFF7; // Scan 3 channels
AD1CON1bits.ADON = 1; // Turn on the ADC
} // InitADC
main() {
InitADC(0xFFF8); // initialize the ADC and analog inputs
char x_string [12];
char y_string [12];
char z_string [12];
//TRISB = 1; // all PORTB pins as outputs
TRISBbits.TRISB0 = 1;
TRISBbits.TRISB1 = 1;
TRISBbits.TRISB2 = 1;
InitPMP(); // Initialize the Parallel Master Port
InitLCD(); // Initialize the LCD
float x_val;
float y_val;
float z_val;
float x_axis, y_axis, z_axis;
while (1) // main loop
{
x_axis= SelectPort(0);
x_val= ((((x_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(x_string, "X: %0.2f ", x_val);
ms_delay(2.5);
y_axis= SelectPort(1);
y_val= ((((y_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(y_string, "Y: %0.2f ", y_val);
ms_delay(2.5);
z_axis= SelectPort(2);
z_val= ((((z_axis * 3.3)/ 1024)-1.58)/0.380);
sprintf(z_string, "Z: %0.2f ", z_val);
ms_delay(2.5);
}
Here is the code where the data is read:
int SelectPort(int ch)
{
//int *result;
AD1CON1bits.ADON = 0; // Turn off the ADC to reconfigure
//result = &ADC1BUF0;
switch(ch) // set values based on the channel to use
{
case 0: // select AN0 as analog input
//AD1CHSbits.CH0SA=0;
//result = ADC1BUF0;
AD1PCFG = 0xFFFE;
break;
case 1:
//AD1CHSbits.CH0SA=1;
//result = ADC1BUF1;
AD1PCFG = 0xFFFD; // select AN1 as analog input
break;
case 2:
//AD1CHSbits.CH0SA=2;
AD1PCFG = 0xFFFB; // select AN2 as analog input
break;
// there's only so many options here, so there's not really a default case
}
AD1CON1bits.ADON = 1; // Turn on the ADC
AD1CHS = ch; // 1. select analog input channel
AD1CON1bits.SAMP = 1; // 2. Start sampling.
while (!AD1CON1bits.DONE); //5. wait for conversion to complete
AD1CON1bits.DONE = 0; // 6. clear flag. We are responsible see text.
return ADC1BUF0; // 7. read the conversion results
}
I am new to PIC24 and need help to figure out why I am not able to get multiple ADC channels to read the data.
You should always give some time for the ADC input voltage to settle after changing its input port. Also, make sure the impedance of your inputs signals are less than 10K.
Separating the ADC channel switching and reading its value will help, and give you an opportunity to add a delay.
I could not find AD1PCFG in the PIC24 datasheet. AD1PCFG is a PIC32 register... PIC24 uses ANSx and TRSx to set pins as analog inputs. Analog inputs should be set once, during the boot sequence. Feeding an analog signal to a digital input CMOS pin will result in increased power draw, and can even lead to hardware failure!
// Set the pins as analog inputs once and for all in your setup code.
void InitADC()
{
// select RB0/AN0, RB1/AN1, RB2/AN2 as analog inputs
TRISB |= 0x07;
ANSB |= 0x07;
// ...
}
void ADC_SelectInput(int ch)
{
AD1CHS = ch & 0x0F
}
int ADC_Read()
{
AD1CON1bits.SAMP = 1;
while (!AD1CON1bits.DONE)
;
AD1CON1bits.DONE = 0;
return ADC1BUF0;
}
Your loop then becomes:
// ...
int adc_in;
while (1)
{
ADC_SelectInput(0);
ms_delay(3); // settling delay, you could also do something
// else in the meantime instead of waiting.
// NOTE: the argument to ms_delay() is an integer
// so waiting at least 2.5 ms makes it 3.
// when computing floats, use float constants, not double.
x_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(x_string, "X: %0.2f ", x_val);
ADC_SelectInput(1);
ms_delay(3);
y_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(y_string, "Y: %0.2f ", y_val);
ADC_SelectInput(2);
ms_delay(3);
z_val = (((ADC_Read() * 3.3f) / 1024) - 1.58f) / 0.380f;
sprintf(z_string, "Z: %0.2f ", z_val);
}

How to send integers via popen?

I need to be able to send an integer from cocoa to an arduino.
It is easy to send characters, i.e. single digit integers, but I can't seem to find a way of sending two and three digit integers.
The purpose of this is to control the brightness of an LED continuously from 0 to 255.
So far, I can either turn it on and off using the following code:
int ledPin = 9; // LED connected to digital pin 9
int incomingByte = 0; // for incoming serial data
void setup() {
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
if(incomingByte == 105){ //105 corresponds to i and is programmed in cocoa to turn the LED on
digitalWrite(ledPin, HIGH);
}
else if(incomingByte == 111){ //111 corresponds to o and is programmed in cocoa to turn the LED on
digitalWrite(ledPin, LOW);
}
}
}
However, I can't work out how to set values between 0 and 255. Instead of 'digitalWrite', I would use 'AnalogWrite', however, I don't know how to send the incomingByte to be a value between 0 and 255.
This is the cocoa code:
#import "MainController.h"
#implementation MainController
-(IBAction)ledOn:(id)sender{
popen("echo i > /dev/cu.usbmodem1411", "r");
}
-(IBAction)ledOff:(id)sender{
popen("echo o > /dev/cu.usbmodem1411", "r");
}
#end
Thanks.
You can treat the integers with more than one digits as cstring in your arduino code then convert them to integer via atoi().
The following code will capture the bytes from the serial buffer as cstring:
char buffer[MAX_BUFFER_SIZE]; // global c character array variable
boolean inputReady()
{
byte index = 0;
byte avail = Serial.available();
if(avail > 0)
{
while(index < avail)
{
byte val;
do
{
val = Serial.read();
}
while (val == -1); // if value is no longer -1, bytes are captured
buffer[index] = val;
index++;
}
buffer[index] = 0; //terminate the character array
return true;
}
return false;
}
Note: I prefer cstrings than the String class built in the arduino IDE since it uses more memory, but be careful using cstrings as they are prone to memory leaks if not managed well.
This is how your loop() block should look like:
void loop()
{
if(inputReady())
{
int pwmValue = atoi(buffer); // convert ascii buffer to integer.
if(pwmValue >= 0 && pwmValue <= 255) // filter values from 0-255
analogWrite(ledPin, pwmValue);
else
digitalWrite(ledPin, LOW); // turn off if pwmValue is more than 255
}
delay(100);
}
You can then send pwm values as string from your cocoa code via popen().
#import "MainController.h"
#implementation MainController
-(IBAction)ledPWMValue:(id)sender{
popen("echo 254 > /dev/cu.usbmodem1411", "r");
}
#end
I've tested this on my Arduino Uno and will probably work on other variants. I hope this helps you in your project and best of luck!

Firmata servo control

I am stuck on my project at the final part which is controlling a servo by reading xml feed and depending on the values it should turn several degrees. I am using a weather xml feed by yahoo which shows different wind speed attributes as speed, direction and etc. What i am doing is Im using only wind direction and speed in order to visualize it with LED's and and arrow for the direction. Everything works fine with the LED's , but when it comes to the servo I'm not quite sure what to do. It works alright with the Arduino sweeping example, but I use Firmata and i guess the code for it is a bit different. First I used standard Firmata to control the LED's but it wasn't good with the servo, so now Im using 2 arduino's one with Standard Firmata for the LEDs and one with Servo Firmata for the servo, noth assigned on different COM ports. Unfortunately when I try to program the servo it only gets faster or slower without being able to control the angle of it and when to stop. In arduino it works with their example, but in Firmata it seems that I can't adapt it so it does similar in Processing with Firmata. I've been stuck on this for 2 days already pls any help would be appreciated since I have to finish it by Monday
here is the code :
import processing.serial.*;
import cc.arduino.*;
Arduino arduino, arduino2;
final String URL = "http://weather.yahooapis.com/forecastrss?w=27764362";
final String WORD = "yweather:wind";
final String TOKEN = "\\W+";
int ledPin = 13;
int ledPin1 = 12;
int ledPin2 = 8;
int pos=0;
void setup() {
arduino = new Arduino(this, Arduino.list()[0], 57600);
arduino2 = new Arduino(this, Arduino.list()[1], 57600);
arduino.pinMode(ledPin, Arduino.OUTPUT);
arduino.pinMode(ledPin1, Arduino.OUTPUT);
arduino.pinMode(ledPin2, Arduino.OUTPUT);
arduino2.pinMode (9, Arduino.OUTPUT);
final String[] xml = loadStrings(URL);
int idx = 0;
for (; idx != xml.length; ++idx)
if ( xml[idx].contains(WORD) ) break;
if (idx == xml.length) {
println("Not found");
exit();
}
println("Index: " + idx);
println(xml[idx]);
final int[] info = int( xml[idx].split(TOKEN) );
final int dir = info[6];
final int spd = info[8];
println("Speed: " + spd);
println("Direction: " + dir);
if (spd < 5 ) {
arduino.digitalWrite(ledPin, Arduino.LOW);
arduino.digitalWrite(ledPin1, Arduino.LOW);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd >= 5 && spd <10) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.LOW);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd >= 10 && spd <= 15) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.HIGH);
arduino.digitalWrite(ledPin2, Arduino.LOW);
}
if (spd > 16) {
arduino.digitalWrite(ledPin, Arduino.HIGH);
arduino.digitalWrite(ledPin1, Arduino.HIGH);
arduino.digitalWrite(ledPin2, Arduino.HIGH);
}
println("3");
if (dir >= 10 && dir <= 25) {
println("4");
arduino2.analogWrite(9, 90);
delay(1500);
}
else if (dir > 340 && dir <= 360) {
println("Low speed");
arduino2.analogWrite(9, 80); //in this case 80 is controlling the speed, although I wanted to control the angle
delay(1500);
arduino2.analogWrite(9, 120); // same here
delay(1500);
println("5");
}
}
All those prinLn(1-5) are obviously just code checkers to see if there is something wrong with it, but i guess there isnt, its just that i cant control the angle or any other particular control over it other than it's speed, but it doesn't stop spinning till I unplug the usb most cases :)
I guess i need to insert somewher this part of the arduino example to make it move properly :
void loop()
{
for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
But not quite sure since i tried, but I might not have programmed it properly .
Thanks!
setup() is only called once at initialization of the sketch. loop() is repeatedly called during the runtime. therefore, most of your code needs to be in the loop.
i do recommend starting off with some simple sketches to get things running step by step.
ladyada has some good tutorials up, i.e. for serial communication at http://www.ladyada.net/learn/arduino/lesson4.html
the firmata repository holds some good examples at https://github.com/firmata/arduino/tree/master/examples
in addition, the arduino forum reveals some discussion on searching for "firmata" at http://forum.arduino.cc/

Getting image of the player with Kinect in XNA performance issues

I am developing an XNA game that is using Kinect. The player seen on the screen is the real image of the person who is playing in front of Kinect sensor. For eliminating the background and getting only the player's image I am doing these operations in kinect.AllFramesReady:
using (ColorImageFrame colorVideoFrame = imageFrames.OpenColorImageFrame())
{
if (colorVideoFrame != null)
{
//Getting the image of the colorVideoFrame to a Texture2D named colorVideo
}
//And setting its information on a Color array named colors with GetData
colorVideo.GetData(colors);
}
using (DepthImageFrame depthVideoFrame = imageFrames.OpenDepthImageFrame())
{
if (depthVideoFrame != null){
//Copying the the image to a DepthImagePixel array
//Using only the pixels with PlayerIndex > 0 to create a Color array
//And then setting the colors of this array from the 'colors' array by using MapDepthPointToColorPoint method, provided by Kinect SDK
//Finally I use SetData function in order to set the colors to a Texture2D I created before
}
}
But the performance is very low unsurprisingly. Because I have to use GetData for a color array with 640*480 = 307200 length (because of the ColorImageFormat) and SetData for another color array with 320*480 = 76800 length (because of the DepthImageFormat) in every frame!
I wonder if there is any other solutions for this problem, any alternatives for SetData and GetData maybe. Because I know that these functions moving data between the GPU and CPU and that is an expensive operation for big data. Thanks for any help.
The Kinect for Windows Toolbox comes with a "GreenScreen-WPF" example, which should provide some insight into processing the information. Because you are working in XNA there may be some differences, but the overall concepts should work between the two examples.
The example works by extracting multiple players. Here is the business end of the processing function:
private void SensorAllFramesReady(object sender, AllFramesReadyEventArgs e)
{
// in the middle of shutting down, so nothing to do
if (null == this.sensor)
{
return;
}
bool depthReceived = false;
bool colorReceived = false;
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (null != depthFrame)
{
// Copy the pixel data from the image to a temporary array
depthFrame.CopyDepthImagePixelDataTo(this.depthPixels);
depthReceived = true;
}
}
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (null != colorFrame)
{
// Copy the pixel data from the image to a temporary array
colorFrame.CopyPixelDataTo(this.colorPixels);
colorReceived = true;
}
}
// do our processing outside of the using block
// so that we return resources to the kinect as soon as possible
if (true == depthReceived)
{
this.sensor.CoordinateMapper.MapDepthFrameToColorFrame(
DepthFormat,
this.depthPixels,
ColorFormat,
this.colorCoordinates);
Array.Clear(this.greenScreenPixelData, 0, this.greenScreenPixelData.Length);
// loop over each row and column of the depth
for (int y = 0; y < this.depthHeight; ++y)
{
for (int x = 0; x < this.depthWidth; ++x)
{
// calculate index into depth array
int depthIndex = x + (y * this.depthWidth);
DepthImagePixel depthPixel = this.depthPixels[depthIndex];
int player = depthPixel.PlayerIndex;
// if we're tracking a player for the current pixel, do green screen
if (player > 0)
{
// retrieve the depth to color mapping for the current depth pixel
ColorImagePoint colorImagePoint = this.colorCoordinates[depthIndex];
// scale color coordinates to depth resolution
int colorInDepthX = colorImagePoint.X / this.colorToDepthDivisor;
int colorInDepthY = colorImagePoint.Y / this.colorToDepthDivisor;
// make sure the depth pixel maps to a valid point in color space
// check y > 0 and y < depthHeight to make sure we don't write outside of the array
// check x > 0 instead of >= 0 since to fill gaps we set opaque current pixel plus the one to the left
// because of how the sensor works it is more correct to do it this way than to set to the right
if (colorInDepthX > 0 && colorInDepthX < this.depthWidth && colorInDepthY >= 0 && colorInDepthY < this.depthHeight)
{
// calculate index into the green screen pixel array
int greenScreenIndex = colorInDepthX + (colorInDepthY * this.depthWidth);
// set opaque
this.greenScreenPixelData[greenScreenIndex] = opaquePixelValue;
// compensate for depth/color not corresponding exactly by setting the pixel
// to the left to opaque as well
this.greenScreenPixelData[greenScreenIndex - 1] = opaquePixelValue;
}
}
}
}
}
// do our processing outside of the using block
// so that we return resources to the kinect as soon as possible
if (true == colorReceived)
{
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int),
0);
if (this.playerOpacityMaskImage == null)
{
this.playerOpacityMaskImage = new WriteableBitmap(
this.depthWidth,
this.depthHeight,
96,
96,
PixelFormats.Bgra32,
null);
MaskedColor.OpacityMask = new ImageBrush { ImageSource = this.playerOpacityMaskImage };
}
this.playerOpacityMaskImage.WritePixels(
new Int32Rect(0, 0, this.depthWidth, this.depthHeight),
this.greenScreenPixelData,
this.depthWidth * ((this.playerOpacityMaskImage.Format.BitsPerPixel + 7) / 8),
0);
}
}
If you are interested in only a single player, you could look into using the player mask to more quickly extract the appropriate pixel set. You'd fi
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null && skeletonFrame.SkeletonArrayLength > 0)
{
if (_skeletons == null || _skeletons.Length != skeletonFrame.SkeletonArrayLength)
{
_skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
}
skeletonFrame.CopySkeletonDataTo(_skeletons);
// grab the tracked skeleton and set the playerIndex for use pulling
// the depth data out for the silhouette.
this.playerIndex = -1;
for (int i = 0; i < _skeletons.Length; i++)
{
if (_skeletons[i].TrackingState != SkeletonTrackingState.NotTracked)
{
this.playerIndex = i+1;
}
}
}
}
You can then step through the depth data to extract the appropriate bits:
depthFrame.CopyPixelDataTo(this.pixelData);
for (int i16 = 0, i32 = 0; i16 < pixelData.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
{
int player = pixelData[i16] & DepthImageFrame.PlayerIndexBitmask;
if (player == this.playerIndex)
{
// the player we are tracking
}
else if (player > 0)
{
// a player, but not the one we want.
}
else
{
// background or something else we don't care about
}
}
I'm pulling this code from a control I use to produce a silhouette, so it does not deal with the color stream. However, making a call to MapDepthFrameToColorFrame at the appropriate time should allow you to deal with the color stream data and extract the corresponding pixels to the player's mask.

Resources