I'm building a processing sketch that uses both changing-background-images, oscillators and soundfiles.
Basically every draw(), the background changes, an oscillator plays at a certain frequence and a short audio file is played
Now, the problem: No matter what framerate I set, it always gets below 5. I have an NVIDIA 960 and 16GB of RAM, so I don't really think it's an hardware limitation (?)
Here's my Setup(), where I set the framerate value.
import processing.sound.*;
SoundFile voice;//Quad [] quads;
PImage bg;
//Quad quads;
ArrayList<Quad> quadsArray;
int j=0;
int randomImg;
int randomVoice;
int playVoiceorNot;
TriOsc triangle;
SawOsc saw;
Reverb reverb;
int playSaw;
int timetoChange;
int randomFrate;
int prevVoice;
int screenWidth = displayWidth;
int screenHeight = displayHeight;
void setup(){
fullScreen();
//size(1920,1080);
//quads=new Quad();
quadsArray=new ArrayList<Quad>();
triangle = new TriOsc(this);
saw = new SawOsc(this);
triangle.amp(0.1);
saw.amp(0.1);
prevVoice=0;
frameRate(30);
//background(255);
//reverb = new Reverb(this);
bg = loadImage("1.png");
bg.resize(width,height);
background(bg);
triangle.play();
saw.play();
}
void draw(){
// println(frameRate);
//frameRate(60);
randomImg=floor(random(19));
//randomImg=4;
bg=loadImage(randomImg+".png");
bg.resize(width, height);
background(bg);
//filter(INVERT);
//----controllo se è tempo di cambiare framerate. Possibilità del 2%----
//timetoChange=floor(random(100));
// randomFrate=floor(random(4,15));
//if(timetoChange>=98){
//frameRate(randomFrate);
// }
//-----------------------------------------------------------------------
//pusho un nuovo Quad nell'arrayList-------------------------------------
quadsArray.add(new Quad());
//----------PER OGNI QUAD, lo displayo e lo updato-----------------------
//----------regolo anche la stroke weight in base alla width dei quadrati
for(Quad current:quadsArray){
blendMode(MULTIPLY);
strokeWeight(4);
triangle.freq(floor(random(100,current.quadwidth/2)));
saw.freq(0);
//reverb.damp(0.8);
//reverb.room(0.7);
// reverb.process(triangle);
playSaw=floor(random(100));
if(playSaw>70){
saw.freq(floor(random(100,current.quadwidth)));
// reverb.damp(0.8);
// reverb.room(0.7);
// reverb.process(saw);
strokeWeight(8);
}
else{
saw.stop();
}
current.display();
current.update();
}
//------------------------------------------------------------------------
//---Ciclo per la gestione dei quads con lifespan terminata-------
for(int i=quadsArray.size()-1;i>=0;i--){
Quad temp=quadsArray.get(i);
if(temp.lifespan<=0){
quadsArray.remove(i);
}
}
println(quadsArray.size());
//---------------------------------------------------------------------------
//--controllo se playare una voce o meno. Possibilità del 15%----------------
playVoiceorNot=floor(random(100));
if(playVoiceorNot>=85){
// Load a soundfile from the /data folder of the sketch and play it back
while(randomVoice==prevVoice){
randomVoice=floor(random(70));
}
prevVoice=randomVoice;
voice = new SoundFile(this,randomVoice + ".wav");
voice.amp(1);
voice.play();
}
//----------------------------------------------------------------------------
}
and here's the Quad Object:
class Quad{
float x;
float y;
float quadwidth;
float quadheight;
float lifespan;
float moving;
Quad(){ //constructor
x=width/2;
y=height/2;
quadwidth=floor(random(80,width/2));
quadheight=floor(random(height/2));
lifespan=255;
moving=0;
}
void display(){
stroke(255,0,0,lifespan);
//strokeWeight(3);
noFill();
rectMode(CENTER);
rect(x,y,quadwidth,quadheight);
}
void update(){
//fill(125,100,30,lifespan);
lifespan=lifespan-20;
moving++;
}
}
thanks for the replies!
These two lines are most likely the culprits:
bg=loadImage(randomImg+".png");
voice = new SoundFile(this,randomVoice + ".wav");
You don't want to load files each frame - it's very slow. Instead, load all files that you may need in setup() (into an ArrayList of PImage for the backgrounds, for example) and then access them within the draw() loop.
I've also found that Processing's image resize() function is quite expensive, so call that as you load them in and not within the draw() loop.
Related
I am working on a project with my rocketry club.
I want to have a microbit control the orientation of the fins to auto-stabilize the rocket.
But first, I tried to make a processing code to display in real-time my micro-bit's orientation using its integrated gyroscope.
Here's my processing code :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
float zRot = 0;
String occ[];
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portName = Serial.list()[0]; // get the name of the first serial port
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
println((Object[]) Serial.list());
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
rotateY(zRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readStringUntil('\n'); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
}
delay(10);
if (data != null) {
// split the string into separate values
String[] values = split(data, ',');
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
and here's the python code I have on my microbit
pitch = 0
roll = 0
x = 0
y = 0
z = 0
def on_forever():
global pitch, roll, x, y, z
pitch = input.rotation(Rotation.PITCH) + 90
roll = input.rotation(Rotation.ROLL) + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
z = 1
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
serial.write_string(str(x) + "," + str(y) + "," + str(z) + "\n")
basic.forever(on_forever)
What happens when I run my code is that a cube appears and rotates weirdly for a short time, then, the cube stops and processing prints "Error, disabling serialEvent() for COM5 null".
Please help me out, I really need this code to be working!
Is this the documentation for the micro:bit Python API you're using ?
input.rotation (as the reference mentions), returns accelerometer data:
a number that means how much the micro:bit is tilted in the direction you ask for. This is a value in degrees between -180 to 180 in either the Rotation.Pitch or the Rotation.Roll direction of rotation.
I'd start with a try/catch block to get more details on the actual error.
e.g. is it the actual serial communication (e.g. resetting the baud rate over and over again (serial.set_baud_rate(BaudRate.BAUD_RATE115200)) instead of once) or optimistically assuming there will be 0 errors in serial communication and the string will always split to at least 3 values.
Unfortunately I won't have the resources to test with an actual device, so the following code might contain errors, but hopefully it illustrates some of the ideas.
I'd try simplifying/minimising the amount of data used on the micropython (and setting the baud rate once) and removing the need to read accelerometer data twice in the same iteration. If z is always 1 it can probably be ignored (you always rotate by 1 degree in Processing if necessary):
pitch = 0
roll = 0
x = 0
y = 0
def on_forever():
global pitch, roll, x, y
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
pitch = x + 90
roll = y + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
serial.write_string(str(x) + "," + str(y) + "\n")
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
basic.forever(on_forever)
On the processing side, I'd surround serial code with try/catch just in case anything went wrong and double check every step of the string parsing process:
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames = Serial.list();
println(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
} catch (Exception e){
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app")
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try{
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2){
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
}else{
println("received unexpected number of values");
printArray(values);
}
}
} catch (Exception e){
println("error reading serial:");
e.printStackTrace();
}
}
(If the above still produces serial errors I'd also write a separate test that doesn't use the servos, just in case internally some servo pwm timing/interrupts alongside accelerometer data polling interferes with serial communication for some reason.)
(AFAIK there is no full IMU support on the micro::bit (e.g. accelerometer + gyroscope + magnetometer (+ ideally sensor fusion)), just accelerometer + magnetometer. If you want to get basic rotation data, but don't care for full 3D orientation of the device should suffice. Otherwise you'd need an IMU (e.g BNO055 or newer) which you can connect to the micro via I2C (but will also probably need to implement the communications protocol to the sensor if someone else hasn't done so already).(In theory I see there's Python support for the Nordic nRF52840 chipset, however microbit uses nRF51822 for v1 and nRF52833 for v2 :/). Depending on your application you might want to switch to a different microcontroller altogether. (for example the official Arduino 33 BLE has a built-in accelerometer (and Python support) (and even supports TensorFlow Lite))
Since I do not have a microbit I tested your Processing code using an Arduino UNO at 9600 baud rate. The following serialEvent() function runs without error:
void serialEvent(Serial myPort) {
String data = myPort.readStringUntil('\n');
if (data != null) {
String inStr = trim(data);
String[] values = split(inStr, ',');
printArray(values);
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
Arduino code:
byte val1 = 0;
byte val2 = 0;
byte val3 = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
val1 += 8;
val2 += 4;
val3 += 2;
String s = String(String(val1) + "," + String(val2) + "," + String(val3));
Serial.println(s);
}
Thank you very much George Profenza, it works perfectly well now!
I just had to fix some errors in the code.
Here's the functional code if anyone has this problem later :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames[] = Serial.list();
printArray(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
}
catch (Exception e) {
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app");
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2) {
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
} else {
println("received unexpected number of values");
printArray(values);
}
}
}
catch (Exception e) {
println("error reading serial:");
e.printStackTrace();
}
}
As for the Micro:Bit, I didn't have to change the code at all...
I assume their was an error with the Z axis since we basically just removed removed that...
I am trying to incorporate a .gif document into my Processing code but it appears that something's wrong with the URL. The gif document is in the same folder with my sketch and I don't know what is wrong.
Animation animation1;
float xpos;
float ypos;
float drag = 30.0;
void setup() {
size(640, 360);
background(255);
frameRate(24);
animation1 = new Animation("Starting.gif", 38);
ypos = height * 0.25;
}
void draw() {
background(255);
float dx = mouseX - xpos;
xpos = xpos + dx/drag;
animation1.display(xpos-animation1.getWidth()/2, ypos);
}
// Class for animating a sequence of GIFs
class Animation {
PImage[] images;
int imageCount;
int frame;
Animation(String imagePrefix, int count) {
imageCount = count;
images = new PImage[imageCount];
for (int i = 0; i < imageCount; i++) {
// Use nf() to number format 'i' into four digits
String filename = imagePrefix + nf(i, 4) + ".gif";
images[i] = loadImage(filename);
}
}
void display(float xpos, float ypos) {
frame = (frame+1) % imageCount;
image(images[frame], xpos, ypos);
}
int getWidth() {
return images[0].width;
}
}
Error Message
The file "Starting.gif0000.gif" is missing or inaccessible, make sure the URL is valid or that the file has been added to your sketch and is readable.
The file "Starting.gif0001.gif" is missing or inaccessible, make sure the URL is valid or that the file has been added to your sketch and is readable.
The file "Starting.gif0002.gif" is missing or inaccessible, make sure the URL is valid or that the file has been added to your sketch and is readable.
Pay attention to the class definition. It takes many separate images and makes it a gif as output. What you need to do is to separate the Starting.gif you got into 38 files (if there actually are 38 frames), each named "Starting0000.gif", "Starting0001.gif", "Starting0002.gif" ... "Starting0037.gif".
animation1 = new Animation("Starting", 38);
It should be in a folder called data. This folder should be in the same folder of your sketch.
SketchFolder
Sketch.pde
data
Image.gif
Using the menu to add or dropping the image in the PDE will do this for you. Or you can do it manually.
Hi if anyone could help me out i would be very grateful, i have a sketch that will enable a user to draw graffiti on a screen with a wireless spray can. At the minute, with the tuio code installed, when the user presses the mouse button, a spray sound is made.. but i am having difficulty in the sketch creating an ellipse when presses the mouse button.
This is my code;
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim minim;
AudioPlayer player;
AudioInput input;
/*TUIO processing demo - part of the reacTIVision project
http://reactivision.sourceforge.net/
Copyright (c) 2005-2009 Martin Kaltenbrunner <mkalten#iua.upf.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You shgould have greceived a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// we need to import the TUIO library
// and declare a TuioProcessing client variable
import TUIO.*;
TuioProcessing tuioClient;
import java.util.*; //ADD THIS LINE TO BE ABLE TO USE TUIOCLIENT WITH PROCESSING 2+
// these are some helper variables which are used
// to create scalable graphical feedback
float cursor_size = 15;
float object_size = 60;
float table_size = 760;
float scale_factor = 1;
PFont font;
//declare a boolean to check mouse click
boolean drag = false;
int n=0;
int size[]= {20,40};
int sizeChosen;
boolean inside = false;
PImage bg;
PImage img;
PGraphics pg;
import controlP5.*;
ControlP5 cp5;
boolean mp = true;
void setup ()
{
size(1000,1000);//size(screen.width, screen.height).
smooth();
noStroke();
fill(0);
loop();
frameRate(30);
hint(ENABLE_NATIVE_FONTS);
font = createFont("Arial",18);
scale_factor = height/table_size;
// we create an instance of the TuioProcessing client
// since we add "this" class as an argument the TuioProcessing class expects
// an implementation of the TUIO callback methods (see below)
tuioClient = new TuioProcessing(this);
ellipseMode( CENTER);
//smooth();
noCursor();
background(170);
bg = loadImage("brickwall.jpg");
background(bg);
img = loadImage("instructions.jpg");
image (img,30,40,THUMB_SIZE, THUMB_SIZE);
cp5 = new ControlP5(this);//screenshot button
cp5.addButton("Save Graffiti Artwork").setPosition(0,650).setSize(200,100);//screenshot details
minim = new Minim(this);
player = minim.loadFile("spray_close.wav");
input = minim.getLineIn();
}
void draw() {
if (mp = true);
ellipse(255,0,255,0);
background(bg);
textFont(font,18*scale_factor);
float obj_size = object_size*scale_factor;
float cur_size = cursor_size*scale_factor;
Vector tuioObjectList = tuioClient.getTuioObjects();
for (int i=0;i<tuioObjectList.size();i++) {
TuioObject tobj = (TuioObject)tuioObjectList.elementAt(i);
noStroke();
fill(0);
pushMatrix();
translate(tobj.getScreenX(width), tobj.getScreenY(height));
rotate(tobj.getAngle());
// ellipse(-obj_size/2, -obj_size/2, obj_size, obj_size);
popMatrix();
//fill(255);
text(""+tobj.getSymbolID(), tobj.getScreenX(width), tobj.getScreenY(height));
if (mousePressed) {
ellipse(255,0,255,0);
// printIn("Pink");
//mouse press 1
if (tobj.getSymbolID()==12) {
ellipse(255,0,255,0);
}
}
}
Vector tuioCursorList = tuioClient.getTuioCursors();
for (int i=0;i<tuioCursorList.size();i++) {
TuioCursor tcur = (TuioCursor)tuioCursorList.elementAt(i);
Vector pointList = tcur.getPath();
if (pointList.size()>0) {
stroke(0, 0, 255);
TuioPoint start_point = (TuioPoint)pointList.firstElement();
;
for (int j=0;j<pointList.size();j++) {
TuioPoint end_point = (TuioPoint)pointList.elementAt(j);
line(start_point.getScreenX(width), start_point.getScreenY(height), end_point.getScreenX(width), end_point.getScreenY(height));
start_point = end_point;
}
stroke(192, 192, 192);
fill(192, 192, 192);
ellipse( tcur.getScreenX(width), tcur.getScreenY(height), cur_size, cur_size);
fill(0);
text(""+tcur.getCursorID(), tcur.getScreenX(width)-5, tcur.getScreenY(height)+5);
}
}
if (drag) //if drag = true, i-e if mouse click is holding, ellipse are drawing according the mouse's position
{
fill(#FF00FF); //black color
ellipse(mouseX, mouseY, 50,50); //draw ellipse with x and y mouse's position + size 10*10
//or line strokeWeight(3);stroke(0);line(mouseX,mouseY,25,25);
}
//draw palette size
for(n=0;n<2;n++)
{
fill(0);
ellipse(360,10+n*40,20*(n+1),20*(n+1));
}
}
//size selector
void mousePressed() {
//bDrawFullSize = true;
if (inside==true){
sizeChosen=size[n];
}
player.play();
mp = true;
}
void mouseReleased() {
//bDrawFullSize = true;
drag = false;
player.close();
//since close closes the file, we need to load the sound effect again.
player = minim.loadFile("spray_close.wav");
}
//function "drag and drop"
void mouseDragged() {
drag = true;
}
// these callback methods are called whenever a TUIO event occurs
// called when an object is added to the scene
void addTuioObject(TuioObject tobj) {
println("add object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle());
}
// called when an object is removed from the scene
void removeTuioObject(TuioObject tobj) {
println("remove object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+")");
}
// called when an object is moved
void updateTuioObject (TuioObject tobj) {
println("update object "+tobj.getSymbolID()+" ("+tobj.getSessionID()+") "+tobj.getX()+" "+tobj.getY()+" "+tobj.getAngle()
+" "+tobj.getMotionSpeed()+" "+tobj.getRotationSpeed()+" "+tobj.getMotionAccel()+" "+tobj.getRotationAccel());
}
// called when a cursor is added to the scene
void addTuioCursor(TuioCursor tcur) {
println("add cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY());
}
// called when a cursor is moved
void updateTuioCursor (TuioCursor tcur) {
println("update cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+ ") " +tcur.getX()+" "+tcur.getY()
+" "+tcur.getMotionSpeed()+" "+tcur.getMotionAccel());
}
// called when a cursor is removed from the scene
void removeTuioCursor(TuioCursor tcur) {
println("remove cursor "+tcur.getCursorID()+" ("+tcur.getSessionID()+")");
}
// called after each message bundle
// representing the end of an image frame
void refresh(TuioTime bundleTime) {
redraw();
}
void keyPressed() {
endRecord();
background(bg);
// exit();
}
public void saveScreen() {
saveFrame();
player.pause();
}
// returns true if mouse is inside this rectangle
boolean inside(int left, int top, int right, int bottom ) {
if (mouseX>left && mouseX<right && mouseY>top && mouseY<bottom ) {
return true;
}
else {
return false;
}
}
Anything under the function:
void mousePressed() {
//bDrawFullSize = true;
if (inside==true){
sizeChosen=size[n];
}
player.play();
mp = true;
}
is run every frame while mouse is pressed. So you would create an ellipse (or whatever you want) here.
You can put the ellipse generation function inside branching condition that's checking on the mouse pressed state:
if (mousePressed) {
ellipse(random(0,width),random(0,height),random(0,100),random(0,100));
}
put the condition at the end of the Draw function so that it overwrites any background element
I have installed openni2.2, nite2.2 and kinect SDK 1.6 along with Simpleopenni library for processing. Everything working fine except infrared image - it is simply not there. That is really strange since at the same time I can clearly see the depth image (and depthimage logically need the infra camera and projector working to run). So I assume there is a problem with drivers or software? I would like to use kinect as infrared camera. Please help, below I attach my test code:
/* --------------------------------------------------------------------------
* SimpleOpenNI IR Test
* --------------------------------------------------------------------------
* Processing Wrapper for the OpenNI/Kinect library
* http://code.google.com/p/simple-openni
* --------------------------------------------------------------------------
* prog: Max Rheiner / Interaction Design / zhdk / http://iad.zhdk.ch/
* date: 02/16/2011 (m/d/y)
* ----------------------------------------------------------------------------
*/
import SimpleOpenNI.*;
SimpleOpenNI context;
void setup()
{
context = new SimpleOpenNI(this);
// enable depthMap generation
if(context.enableDepth() == false)
{
println("Can't open the depthMap, maybe the camera is not connected!");
exit();
return;
}
// enable ir generation
if(context.enableIR() == false)
{
println("Can't open the depthMap, maybe the camera is not connected!");
exit();
return;
}
background(200,0,0);
size(context.depthWidth() + context.irWidth() + 10, context.depthHeight());
}
void draw()
{
// update the cam
context.update();
// draw depthImageMap
image(context.depthImage(),0,0);
// draw irImageMap
image(context.irImage(),context.depthWidth() + 10,0);
}
This does the job:
context.enableIR(1,1,1);
I have the exact same issue.
It's not a solution but the closest I can get to getting an infra-red image from the kinect is by getting the point cloud from the depth Image
That soltuion is here
import SimpleOpenNI.*;
import processing.opengl.*;
SimpleOpenNI kinect;
void setup()
{
size( 1024, 768, OPENGL);
kinect = new SimpleOpenNI( this );
kinect.enableDepth();
}
void draw()
{
background( 0);
kinect.update();
image(kinect.depthImage(),0,0,160,120);//check depth image
translate( width/2, height/2, -1000);
rotateX( radians(180));
stroke(255);
PVector[] depthPoints = kinect.depthMapRealWorld();
//the program get stucked in the for loop it loops 307200 times and I don't have any points output
for( int i = 0; i < depthPoints.length ; i+=4)//draw point for every 4th pixel
{
PVector currentPoint = depthPoints[i];
if(i == 0) println(currentPoint);
point(currentPoint.x, currentPoint.y, currentPoint.z );
}
}
Are you able to capture the infrared stream, but you just can't see it?
Then the issue might be RANGE (which it should be in [0, 255]).
I had this issue in Python and C++; I solved it by dividing the array by the range (max-min) and then multiply all entries by 255.
user3550091 is right!
For reference here is my complete working code (Processing+OpenNI):
import SimpleOpenNI.*;
SimpleOpenNI context;
void setup(){
size(640 * 2 + 10, 480);
context = new SimpleOpenNI(this);
if(context.isInit() == false){
println("fail");
exit();
return;
}
context.enableDepth();
// enable ir generation
//context.enableIR(); old line
context.enableIR(1,1,1); //new line
background(200,0,0);
}
void draw(){
context.update();
image(context.depthImage(),context.depthWidth() + 10,0);
image(context.irImage(),0,0);
}
How to create more than one window of a single sketch in Processing?
Actually I want to detect and track a particular color (through webcam) in one window and display the detected co-ordinates as a point in another window.Till now I'm able to display the points in the same window where detecting it.But I want to split it into two different windows.
You need to create a new frame and a new PApplet... here's a sample sketch:
import javax.swing.*;
SecondApplet s;
void setup() {
size(640, 480);
PFrame f = new PFrame(width, height);
frame.setTitle("first window");
f.setTitle("second window");
fill(0);
}
void draw() {
background(255);
ellipse(mouseX, mouseY, 10, 10);
s.setGhostCursor(mouseX, mouseY);
}
public class PFrame extends JFrame {
public PFrame(int width, int height) {
setBounds(100, 100, width, height);
s = new SecondApplet();
add(s);
s.init();
show();
}
}
public class SecondApplet extends PApplet {
int ghostX, ghostY;
public void setup() {
background(0);
noStroke();
}
public void draw() {
background(50);
fill(255);
ellipse(mouseX, mouseY, 10, 10);
fill(0);
ellipse(ghostX, ghostY, 10, 10);
}
public void setGhostCursor(int ghostX, int ghostY) {
this.ghostX = ghostX;
this.ghostY = ghostY;
}
}
One option might be to create a sketch twice the size of your original window and just offset the detected coordinates by half the sketch's size.
Here's a very rough code snippet (assumming blob will be a detected color blob):
int camWidth = 320;
int camHeight = 240;
Capture cam;
void setup(){
size(camWidth * 2,camHeight);
//init cam/opencv/etc.
}
void draw(){
//update cam and get data
image(cam,0,0);
//draw
rect(camWidth+blob.x,blob.y,blob.width,blob.height);
}
To be honest, it might be easier to overlay the tracked information. For example, if you're doing color tracking, just display the outlines of the bounding box of the tracked area.
If you really really want to display another window, you can use a JPanel.
Have a look at this answer for a running code example.
I would recommend using G4P, a GUI library for Processing that has some functionality built in for handling multiple windows. I have used this before with a webcam and it worked well. It comes with a GWindow object that will spawn a window easily. There is a short tutorial on the website that explains the basics.
I've included some old code that I have that will show you the basic idea. What is happening in the code is that I make two GWindows and send them each a PImage to display: one gets a webcam image and the other an effected image. The way you do this is to augment the GWinData object to also include the data you would like to pass to the windows. Instead of making one specific object for each window I just made one object with the two PImages in it. Each GWindow gets its own draw loop (at the bottom of the example) where it loads the PImage from the overridden GWinData object and displays it. In the main draw loop I read the webcam and then process it to create the two images and then store them into the GWinData object.
Hopefully that gives you enough to get started.
import guicomponents.*;
import processing.video.*;
private GWindow window;
private GWindow window2;
Capture video;
PImage sorted;
PImage imgdif; // image with pixel thresholding
MyWinData data;
void setup(){
size(640, 480,P2D); // Change size to 320 x 240 if too slow at 640 x 480
// Uses the default video input, see the reference if this causes an error
video = new Capture(this, 640, 480, 24);
numPixels = video.width * video.height;
data = new MyWinData();
window = new GWindow(this, "TEST", 0,0, 640,480, true, P2D);
window.isAlwaysOnTop();
window.addData(data);
window.addDrawHandler(this, "Window1draw");
window2 = new GWindow(this, "TEST", 640,0 , 640,480, true, P2D);
window2.isAlwaysOnTop();
window2.addData(data);
window2.addDrawHandler(this, "Window2draw");
loadColors("64rev.csv");
colorlength = mycolors.length;
distances = new float[colorlength];
noCursor();
}
void draw()
{
if (video.available())
{
background(0);
video.read();
image(video,0,0);
loadPixels();
imgdif = get(); // clones the last image drawn to the screen v1.1
sorted = get();
/// Removed a lot of code here that did the processing
// hand data to our data class to pass to other windows
data.sortedimage = sorted;
data.difimage = imgdif;
}
}
class MyWinData extends GWinData {
public PImage sortedimage;
public PImage difimage;
MyWinData(){
sortedimage = createImage(640,480,RGB);
difimage = createImage(640,480,RGB);
}
}
public void Window1draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.sortedimage, 0,0);
}
public void Window2draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.difimage,0,0);
}