Reading Pixel values outside Processing frame - processing

Short question: Is there a way to read RGB values of pixels on the screen, outside Processings sketch display window?

You can use's java's Robot class which has a createScreenCapture() method. This will return an image in java's most common image format: java.awt.BufferedImage.
Luckily Processing's PImage has a constructor from a java.awt.Image (including subclasses such as BufferedImage), so putting the two together is fairly straight forward:
import java.awt.*;
import java.awt.image.BufferedImage;
PImage shot;
void setup(){
rectMode(CENTER);
try
{
Robot robot = new Robot();
BufferedImage screenshot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
shot = new PImage(screenshot);
}catch (AWTException e){
throw new RuntimeException("Unable to Initialize", e);
}
}
void draw(){
image(shot,0,0);
fill(shot.get(mouseX,mouseY));
rect(mouseX,mouseY,15,15);
}

Related

changing rate of Animation/Transition

I'm trying to do some basic animations, but am failing at the most simple things:
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
Animation anim = new Timeline(new KeyFrame(Duration.seconds(30.0),
new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
rect.setOnMouseClicked(e -> {
if (anim.getStatus() == Status.RUNNING) {
anim.pause();
} else {
anim.setRate(Math.random() * 5.0);
anim.play();
System.out.println(anim.getRate());
}
});
The problem I am facing is that when I click the rectangle multiple times, the size will randomly jump around, instead of just changing the speed at which it drops. So for example, I let it run to about 50% size at speed ~2.5 and then stop it. When I start it up again, it will jump to a totally different size, smaller for a lower speed, bigger for a higher speed, so for example to ~20% for ~1.0 speed or ~80% for ~4.5 speed.
At first I thought animation was pre-calculated for the new speed and thus jumped to the position at which it would be, had it been played with the new speed from the beginning for the time that it was already playing before the pause, but it's bigger for a smaller speed, which doesn't really make sense then.
How do I change the speed/rate of an animation without having it jump around?
I think your diagnosis is correct: the current value is interpolated given the current time and current rate. If you decrease the rate without changing the current time, you are then earlier in the animation. Since the animation is shrinking this has the effect of making the rectangle bigger.
The easiest way is probably just to start a new animation each time:
import javafx.animation.Animation;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class VariableRateAnimation extends Application {
private Animation anim ;
#Override
public void start(Stage primaryStage) {
Pane mainPane = new Pane();
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
rect.setOnMouseClicked(e -> {
if (anim != null && anim.getStatus() == Status.RUNNING) {
System.out.println("Paused (" + anim.getTotalDuration().subtract(anim.getCurrentTime())+ " remaining)");
anim.pause();
} else {
Duration duration = Duration.seconds(30.0 * rect.getWidth() / (100 * Math.random() * 5.0));
System.out.println("Starting: ("+duration+ " to go)");
double currentWidth = rect.getWidth() ;
if (anim != null) {
anim.stop();
}
anim = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rect.widthProperty(), currentWidth, Interpolator.LINEAR)),
new KeyFrame(duration, new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
anim.play();
}
});
primaryStage.setScene(new Scene(mainPane, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Can't paint an image after choosing it from JFileChooser

Good evening. I have read a lot of topics here on stackoverflow or even internet but I can't find the solution to my problem.
I have an interface like this:
When I click on "Load Image A", I can choose the image that I want. Next I want to paint this image under the JLabel "Image A". But it doesn't want to show up.
Here is the code I wrote:
package projet;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class MonPanelImage extends JPanel{
private static final long serialVersionUID = -8267224342030244581L;
private BufferedImage image;
public MonPanelImage(File adresse)
{
try{
image = ImageIO.read(adresse);
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
System.out.println("paint");
if(image != null){
g.drawImage(image, 20, 20, this);
}
}
}
and here is where I call it:
//panel image. This is my second panel which will be for the images
final JPanel second = new JPanel(new BorderLayout());
//panel button. This is the third panel for the buttons
rows = 0;
cols = 3;
hgap = 5;
vgap = 0;
JPanel third = new JPanel(new GridLayout(rows,cols,hgap,vgap));
//buttons
JButton boutonLoad1 = new JButton("Load image A");
boutonLoad1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int retour = fc.showDialog(frame, "Charger l'image");
if(retour == JFileChooser.APPROVE_OPTION){
String pathImage1 = fc.getSelectedFile().getAbsolutePath();
path1 = pathImage1;
File file = fc.getSelectedFile();
MonPanelImage panelImage1 = new MonPanelImage(file);
second.add(panelImage1, BorderLayout.WEST);
second.revalidate();
second.repaint();
}
}
});
At the very end, i add the 3 panels to my frame and set the frame to visible.
But I can't paint an image. Maybe I'm not doing it properly. Can someone help me please?
Thanks
super.paintComponents(g);
First of all it should be super.paintComponent(g), without the "s".
second.add(panelImage1, BorderLayout.WEST);
You are adding your image to a component using a BorderLayout. The BorderLayout will respect the width of your component, which is 0, so there is nothing to paint.
Whenever, you do custom painting you need to override the getPreferredSize() method to return the size of your component so the layout manager can do its job.
However, an easier solution is to just use a JLabel with an Icon. There is no need to do custom painting when you are painting the image at its real size.

Create more than one window of a single sketch in Processing

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);
}

Unable to draw a simple image using JComponent

I'm using netbeans IDE to practice some Java basic code. But I'm unsuccessful to draw a PNG image. Below is my code,
package JavaApplication1;
import javax.swing.*;
import java.awt.*;
class MyCanvas extends JComponent
{
Image img;
public MyCanvas(){
img = Toolkit.getDefaultToolkit().createImage("pengbrew.png");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
}
}
public class JavaGame
{
public static void main(String args[]){
JFrame window = new JFrame("Image demo");
window.getContentPane().add( new MyCanvas() );
window.setSize(400,400);
window.setVisible(true);
}
}
I added the images in the netbeans project.
Please advise.
Many thanks.
easiest ways is look for JLabel that's best of JComponents for Icon/ImageIcon examples here
To load an image use ImageIO.read(File file). It's a newer API, easier to use and better supported. A tutorial on loading images is here http://docs.oracle.com/javase/tutorial/2d/images/loadimage.html if you need some more pointers.
Your code would look like this instead,
Image img;
public MyCanvas(){
try {
img = ImageIO.read(new File("pengbrew.png"));
} catch (IOException e) {
// Handle exception if there is one.
}
}
For the long answer about why the method you were using wasn't working is probably because of the following...
Your image may be in the proper location and instead Toolkit.createImage() hasn't finished loading the image before the frame comes up to paint. Toolkit.createImage() returns control back to your application before the underlying image has actually finished being loaded. You can usually verify if this is the issue by resizing your application to force it to repaint. If after a few seconds of trying to resize the application the image shows up it was due to the image not being loaded during the first paint calls.
To ensure that the image is loaded before you continue you need to use a MediaTracker. Here is some example code to ensure loading of Image is complete before using it.
Component component = new Component() {};
MediaTracker TRACKER = new MediaTracker(component);
...
Image image = Toolkit.getDefaultToolkit().createImage("imageToLoad.png");
synchronized(TRACKER) {
int id = ++mediaTrackerID;
TRACKER.addImage(image, id);
try {
TRACKER.waitForID(id, 0);
} catch (InterruptedException ex) {
image = null;
}
TRACKER.removeImage(image, id);
}
// Now you can use your image.
You'll see code just like this in the ImageIcon class in the method loadImage(Image image).

Java - drawing many images with Graphics.drawImage() and 2-screen buffer strategy distorts and cuts images

I am using a loop to invoke double buffering painting. This, together with overriding my only Panel's repaint method, is designed to pass complete control of repaint to my loop and only render when it necessary (i.e. some change was made in the GUI).
This is my rendering routine:
Log.write("renderer painting");
setNeedsRendering(false);
Graphics g = frame.getBufferStrategy().getDrawGraphics();
g.setFont(font);
g.setColor(Color.BLACK);
g.fillRect(0, 0, window.getWidth(),window.getHeight());
if(frame != null)
window.paint(g);
g.dispose();
frame.getBufferStrategy().show();
As you can see, it is pretty standard. I get the grpahics object from the buffer strategy (initialized to 2), make it all black and pass it to the paint method of my "window" object.
After window is done using the graphics object, I dispose of it and invoke show on the buffer strategy to display the contents of the virtual buffer.
It is important to note that window passes the graphics object to many other children components the populate the window and each one, in turn, uses the same instance of the graphics object to draw something onto the screen: text, shapes, or images.
My problem begins to show when the system is running and a large image is rendered. The image appears to be cut into seveeal pieces and drawn again and again (3-4 times) with different offsets inside of where the image is supposed to be rendered. See my attached images:
This is the original image:
alt text http://img109.imageshack.us/img109/8308/controller.png
This is what I get:
alt text http://img258.imageshack.us/img258/3248/probv.png
Note that in the second picture, I am rendering shapes over the picture - these are always at the correct position.
Any idea why this is happening?
If I save the image to file, as it is in memory, right before the call to g.drawImage(...) it is identical to the original.
Uh, you are using Swing ?
Normally Swing automatically renders the image, you can't switch it off. The repaint()
method is out of bounds because Swing has a very complicated rendering routine due to
method compatibility for AWT widgets and several optimizations, inclusive drawing only
when necessary !
If you want to use the High-Speed Drawing API, you use a component with a BufferStrategy
like JFrame and Window, use
setIgnoreRepaint(false);
to switch off Swing rendering, set up a drawing loop and paint the content itself.
Or you can use JOGL for OpenGL rendering. The method you are using seems completely
at odds with correct Java2D usage.
Here the correct use:
public final class FastDraw extends JFrame {
private static final transient double NANO = 1.0e-9;
private BufferStrategy bs;
private BufferedImage frontImg;
private BufferedImage backImg;
private int PIC_WIDTH,
PIC_HEIGHT;
private Timer timer;
public FastDraw() {
timer = new Timer(true);
JMenu menu = new JMenu("Dummy");
menu.add(new JMenuItem("Display me !"));
menu.add(new JMenuItem("Display me, too !"));
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
setJMenuBar(menuBar);
setIgnoreRepaint(true);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
super.windowClosing(evt);
timer.cancel();
dispose();
System.exit(0);
}
});
try {
backImg = javax.imageio.ImageIO.read(new File("MyView"));
frontImg = javax.imageio.ImageIO.read(new File("MyView"));
}
catch (IOException e) {
System.out.println(e.getMessage());
}
PIC_WIDTH = backImg.getWidth();
PIC_HEIGHT = backImg.getHeight();
setSize(PIC_WIDTH, PIC_HEIGHT);
createBufferStrategy(1); // Double buffering
bs = getBufferStrategy();
timer.schedule(new Drawer(),0,20);
}
public static void main(String[] args) {
new FastDraw();
}
private class Drawer extends TimerTask {
private VolatileImage img;
private int count = 0;
private double time = 0;
public void run() {
long begin = System.nanoTime();
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
GraphicsConfiguration gc = g.getDeviceConfiguration();
if (img == null)
img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
Graphics2D g2 = img.createGraphics();
// Zeichenschleife
do {
int valStatus = img.validate(gc);
if (valStatus == VolatileImage.IMAGE_OK)
g2.drawImage(backImg,0,0,null);
else {
g.drawImage(frontImg, 0, 0, null);
}
// volatile image is ready
g.drawImage(img,0,50,null);
bs.show();
} while (img.contentsLost());
time = NANO*(System.nanoTime()-begin);
count++;
if (count % 100 == 0)
System.out.println(1.0/time);
}
}

Resources