The aim of this little project is to break down an image (in this case a flag) into pieces like a jigsaw and store each piece in part of a 2D array. I then want to be able to view each piece individually so that I know it has worked.
I have created an object class which loads and stores the image. I created the object in my main class and then pass it to my splitImage method which divides the image into chunks and stores in the array. I would like to be able to view a section of the array to check that the splitImage method has worked correctly. Long term however I do need to view the array as I will be determining the colour of the pixel in each image piece and counting how many of each colour is in the image. When I run the current code I get the following in the console,
Exception in thread "main" java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage
at sample.ImageFrame.splitImage(ImageFrame.java:28)
at sample.ImageFrame.main(ImageFrame.java:59)
28 is the line - BufferedImage image = (BufferedImage)((Image) icon.getImage());
59 is - ImageFrame.splitImage(imageSwing.label);
I have played around with these for some time, changing the position trying other options and have been unsuccessful. Help on this is much appreciated.
Code is below and thanks in advance.
public class ImageSwing extends JFrame
{
public JLabel label;
public ImageSwing()
{
super("Test Image Array");
setLayout(new FlowLayout());
Icon flag = new ImageIcon(getClass().getResource("Italy_flag.jpg"));
label = new JLabel(flag);
label.setToolTipText("Italian Flag");
add(label);
}//main
}//class
public class ImageFrame
{
//public ImageSwing imageSwing = new ImageSwing();
//ImageSwing imageSwing = new ImageSwing();
public static BufferedImage splitImage(JLabel i) throws IOException
{
//Holds the dimensions of image
int rows = 4;
int cols = 4;
ImageIcon icon = (ImageIcon)i.getIcon();
BufferedImage image = (BufferedImage)((Image) icon.getImage());
int chunks = rows * cols; //Total amount of image pieces
int partWidth = i.getWidth() / cols; // determines the piece width
int partHeight = i.getHeight() / rows; //determines the piece height
int count = 0;
BufferedImage[][] flagArray = new BufferedImage[rows][cols]; //2D Array to hold each image piece
for (int x = 0; x < rows; x++)
{
for (int y = 0; y < cols; y++)
{
//Initialize the image array with image chunks
flagArray[x][y] = new BufferedImage(partWidth, partHeight, image.getType());
// draws the image chunk
Graphics2D gr = flagArray[x][y].createGraphics();
gr.drawImage(image, 0, 0, partWidth, partHeight, partWidth * y, partHeight * x, partWidth * y + partWidth, partHeight * x + partHeight, null);
gr.dispose();
}
}
return flagArray[rows][cols];
}
public static void main(String[] args)
{
ImageSwing imageSwing = new ImageSwing();
try
{
ImageFrame.splitImage(imageSwing.label);
} catch (IOException e)
{
e.printStackTrace();
}
imageSwing.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
imageSwing.setSize(260,180);
imageSwing.setVisible(true);
}//main
}//class
Take a look at Java converting Image to BufferedImage
It provides a way to convert from Image to BufferedImage, which seems to be the problem.
Related
I have to write a program in Java that uses StdAudio and Picture to create a two-dimensional color visualization of a sound file while it is playing but I'm not really sure how to.
Can someone tell me everything that I need or tell me what I need to do to "convert" the sound file so that it's readable by Picture?
I could grab the samples from the sound file and return them as array of doubles, but then how would that even create an image? How could those values even sync with the image?
I have been playing around in eclipse just trying to figure out how this could possibly even work but my code just ends up being a whole mess.
private final static int SAMPLE_RATE = 44100;
private static int WIDTH = 500;
private static int HEIGHT = 100;
private static JFrame frame;
private static Picture pic;
public static void main(String[] args) throws IOException
{
pic = new Picture(WIDTH, HEIGHT); // <- blank black image
String audioFile = "SampleTest2.wav";
double[] audio = StdAudio.read(audioFile);
frame = new JFrame();
frame.setContentPane(pic.getJLabel());
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setTitle("Sound Visualization");
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
for (int k = 0; k < audio.length; k++)
StdAudio.play(audio[k]);
for (int i = 0; i < pic.width(); i ++)
{
for (int j = 0; j < pic.height(); j++)
{
pic.set(i, j, toColor(audio[SAMPLE_RATE + i]));
//frame.setContentPane(pic.getJLabel());
}
frame.repaint();
}
}
private static Color toColor(double colVal)
{
int r = (int) (((colVal + 1) / 2) * 255);
int g = (int) (((colVal + 1) / 2) * 255);
int b = (int) (((colVal + 1) / 2) * 255);
return new Color(r, g, b);
}
To use StdAudio you need wav file with sampling rate of 44100. It means every second of this sound consists of 44100 values(samples). When you load such file with duration of 1 second using method double[] read(String filename) you will obtain an array with 44100 elements. Javadoc of that method tells us the values will be between -1.0 and +1.0. We can iterate over every sample, map values from -1..1 range to 0..255 range (because colors need values from 0 to 255) and paint each pixel with this color. For better effect let's not paint single pixel but a column of 100 pixels.
I'll create image of 500x100. It will display only 500 samples so it will represent 500/44100 = only 0,01 of a second. To create empty picture of that size use:
Picture p = new Picture(500, 100);
To paint separate pixels along the image use:
for (int i = 0; i < 500; i++) {
p.set(i, 0, color);
}
and to display this picture use:
p.show();
Next, to create a color we need 3 values: red, green and blue components. Here we have only one value so the resulting image will be a greyscale image because saturation of every component will be the same value new Color(value, value, value). To quickly convert a range from -1..1 to 0..255 use such formula: (int) (((d + 1) / 2) * 255)
I used the first sound file from this site:
http://www.music.helsinki.fi/tmt/opetus/uusmedia/esim/index-e.html and the image I obtained is:
The code I used is:
import java.awt.Color;
import java.io.IOException;
public class StackOverflow58899141 {
private static int IMAGE_WIDTH = 500;
private static int IMAGE_HEIGHT = 100;
static String filename = "O:\\1.wav";
public static void main(final String[] args) throws IOException {
// reading sound file to samples
double[] samples = StdAudio.read(filename);
// creating empty image
Picture p = new Picture(IMAGE_WIDTH, IMAGE_HEIGHT);
// filling image from left to right
for (int i = 0; i < IMAGE_WIDTH; i++) {
// filling image from top to bottom
for (int j = 0; j < IMAGE_HEIGHT; j++) {
// adding 44100 to skip 1s of silence at the beginning
p.set(i, j, doubleToColor(samples[44100 + i]));
}
}
p.show();
}
// convert number from range -1.0..1.0 to 0..255
private static Color doubleToColor(double d) {
int val = (int) (((d + 1) / 2) * 255);
return new Color(val, val, val);
}
}
Now you have a solid start to understand how it works. Although Picture class allows easy saving of an image it doesn't allow animating. To achieve that you'd need to create own JFrame and draw image and delay drawing each column of pixels to get the animation effect.
I am new to programming and I'm currently working on a program that rotates an image to the right and upside down. I was able to get the upside down method working but not the rotate to the right (90 degrees clockwise). It keeps giving me an out of bounds error, and I'm not sure why as I have looked at other examples. Any help would be appreciated.
Here's is the method that I'm working on:
public Image rotateRight()
{
Image right = new Image (this);
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int width = right.img.getWidth();
int height = right.img.getHeight();
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
}
return right;
}
Here's the rest of the code:
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class Image {
private BufferedImage img = null;
int width;
int height;
private Image()
{
}
public Image (int w, int h)
{
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB );
width = w;
height = h;
}
public Image (Image anotherImg)
{
width = anotherImg.img.getWidth();
height = anotherImg.img.getHeight();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
this.img.setRGB(j,i,anotherImg.img.getRGB(j,i)) ;
}
}
public String toString()
{
return "Width of Image:" +width+"\nHeight of Image:"+height;
}
public Image (String filename)
{
try
{
img = ImageIO.read(new File(filename));
width = img.getWidth();
height = img.getHeight();
}
catch (IOException e)
{
System.out.println(e);
}
}
public void save(String filename, String extension)
{
try
{
File outputfile = new File(filename);
ImageIO.write(img, extension, outputfile);
}
catch (IOException e)
{
System.out.println(e);
}
}
public Image copy()
{
Image copiedImage = new Image(this);
return copiedImage;
}
Here's Main:
public static void main (String args[])
{
Image srcimg = new Image("apple.jpg");
System.out.println(srcimg);
Image copy = srcimg.copy();
copy.save("apple-copy.jpg", "jpg");
Image copy2 = srcimg.copy();
Image right = copy2.rotateRight();
right.save("apple-rotateRight.jpg", "jpg");
}
The reason you are getting an ArrayIndexOutOfBoundsException when rotating your image is as stated. Something is out of bounds. It could be either your i variable that has exceeded its bounds or your j variable that has exceeded its bounds and this is generally easy to test for by just adding a print statement within your for loop and checking which one of the two values is out of bounds. It is good practice to try to resolve these problems yourself as you will start learning what causes these and where the problem lies.
Anyways enough of my rambling. The problem that you seem to have is that you are trying to turn the image without changing the size of the image.
You are creating a new Image with the same width and height parameters as the original
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
However when you want to rotate an image by 90 degrees you actually want to flip the width and height parameters. If you think about it, it makes sense when you rotate an image by 90 degrees the width will become the height and the height will become the width.
So your problem is here:
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
In your case the bounds for the x parameter in the setRGB function is from 0 to the WIDTH of your image and the y parameter is from 0 to the HEIGHT of your image. Therefore because your height variable is different from your width. If for example your WIDTH is 200 and your HEIGHT is 100. When you put this in to the function the greatest value for the x parameter will be:
'100 - 199 - 1 = -100' which is clearly out of bounds. However if we change your code to.
img = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB );
now when we do the same thing as before where we get the maximum possible value.
WIDTH = 100, HEIGHT = 200;
'200 - 99 - 1 = 100' which is inside the bounds
I am trying to create a color tracking bird flock, using live video from my webcam. I was instructed to use a constructor to create an array of .gifs that could work independently and follow a specific color around the video.
I did some research and this is as far as I got. Now I am getting an error that I don't really understand. For a very early dummy example of the intentions i have with the code, please see this .gif: Flock of birds
import processing.video.*;
import gifAnimation.*;
video = new Movie(); /// This is the line that gives me the error
// class
Birdy [] arrayOfBirds;
int numberOfBirds = 10;
class Birdy
{
//variables
int numberOfBeaks;
String birdName;
color birdColor;
PVector location;
// constructor, allows you to make new Birds in the rest of the code
// A constructor is part of the class
Birdy (int nob, String bname, color bColor, PVector loc) {
numberOfBeaks = nob;
birdName = bname;
birdColor = bColor;
location = loc;
}
//The bird appears
void showBird()
{
fill(birdColor);
textSize(24);
text(birdName, location.x, location.y);
ellipse(location.x, location.y, 20, 20);
}
}
void setup() {
size(640, 480);
//fill the array Of Birds with new Birds
arrayOfBirds = new Birdy[numberOfBirds];
//to make 10 birds and put them in the array
for (int i = 0; i < numberOfBirds; i++)
{
// each new bird needs its own set of parameters but will do this when i figure out how to work with this one first!
arrayOfBirds[i]= new Birdy(2, "Tweety "+i, color(255-(i*25), i*25, 255), new PVector(i*40, i*40));
}
}
void draw(int x, int y) {
if (video.available()) {
video.read();
image(video, 0, 0, width, height); // Draw the webcam video onto the screen
int colorX = 0; // X-coordinate of the closest in color video pixel
int colorY = 0; // Y-coordinate of the closest in color video pixel
float closestColor = 500; //we set this to be abritrarily large, once program runs, the first pixel it scans will be set to this value
// Search for the closest in color pixel: For each row of pixels in the video image and
// for each pixel in the yth row, compute each pixel's index in the video
background(0);
//show that first bird we called Tweety by calling the showBird() function on Tweety
Tweety.showBird();
//show all the birds in the array by calling the showBird() method on each object in the array
for(int i = 0; i < arrayOfBirds.length; i++){
arrayOfBirds[i].location = new PVector(x,y);
arrayOfBirds[i].showBird();
}
}
setup();
Gif loopingGif;
Capture video;
size(640, 480); // Change size to 320 x 240 if too slow at 640 x 480 // Uses the default video input ---- but i dont think it works
video = new Capture(this, width, height, 30);
video.start();
noStroke();
smooth();
frameRate(10);
loopingGif = new Gif(this, "circle.gif");
String [] animas = {};
video.loadPixels();
int index = 0;
for (int y = 0; y < video.height; y++) {
for (int x = 0; x < video.width; x++) {
// Get the color stored in the pixel
color pixelValue = video.pixels[index];
// Determine the color of the pixel
float colorProximity = abs(red(pixelValue)-27)+abs(green(pixelValue)-162)+abs(blue(pixelValue)-181); //select pixel
// If that value is closer in color value than any previous, then store the
// color proximity of that pixel, as well as its (x,y) location
if (colorProximity < closestColor) {
closestColor = colorProximity;
closestColor=closestColor-10; //Once it "locks" on to an object of color, it wont let go unless something a good bit better (closer in color) comes along
colorY = y;
colorX = x;
}
index++;
}
draw(x,y);
}
image (loopingGif, colorX, colorY);
loopingGif.play();
}here
You need to declare your variable by giving it a type:
Movie video = new Movie();
You've got some other weird things going on here. Why are you specifically calling the setup() function? Processing does that for you automatically. You've also got a bunch of code outside of a function at the bottom of your sketch. Maybe you meant to put that code inside the setup() function?
If you're still getting errors, edit your question to include their exact full text.
I have a sprite sheet that will be 5x5 and each sprite is 20x20 pixels. I need to get each item of that sprite sheet into an array. I made a for loop but got an error. So I tried defining one of the sub images in the array myself but still get an error. I do not get an error when I don't print an item of that array. I now can not figure out the for loop problem.
Here's my code so far
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class LoopSub extends Component {
BufferedImage img;
BufferedImage img2;
BufferedImage bigImg;
BufferedImage[] sprites;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
g.drawImage(img2, 18, 0, null); //letter size 20x20 ; set lower to overlap
g.drawImage(sprites[0], 36, 0, null); //this is whats causing the error
}
public LoopSub() {
try {
img = ImageIO.read(new File("res/a.png"));
img2 = ImageIO.read(new File("res/b.png"));
/////////////////////////////
bigImg = ImageIO.read(new File("sheet.png"));
final int width = 20;
final int height = 20;
final int rows = 5;
final int cols = 5;
sprites = new BufferedImage[rows * cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
sprites[(i * cols) + j] = bigImg.getSubimage(
j * width,
i * height,
width,
height
);
}
}
sprites[0] = bigImg.getSubimage(1,1,1,1); //where I tried to define the array myself
/////////////////////////////////////////////
} catch (IOException e) {
}
}
public Dimension getPreferredSize() { //sets size of screen
if (img == null) {
return new Dimension(100,100);
} else {
return new Dimension(img.getWidth(null), img.getHeight(null)); //sets size to one image //// change to all images
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Load Image Sample");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(new LoopSub());
f.pack();
f.setVisible(true);
}
}
New error message
Exception in thread "main" java.awt.image.RasterFormatException: (x + width) is outside of Raster
at sun.awt.image.ByteInterleavedRaster.createWritableChild(Unknown Source)
at java.awt.image.BufferedImage.getSubimage(Unknown Source)
at LoopSub.<init>(LoopSub.java:48)
at LoopSub.main(LoopSub.java:85)
When changing j*width to 1 it works fine. So that's the problem. Just don't know why.
You have a NullPointerException, which means that either sprites or sprites[0] is null.
Given that you initialize them in the constructor, it can happens only if there is an IOException occuring in the constructor, because you are catching it, so it doesn't terminate the program.
You should:
Never silently ignore an exception, like you are doing here. if you don't do anything useful, at least put a message to print the error like this:
} catch (IOException e) {
e.printStackTrace();
}
Look what is the content of the exception, which contains the root of the problem. Probably the program can not find one of your files for some reason.
Edit: for the RasterFormatException, it means that you are getting out of the limits of the image. More specifically, j * width + width is apparently larger than the width of the image.
Since j is at most 4 and width is 20, then the maximum value that j * width + width can have is 100. Your original image should then be at least 100px wide (and also 100px tall). Check that it is indeed the case.
You can for example print the width this way before the loop:
System.out.println("bigImg width: " + bigImg.getWidth());
I have some data that is loaded from the text file that corresponds to my image file. this data is now in a 2D array. I want to show this image. apparently the image show be of format bufferedimage. but mine is just simple 2D double format.
Also how is possible to resize the image, meaning to make it twice bigger ( requiring interpolation in between of course)
In other words how can we do the "imshow" and " imresize" Matlab equilvalent in java?
There is no simple method for converting between an array based intensity matrix to a renderable image in Java, at least not that I am aware of. Nor is there any simple one line method for displaying an image on the screen etc.
It is however correct that a BufferedImage would be a viable solution in this case. What you would have to do is to create a BufferedImage of the desired size and then loop through your 2D intensity matrix and fill in the colors in the resulting image.
Once you have the data in form of a BufferedImage you can use it directly for rendering. For example you could create a JFrame with a custom JPanel component for displaying the image. The following sample code illustrates that procedure: (Note that this assumes that your image data in the 2D array is scaled to fit in the interval [0,1]. If it is not then it will have to be re-scaled prior to filling in the BufferedImage.)
public class ImageTest {
private static final int HEIGHT = 250;
private static final int WIDTH = 250;
public static void main(String[] args) {
double[][] data = new double[WIDTH][HEIGHT];
Random r = new Random();
for(int i = 0; i < WIDTH; i++) {
for(int j = 0; j < HEIGHT; j++) {
data[i][j] = r.nextDouble();
}
}
final BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)img.getGraphics();
for(int i = 0; i < WIDTH; i++) {
for(int j = 0; j < HEIGHT; j++) {
float c = (float) data[i][j];
g.setColor(new Color(c, c, c));
g.fillRect(i, j, 1, 1);
data[i][j] = r.nextDouble();
}
}
JFrame frame = new JFrame("Image test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// Or _BICUBIC
g2d.scale(2, 2);
g2d.drawImage(img, 0, 0, this);
}
};
panel.setPreferredSize(new Dimension(WIDTH*2, HEIGHT*2));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
If you are happy with resizing and interpolating in the resulting output image then you can achieve it by simply scaling the graphics context and enabling the interpolation rendering hint on it, as the above example shows when displaying/rendering the image. (This can of course be done directly in the BufferedImage as well in a similar fashion.
Have a look at MemoryImageSource. It might not do exactly what you want (because Java tends to use int / byte for image data) but it will at least send you down the right route.
http://www.javaworld.com/javatips/jw-javatip16.html