So I'm trying to map the pixel on the rgbMap to one on the depthMap so I can get the depth from a color tracked object.
I've noticed the depth map is smaller than the rgb map in addition to the different POV from being on a different spot on the kinect itself.
Is there an efficient way to do this that I'm unaware of? Currently I'm thinking of trying to line up the example pixels and then try to figure out an equation for the offset as you get farther away.
Code below, please not that the color tracking is far from done, and that I'm using mouse pressed for testing the pixel position.
/**
* ControlP5 Controlframe
* with controlP5 2.0 all java.awt dependencies have been removed
* as a consequence the option to display controllers in a separate
* window had to be removed as well.
* this example shows you how to create a java.awt.frame and use controlP5
*
* by Andreas Schlegel, 2012
* www.sojamo.de/libraries/controlp5
*
*/
import java.awt.Frame;
import java.awt.BorderLayout;
import controlP5.*;
import SimpleOpenNI.*;
private ControlP5 cp5;
ControlFrame cf;
SimpleOpenNI context;
Ktracker p,o,b;
float rx,ry,dx,dy;
int def;
void setup() {
size((2 * 640),480);
cp5 = new ControlP5(this);
o = new Ktracker(188,57,49);
// by calling function addControlFrame() a
// new frame is created and an instance of class
// ControlFrame is instanziated.
cf = addControlFrame("Output", 640,480);
// add Controllers to the 'extra' Frame inside
// the ControlFrame class setup() method below.
context = new SimpleOpenNI(this);
context.enableRGB();
context.enableDepth();
smooth();
rx=context.rgbWidth()/2;
ry=height/2;
}
void draw() {
context.update();
background(0,150,0);
image(context.depthImage(),context.rgbWidth(),0);
image(context.rgbImage(), 0,0);
int[] dm = context.depthMap();
o.run();
rectMode(CENTER);
noStroke();
fill(255,255,0);
rect(rx,ry,5,5);
dx=rx;
dy=ry;
fill(0,255,255);
rect(dx+context.rgbWidth(),dy,5,5);
rectMode(CORNER);
if(o.wr<10){
fill(0,0,255);
noStroke();
ellipse(o.currentPoints[0]+context.rgbWidth(),o.currentPoints[1],10,10);
cf.z = dm[int(o.currentPoints[0]*o.currentPoints[1])];
} else {
cf.z=0;
}
}
void mousePressed(){
rx=mouseX;
ry=mouseY;
}
ControlFrame addControlFrame(String theName, int theWidth, int theHeight) {
Frame f = new Frame(theName);
ControlFrame p = new ControlFrame(this, theWidth, theHeight);
f.add(p);
p.init();
f.setTitle(theName);
f.setSize(p.w, p.h);
f.setLocation(100, 100);
f.setResizable(false);
f.setVisible(true);
return p;
}
// the ControlFrame class extends PApplet, so we
// are creating a new processing applet inside a
// new frame with a controlP5 object loaded
public class ControlFrame extends PApplet {
int w, h;
float z;
int abc = 100;
public void setup() {
size(w, h, P3D);
frameRate(25);
z=0;
}
public void draw() {
background(abc);
translate(width/2,height/2,z/100);
sphere(250);
}
private ControlFrame() {
}
public ControlFrame(Object theParent, int theWidth, int theHeight) {
parent = theParent;
w = theWidth;
h = theHeight;
}
public ControlP5 control() {
return cp5;
}
ControlP5 cp5;
Object parent;
}
class Ktracker{
float mx,my,wr;
// A variable for the color we are searching for.
color trackColor;
float[] currentPoints, prevPoints;
Ktracker(int r,int g, int b){
trackColor = color(r,g,b);
currentPoints = new float[2];
prevPoints = new float[2];
prevPoints[0]=0;
prevPoints[1]=0;
}
void run(){
loadPixels();
// Before we begin searching, the "world record" for closest color is set to a high number that is easy for the first pixel to beat.
float worldRecord = 500;
// XY coordinate of closest color
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < width/2; x ++ ) {
for (int y = 0; y < height; y ++ ) {
int loc = x + y*width;
// What is current color
color currentColor = pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1,g1,b1,r2,g2,b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
currentPoints[0] = closestX;
currentPoints[1] = closestY;
}
}
}
wr=worldRecord;
// We only consider the color found if its color distance is less than 10.
// This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(255,0,0);
//strokeWeight(4.0);
stroke(0,0);
ellipse(currentPoints[0],currentPoints[1],16,16);
}
println("wr: "+wr);
println("worldRecord: "+worldRecord);
}
}
If you want to align the depth map with the RGB map you need to simply tell OpenNI to do so fo you in setup:
context.alternativeViewPointDepthToImage();
Have a look at the AlternativeViewpoint3d sketch in Examples > SimpleOpenNI > OpenNI
OpenNI has the registration done already so all you need to do is enable it when you need it.
Related
So I'm trying to program snake on a JFrame and doing all graphical stuff (moving the 'snake', random food generation, etc.) on a JPanel. I'm in the beginning stages so all I'm trying to do right now is move a black square around on my frame using arrow keys. My while loop in the Panel class won't get interrupted by a key press in the Snake class, so is there a way to edit JPanel graphics from the same class with all my other code?
Here's all the code. My Panel class at the bottom follows the template I found here.
public class Snake {
// panel width and height
static int pW;
static int pH;
static int x = 10;
static int y = 10;
static int k;
static JFrame frame = new JFrame("SNAKE");
// getters for panel class
public int getPW() { return pW; }
public int getPH() { return pH; }
public int getX() { return x; }
public int getY() { return y; }
public static void main(String[] args) {
// get screen dimensions
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int sH = (int) screenSize.getHeight();
int sW = (int) screenSize.getWidth();
pW = (int) sW/2;
pH = (int) sH/2;
// initialize frame
frame.setSize (pW/1,pH/1);
frame.setLocation(pW/2,pH/2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener( new KeyAdapter() {
public void keyPressed(KeyEvent e) {
k = e.getKeyCode();
switch(k) {
case 38: /* y -= square size */ break; // up
case 40: /* y += square size */ break; // down
case 37: /* x -= square size */ break; // left
case 39: /* x += square size */ break; // right
case 27: System.exit(0);
}
}
});
Panel panel = new Panel();
frame.add(panel);
frame.setVisible(true);
}
}
class Panel extends JPanel {
Snake snake = new Snake();
//square size and separation between squares
int sep = 0;
int size = 50;
// initial location of square on the panel/frame
int x = sep + size;
int y = sep + size;
// holding values to check if x or y have changed
int xH = x;
int yH = x;
public void paint(Graphics g) {
int pW = snake.getPW();
int pH = snake.getPH();
int i; int o;
Color on = Color.BLACK;
Color off = Color.GRAY;
// gray background
g.setColor(Color.GRAY);
g.fillRect(0,0,pW,pH);
// black square initialization
g.setColor(Color.BLACK);
g.fillRect(x, y, size, size);
/* this loop is supposed to check if the black
* rectangle has moved by repeatedly grabbing x & y
* values from the Snake class. When a key is pressed
* and the values change, a gray rectangle is placed at the old location
* and a black one is placed at the new location.
*
* When I run the program, I get stuck in this while loop.
* If I had the while loop in the same class I check for keys,
* I don't think I would have this problem
*/
while(true) {
x = snake.getX();
y = snake.getY();
if(x != xH || y != yH) {
g.setColor(off);
g.fillRect(xH, yH, size, size);
g.setColor(on);
g.fillRect(snake.getX(), snake.getY(), size, size);
xH = x;
yH = y;
}}
}
}
You should never have a while(true) loop in a painting method. This will just cause an infinite loop and your GUI will not be able to respond to events.
Instead you need to add methods to your snake class to move the snake. So when one of the arrow keys is pressed you update the starting position of the snake. Then the method will invoke repaint() and the snake will repaint itself when the paintComponent() method is invoked by Swing.
So your painting code should override paintComponent() not paint() and you should invoke super.paintComponent(g) as the first statement in the method.
Don't call your custom class "Panel", there is an AWT class with that name. Make your class name more descriptive.
I was wondering if I could find some help on this problem. I was asked to use an image ("corn.jpg"), and flip it entirely upside down. I know I need to write a program which will switch pixels from the top left corner with the bottom left, and so on, but I wasn't able to get my program to work properly before time ran out. Could anyone provide a few tips or suggestions to solve this problem? I'd like to be able to write my code out myself, so suggestions only please. Please note that my knowledge of APImage and Pixel is very limited. I am programming in Java.
Here is what I managed to get done.
import images.APImage;
import images.Pixel;
public class Test2
{
public static void main(String [] args)
{
APImage image = new APImage("corn.jpg");
int width = image.getImageWidth();
int height = image.getImageHeight();
int middle = height / 2;
//need to switch pixels in bottom half with the pixels in the top half
//top half of image
for(int y = 0; y < middle; y++)
{
for (int x = 0; x < width; x++)
{
//bottom half of image
for (int h = height; h > middle; h++)
{
for(int w = 0; w < width; w++)
{
Pixel bottomHalf = image.getPixel(h, w);
Pixel topHalf = image.getPixel(x, y);
//set bottom half pixels to corresponding top ones?
bottomHalf.setRed(topHalf.getRed());
bottomHalf.setGreen(topHalf.getGreen());
bottomHalf.setBlue(topHalf.getBlue());
//set top half pixels to corresponding bottom ones?
topHalf.setRed(bottomHalf.getRed());
topHalf.setGreen(bottomHalf.getGreen());
topHalf.setBlue(bottomHalf.getBlue());
}
}
}
}
image.draw();
}
}
Thank you for your help!
See Transforming Shapes, Text, and Images.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FlipVertical {
public static BufferedImage getFlippedImage(BufferedImage bi) {
BufferedImage flipped = new BufferedImage(
bi.getWidth(),
bi.getHeight(),
bi.getType());
AffineTransform tran = AffineTransform.getTranslateInstance(0, bi.getHeight());
AffineTransform flip = AffineTransform.getScaleInstance(1d, -1d);
tran.concatenate(flip);
Graphics2D g = flipped.createGraphics();
g.setTransform(tran);
g.drawImage(bi, 0, 0, null);
g.dispose();
return flipped;
}
FlipVertical(BufferedImage bi) {
JPanel gui = new JPanel(new GridLayout(1,2,2,2));
gui.add(new JLabel(new ImageIcon(bi)));
gui.add(new JLabel(new ImageIcon(getFlippedImage(bi))));
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) throws AWTException {
final Robot robot = new Robot();
Runnable r = new Runnable() {
#Override
public void run() {
final BufferedImage bi = robot.createScreenCapture(
new Rectangle(0, 660, 200, 100));
new FlipVertical(bi);
}
};
SwingUtilities.invokeLater(r);
}
}
Whenever you're swapping variables, if your language doesn't allow for simultaneous assignment (and Java doesn't), you need to use a temporary variable.
Consider this:
a = 1;
b = 2;
a = b; // a is now 2, just like b
b = a; // b now uselessly becomes 2 again
Rather than that, do this:
t = a; // t is now 1
a = b; // a is now 2
b = t; // b is now 1
EDIT: And also what #vandale says in comments :P
If you are able to use the Graphics class, the following may be of use:
http://www.javaworld.com/javatips/jw-javatip32.html
And the Graphics class documentation:
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html
Instead of using
Pixel bottomHalf = image.getPixel(h, w);
Pixel topHalf = image.getPixel(x, y);
//set bottom half pixels to corresponding top ones?
bottomHalf.setRed(topHalf.getRed());
bottomHalf.setGreen(topHalf.getGreen());
bottomHalf.setBlue(topHalf.getBlue());
//set top half pixels to corresponding bottom ones?
topHalf.setRed(bottomHalf.getRed());
topHalf.setGreen(bottomHalf.getGreen());
topHalf.setBlue(bottomHalf.getBlue());
You should have stored the bottomHalf's RGB into a temporary Pixel and used that to set topHalf after replacing bottomHalf's values (if you follow). You could have also really used something like this.... assuming your pixel operates on integer rgb values (which would have improved your main method).
private static final Pixel updateRGB(Pixel in, int red, int green, int blue) {
in.setRed(red); in.setGreen(green); in.setBlue(blue);
}
You want to flip the image upside down, not swap the top and bottom half.
The loop could look like this.
int topRow = 0;
int bottomRow = height-1;
while(topRow < bottomRow) {
for(int x = 0; x < width; x++) {
Pixel t = image.getPixel(x, topRow);
image.setPixel(x, topRow, image.getPixel(x, bottomRow));
image.setPixel(x, bottomRow, t);
}
topRow++;
bottomRow--;
}
I'm really stuck on how to go about programming this. Need to draw a series of 8 concentric circles using Java drawArc method with following conditions
using import java.util.Random library
Provide for starting the drawings at random location (i.e., the x-y
cooridinate must be calculated randomly).
Provide a random color for each circle
Provide a random diameter for each circle
My current code is able to get random random color for each circle but not clear how to meet other random conditions
// Exercise 12.6 Solution: CirclesJPanel.java
// This program draws concentric circles
import java.awt.Graphics;
import javax.swing.JPanel;
public class ConcentricCircles extends JPanel
{
// draw eight Circles separated by 10 pixels
public void paintComponent( Graphics g )
{
Random random = new Random();
super.paintComponent( g );
// create 8 concentric circles
for ( int topLeft = 0; topLeft < 80; topLeft += 10 )
{
int radius = 160 - ( topLeft * 2 );
int r = random.nextInt(255);
int gr = random.nextInt(255);
int b = random.nextInt(255);
Color c = new Color(r,gr,b);
g.setColor(c);
g.drawArc( topLeft + 10, topLeft + 25, radius, radius, 0, 360 );
} // end for
}
}
// This program draws concentric circles
import javax.swing.JFrame;
public class ConcentricCirclesTest extends JFrame {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame=new JFrame("Concentric Circles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ConcentricCircles cCirclesJPanel = new ConcentricCircles();
frame.add(cCirclesJPanel);
frame.setSize(200,250);
frame.setVisible(true);
}//end main
}
Several points are key to such an exercise:
Start with constants for the number of circles and step size; the random number generator in particular only needs to be created once.
private static final int N = 8;
private static final int S = 32;
private static Random random = new Random();
Choose a random point whose coordinates fall within the drawing area.
// a random point inset by S
int x = random.nextInt(getWidth() - S * 2) + S;
int y = random.nextInt(getHeight() - S * 2) + S;
For each circle, find the diameter as a function of S, adding a random fraction of a step, and render the arc at the chosen point offset by the radius.
for (int i = 0; i < N; i++) {
g2d.setColor(…);
int d = (i + 1) * S + random.nextInt(S / 2);
int r = d / 2;
g2d.drawArc(x - r, y - r, d, d, 0, 360);
}
Resize the enclosing frame, which forces a repaint(), to see the effect.
As random colors are not always appealing, consider Collections.shuffle() on a List<Color>.
private final List<Color> clut = new ArrayList<Color>();
…
for (int i = 0; i < N; i++) {
clut.add(Color.getHSBColor((float) i / N, 1, 1));
}
…
Collections.shuffle(clut);
…
g2d.setColor(clut.get(i));
Override getPreferredSize() to establsh the drawing panel's size.
private static final int W = S * 12;
private static final int H = W;
…
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
See also Initial Threads.
I was asked to display the Mandelbrot set on Java but I have encountered a problem. My teacher and I both are stumped to why this doesn't run correctly.
I reckon it has something to do with the algorithm or the complex class since all values except positive/negative 1 and 0 escape to infinity after two iterations.
import javax.swing.*;
import java.awt.*;
public class fractal {
public class complex { double re; double im;
public complex(double x, double y){
this.re =x;
this.im =y;
}
public double mag(){
return (Math.sqrt(re*re+im*im));
}
}
static int xcord = 500;
static int ycord = 500;
public static void main(String[] args) {
JFrame myFrame = new JFrame("Question 10");
myFrame.setSize(xcord,ycord);
JPanel myPane = (JPanel) myFrame.getContentPane();
myPane.add(new paint());
myFrame.setVisible(true);
}
}
class paint extends JComponent {
public complex add(complex a, complex b){
return new complex(a.re+b.re,a.im+b.im);
}
public complex multiply(complex a,complex b) {
return new complex((a.re*b.re)-(a.im*b.im),(a.re*b.im)+(a.im*b.re));
}
public void paint (Graphics g){
final int SCALE =100; //pixels per unit
int itr = 0;
int max_itr = 30;
Color clr = Color.black;
g.translate(fractal.xcord/2, fractal.ycord/2); // Move origin to center of frame
for (int x = -2*SCALE; x <= 1*SCALE; x++){
for (int y = -1*SCALE; y <= 1*SCALE; y++){
complex C = new complex(x/SCALE,y/SCALE); // math done on unscaled values
complex z = C;
itr = 0;
while ( z.mag() <= 4.0 && itr < max_itr){
z = add(multiply(z,z),C);
itr++;
}
if (itr == max_itr){
clr = Color.black;
}
else{
clr = new Color((int) Math.round(itr*8.5),(int) Math.round(itr*8.5),(int) Math.round(itr*8.5)); // Colouring of fractal
}
g.drawOval(x, y, 2, 2);
g.setColor(clr);
}
}
}
}
I think that you have to wide boundaries. [-200,100], where you should have [-2,1] for Re and [-1,1] for Im.
complex C = new complex(x/SCALE,y/SCALE);
complex C = new complex(x/SCALE,y/SCALE); // math done on unscaled values
Since x and y are ints (and SCALE too), you're doing integer division here.
Try this instead:
complex C = new complex((double)x/SCALE,(double)y/SCALE); // math done on unscaled values
By the way, this is not an error, but add() and multiply() should really be methods of the Complex class, which should be capitalised according to the Java naming convention.
In the effort to learn more about applets and Java, I am experimenting making wave applets by drawing lines (drawLine) and making animated line graphs.
I can make a static graph just fine. However I am struggling with the animated aspect of the graph: the axes of the graph should move from left to right, increasing and growing larger than 0.
My problem is translating my needs into a solution. Can anyone give me any pointers with my problem?
I have a multidimensional array indexed by points containing the x and y of a particular point. I have tried modifying my render function to decrease the Xs to make it appear as if it is moving left but this doesn't work right.
What approach am I looking to take? How different will my approach be if the values of Y could change due to user action or added data?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
/**
* A graph that should in the future represent a wave according to my inputs
*
* #authorImprofane
* #version 1
*/
public class Graph extends JFrame
{
private InnerGraph inner;
private int width;
private Random RNG;
private int height;
private int[][] series;
private int xoffset;
int prevx = 0;
int prevy = 0;
/**
* Constructor for objects of class Graph
*/
public Graph(int width, int height) throws InterruptedException
{
RNG = new Random();
setTitle(" Graph");
series = new int[width][2];
this.width = width;
this.height = height;
inner = new InnerGraph(width, height);
add(inner, BorderLayout.CENTER);
setVisible(true);
inner.preparePaint();
pack();
updateGraph();
}
public static void main(String[] args) throws InterruptedException
{
new Graph(300, 300);
}
public void updateGraph() throws InterruptedException
{
// virtual x is how far along on the x axis we are, I ignore the 'real' X axis
int vx = 0;
int point = 0;
int xdecay = 0;
int inc = 5;
// how many times we need to plot a point
int points = (int) java.lang.Math.floor( width / inc );
System.out.println(points);
inner.preparePaint();
// draw all points to graph
// make some junk data, a saw like graph
for (vx = 0 ; vx < points ; vx++) {
series[vx] = new int[] { vx*inc, ( (vx*inc) % 120 ) };
}
Thread.sleep(150);
int n = 5;
while(n > 0) {
System.out.println(xdecay);
inner.preparePaint();
for (vx = 0 ; vx < points ; vx++) {
inner.updateSeries(vx, xdecay);
inner.repaint();
Thread.sleep(50);
}
xdecay += inc;
// shift the data points to the left
int[][] nseries = new int[points][2];
// System.arraycopy(series, 1, nseries, 0, points-1);
n--;
}
}
public class InnerGraph extends JPanel
{
private Graphics g;
private Image img;
private int gwidth;
private int gheight;
Dimension size;
public InnerGraph(int width, int height)
{
gwidth = width;
gheight = height;
size = new Dimension(1, 1);
}
/**
* Try make panel the requested size.
*/
public Dimension getPreferredSize()
{
return new Dimension(gwidth, gheight);
}
/**
* Create an image and graphics context
*
*/
public void preparePaint()
{
size = getSize();
img = inner.createImage( (size.width | gwidth), (size.height | gheight) );
g = img.getGraphics();
}
/**
* Draw a point to the chart given the point to use and the decay.
* Yes this is bad coding style until I work out the mathematics needed
* to do what I want.
*/
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
prevx -= decay;
g.drawLine(prevx-decay, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
public void paintComponent(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
}
}
First, it looks like you are subtracting the decay too often in the updateSeries method.
Below is a new version of that method.
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
// prevx -= decay;
// g.drawLine(prevx-decay, prevy, nx-decay, ny );
g.drawLine(prevx, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
With those changes, the lines draw better, but they draw so slowly that the animation is hard to see. You probably need to build a new graphics and swap the whole thing so that you don't have to watch each individual line segment being drawn.
For a starter you could check out the following example (and the ones related to this)
Scroll Chart #java2s.com