Buffered Image from string - java

I am attempting to create an image based on string with RGB color values assigned on new lines. But for whatever reason the pixels are being placed in the wrong spots creating this odd chevron pattern. Clearly the issue is in how I am increasing the values but I can't seem to find the issue.
I've also confirmed multiple different ways that there is nothing wrong with the string
Chevron pattern I was talking about
static void AddPixels(String Data){
Scanner Scan = new Scanner(Data);
ArrayList<Integer> Table = new ArrayList<>();
while (Scan.hasNextLine() && !(XCount == XTotal)){
Scanner LineScan = new Scanner(Scan.nextLine());
while (LineScan.hasNext()){
Table.add(LineScan.nextInt());
}
if (Table.size() == 3){
Image.setRGB(XCount,YCount, new Color(Table.get(0),Table.get(1),Table.get(2),255).getRGB());
}
else{
Image.setRGB(XCount,YCount, new Color(0,0,0,0).getRGB());
}
Table.clear();
YCount++;
if (YCount == YTotal){
YCount = 0;
XCount++;
System.out.println(Math.floor(((double)XCount/XTotal)*100));
}
}
//System.out.println("Finished");
if (XCount >= XTotal){
System.out.println("Runnin");
try{
File ImageFile = new File("TestImage.png");
ImageIO.write(Image, "png", ImageFile);
}
catch(IOException e)
{
System.out.println("Error: " + e);
}
}
}

You're updating your y-coordinate each time you loop (for each of R, G, and B), and painting a black pixel 2/3rds of the time (the else block in your code).
If I understand your problem statement correctly, the file looks like:
200
100
0
where 200 is the R value, 100 is the B value, and 0 is the G value, for each pixel.
If this is the case, you need to be updating your Y value only every third value read from the file - and not painting black pixels at all.

Related

How can I convert an RGB image to grayscale but keep one color? - Java

I am trying to create an effect similar to Sin City or other movies where they remove all colors except one from an image.
I have an RGB image which I want to convert to grayscale but I want to keep one color.
This is my picture:
Image to edit
I want to keep the red color. The rest should be grayscale.
Here is my code so far:
package poza;
import java.io.*;
public class poza {
public static void main(String[] args) {
try {
FileInputStream fis=new FileInputStream("poza.bmp");
BufferedInputStream dis=new BufferedInputStream(fis);
FileOutputStream sif=new FileOutputStream("poza1.bmp");
BufferedOutputStream bos=new BufferedOutputStream(sif);
byte[] sti=new byte[54];
dis.read(sti,0,54);
bos.write(sti);
while(dis.available()>0)
{
int b,g,r;
b=dis.read();
g=dis.read();
r=dis.read();
System.out.print(b+" "+g+" "+r+"\n");
int gri=(int)(0.114*b+0.587*g+0.299*r);
if(r>=b && r>=g)
{
bos.write(gri);
bos.write(gri);
bos.write(r);
}
else
{
bos.write(b);
bos.write(g);
bos.write(r);
}
System.out.print(b+" "+g+" "+r+"\n");
}
dis.close();
bos.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
You need to note that every color is represented by 3 values or channels, i.e. red, green and blue. If you only keep one of those channels you'll skew the results.
Instead you need to decide whether a pixel should retain its original color or become grayscale. So assuming your code already does the conversion to grayscale correctly, it comes down to this:
if( keepColor ) {
//I'll keep the order of the components that your example uses, make sure this is correct
bos.write(b);
bos.write(g);
bos.write(r);
} else {
bos.write(gri); //b
bos.write(gri); //g
bos.write(gri); //r
}
So what is left is how keepColor is defined and that depends on your requirements. A simple option might be to pick a color and check if the pixel is within a certain threshold of that color, e.g. like this:
/**
* value - the value to check
* base - the base value to check against, i.e. the center of the range, expressed in range [0, 255]
* difference - the allowable difference in percent, expressed in range [0.0, 1.0]
*/
boolean withinThreshold(int value, int base, double difference) {
return value>= base * (1-difference) //check lower bound
&& value <= base * (1+difference); //check upper bound
}
Then pick a value and a difference, e.g. like this:
boolean keepColor = withinThreshold(r, 228, 0.6) //40%-160% of 228
&& withinThreshold(g, 95, 0.6) //40%-160% of 95
&& withinThreshold(b, 78, 0.6); //40%-160% of 78
Of course there are many other possibilities you can play around with, i.e. different thresholds, different colors, based on brightness (grayscale value in a certain range) etc.

Java game lag, too many if statement?

I'm working on a game in java, based on the Atari game adventure. I got the basic KeyListener part working fine, but then I added another if statement, using another class, to test if if the player was going to hit a wall, and stopping movement if that was the case. The method I used also used if statements, and when I ran the code, it had MAJOR lag. I tried a while loop first, but that made it lag even worse. Anyway to make this not lag so much? It doesn't seem that complex a program to run, and I still have to add yet another if statement to make be able to move into another room, so I have to do something to massively cut down on the lag.
Here is the class:
class Player extends JPanel implements KeyListener{
private char c = 'e';
int x = 400;
int y = 400;
int mapX = 0;
int mapY = 0;
public Player() {
this.setPreferredSize(new Dimension(800, 500));
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Environment Layout = new Environment();
Layout.drawRoom(mapX,mapY,g);
g.fillRect(x , y , 20, 20);
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) {
c = e.getKeyChar();
repaint();
Environment Layout = new Environment();
if(Layout.isWall(x,y,c)){}
else{
if (c == 'a'){
x = x - 3;
}
else if (c == 'w'){
y = y - 3;
}
else if (c == 's'){
y = y + 3;
}
else if (c == 'd'){
x = x + 3;
}
}
}
public static void main(String[] s) throws IOException{
JFrame f = new JFrame();
f.getContentPane().add(new Player());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
The draw room method I used in this was just to put the background of the room into place.
Here is the isWall method from the Environment class:
public boolean isWall(int moveX, int moveY, char let){
BufferedImage room = null;
try {
room = ImageIO.read(new File(xNum + "," + yNum + ".png"));
}
catch (IOException e) {
}
int[][] walls = convertImage(room);
boolean blocked = false;
if(let == 'w') {
if(walls[moveY-8][moveX] == -3584){blocked = true;}
}
else if(let == 's') {
if(walls[moveY+20][moveX] == -3584){blocked = true;}
}
else if(let == 'a') {
if(walls[moveY][moveX-5] == -3584){blocked = true;}
}
else if(let == 'd') {
if(walls[moveY][moveX+20] == -3584){blocked = true;}
}
return blocked;
}
the convertImage method just converts the image of the room into an int array, for the value of the colors. -3584 is the color of the walls. It's possible this is what's lagging it, but this seemed like the best way for each room to have the walls done automatically.
I also tried a timer, but either I did that wrong, or it just didn't help.
I can give more of my code if that's needed, but help with this would be much appreciated. I'm relatively new to this kind of stuff, so it's likely I'm missing something big. Thanks.
The lag here is almost certainly not from the if statements. Those are really fast. I think the bigger issue is in isWall. Notice that any time you want to check for whether a wall is present, you
Open a file,
read the file contents,
convert the file contents from an image to a grid of pixels, and
read exactly one pixel.
Reading files from disk is extremely slow compared to looking at values in memory. For example, a regular magnetic hard drive works at around 7200 RPM, so the seek time is measured in milliseconds. On the other hand, your processor can do about a billion operations per second, so other operations take nanoseconds. That means that a disk read is roughly a million times slower than other operations, which is almost certainly where you're getting the lag from!
To fix this, consider rewriting your isWall code so that you only read the file and do the conversion once and, having done that, then just look up the part of the image you need. This converts doing tons of (glacially slow) file reads to one single (slow but inevitable) file read followed by tons of fast memory reads.
You appear to be moving your walls further than you are moving your player.
Is it possible that your player object is getting stuck in a wall there by producing "blocked = true" continuously?
Your character gets +- 3 in every direction, however your walls seem inconsistent and range from 8 up to 20 down to 5 left to 20 right.
This is an extension to #templatetypedef's answer.
Instead of loading the image files upon calling the isWall method, you might want to consider caching all of the walls on game start.
So I am thinking;
have a HashMap data structure keyed by <String, Integer>. Where String is your coordinates. E.g. coordinate string = "100,238"
parse all the .png image files in the directories and store the coordinates as key and the value can just be any dummy value like 1 or 2.
Then when isWall() is invoked. Given the X and Y coordinate, build the coordinate string as mentioned in point 1 and check if the key exists. If it does then we know it is a piece of wall else not.
This should drastically reduce the I/O disk contention.
In future, if you would like to extend the solution to incorporate APIs like isTreasureChest() or isMonster(). It can be extended by building a immutable class call "Room" or "Tile" to represent the object. Then modify the HashMap to take in <String, Room>.

How do I test a pixel of a bufferedimage for a certain color in Java

I'm trying to take a screenshot and then look through it for a pixel that has a certain color. Firstly, I tried to just print the color of an image at a certain xy coordinate but I could not even do that. What am I doing wrong?
static int ScreenWidth;
static int ScreenHeight;
static Robot robot;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic
callibrateScreenSize();
findSquares();
//takeScreenShot();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void callibrateScreenSize() {
try {
Rectangle captureSize = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
ScreenWidth = captureSize.width;
ScreenHeight = captureSize.height;
System.out.println("Width is " + ScreenWidth);
System.out.println("Height is " + ScreenHeight);
} catch (Exception e) {
e.printStackTrace();
}
//return null;
}
public static BufferedImage takeScreenShot() {
Rectangle captureSize = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage image = robot.createScreenCapture(captureSize);
return image;
}
public static void findSquares() {
System.out.println(takeScreenShot().getRGB(5,5));
}
Thanks!
You can use BufferedImage#getRGB or byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData() to get the pixel data. getRBG is more convenient, but is typically slower than getting the pixel array
getRGB packs the pixel data into an int, getData will return the RGB(A) in each entry of the array (R = n; G = n+1; B=n+2(, A=n+3)), so will need to process this yourself
You can use java.awt.Color, which allows you to access the RGB values of the color, pack it as a int value or convert an int to a Color
Color color = new Color(bufferedImage.getRGB(0, 0), true);
int redColor = Color.RED.getRGB();
The answer to this question provides an example of dealing with the byte[] pixel data
Basically, you will need to loop over the data, comparing the values in the image to the value you are after, either directly (comparing the red, green and blue values) or indirectly, comparing the packed int or Color values.
Personally, I'd grab the pixel data, convert each element to an int and compare it with a previously packed int from a Color object, this creates the less number of short lived objects and should be reasonably efficient
You can take a look at this answer which use getRGB to get the red, green, blue values from a given pixel
Here's something I wrote a while ago using the Robot class. It returns an array of the screen wherever the screen is white, it was not very computationally expensive for my application, but I found probing the values individually using robot was. At first I didn't even read your question, but looking back, I think this will help you A LOT. Good luck. And then I saw the original post date...
public boolean[][] raster() throws AWTException, IOException{
boolean[][] filled= new boolean[720][480];
BufferedImage image = new Robot().createScreenCapture(new Rectangle(0,0,720,480));
//accepts (xCoord,yCoord, width, height) of screen
for (int n =0; n<720; n++){
for (int m=0; m<480; m++){
if(new Color(image.getRGB(n, m)).getRed()<254){
//can check any rgb value, I just chose red in this case to check for white pixels
filled[n][m]=true;
}
}
}
return filled;
}

How to create object based off .txt file information and assign to an arraylist?

GeometricObjectsData.txt:
CIRCLE, 1, blue, true
RECTANGLE, 1, 2, blue, true
RECTANGLE, 10, 2, red, true
CIRCLE, 2, green
RECTANGLE
CIRCLE
I'm not sure how I add the information from the .txt file to an object Circle() or Rectangle() and then add it to an ArrayList so I can compare the largest object based off Area.
I can post the other classes if needed, but I am just stuck on the main method where I create an object based off the information in the text file.
EDIT:
public static void main(String[] args) throws FileNotFoundException {
Scanner input = new Scanner(new File(
"C:/Users/Charles/Desktop/GeometricObjectsData.txt"));
ArrayList<GeometricObject> list = new ArrayList<GeometricObject>();
while (input.hasNextLine()) {
String line = input.nextLine();
String[] tokens = line.split(", ");
if (tokens[0].equals("CIRCLE")) {
Circle c = new Circle();
float radius = Float.parseFloat(tokens[1]);
c.setRadius(radius);
String color = String.valueOf(tokens[2]);
c.setColor(color);
Boolean filled = Boolean.valueOf(tokens[3]);
c.setFilled(filled);
c.getArea();
list.add(c);
System.out.println(c.toString());
} else if (tokens[0].equals("RECTANGLE")) {
Rectangle r = new Rectangle();
float height = Integer.parseInt(tokens[1]);
r.setHeight(height);
float width = Integer.parseInt(tokens[2]);
r.setWidth(width);
String color = String.valueOf(tokens[3]);
r.setColor(color);
Boolean filled = Boolean.valueOf(tokens[4]);
r.setFilled(filled);
r.getArea();
list.add(r);
System.out.println(r.toString());
}
}
}
}
I'm getting an ArrayIndexOutOfBoundsExecption after I changed the code to that. I think it stops when it hits the 4th line where it doesn't have the 4th token indicating if it is filled/not filled. How do I fix that?
All the info you need for creating these shapes are available on Oracle's website.
Circles: http://docs.oracle.com/javafx/2/api/javafx/scene/shape/Circle.html
Rectangles: http://docs.oracle.com/javase/7/docs/api/java/awt/Rectangle.html
I'm not sure exactly what the data in your txt file represents, but assuming the number for the circles is the radius and the two numbers for the rectangles are its width and height, you would want something like:
Scanner input = new Scanner(new File("C:/Users/Charles/Desktop/GeometricObjectsData.txt"));
// you read each line at a time, so better to have hasNextLine instead
while(input.hasNextLine()) {
String line = input.nextLine();
System.out.println(line);
String[] tokens = line.split(", ");
if (tokens[0].equals("Circle"){
Circle c = new Circle();
float radius = Float.parseFloat(tokens[1]);
c.setRadius(radius);
// do what you wish with circle
}
else if (tokens[0].equals("Rectangle"){
Rectangle r = new Rectangle();
int height = Integer.parseInt(tokens[1]);
int width = Integer.parseInt(tokens[2]);
r.setSize(width,height);
// do what you wish with rectangle
}
}
As for the other information provided on the txt file, you will need to explain what the true means. Neither the circle nor rectangle classes have methods involving color, so if you plan to draw them, on a canvas, then you will need to look up the methods for a canvas pertaining to filling in colors.
Building off of Pi Joules answer, you should probably make sure you are accounting for case in your text file:
if (tokens[0].equals("CIRCLE")){
Or better yet:
if (tokens[0].toUpperCase().equals("CIRCLE")){
Or even better yet:
if (tokens[0].equalsIgnoreCase("Circle")){

save Linked List in Notepad.txt

I draw many triangle polygons and store it in Linked List. My problem is that, when I store the drawing in a Notepad file, the data is unreadable (weird symbol). When I try to print it using println the output is like this java.awt.Polygon#1d6096.
How to store the coordinate of the polygon in Notepad?
...
java.util.List<Polygon> triangles = new LinkedList<Polygon>();
String pathname = "eyemovement.txt";
...
int[] xs = { startDrag.x, endDrag.x, midPoint.x };
int[] ys = { startDrag.y, startDrag.y, midPoint.y };
triangles.add(new Polygon(xs, ys,3));
...
public void actionPerformed(ActionEvent e) {
if(e.getSource() == saveBtn){
try {
FileOutputStream fos = new FileOutputStream(pathname);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(triangles);
oos.flush();
oos.close();
fos.close();
}
catch (Exception ex) {
System.out.println("Trouble writing display list vector");
}
}
EDITED:
I have tried all the suggestions but still I can't managed to get the output as the following. I have tried the "Printwriter" as well, but I cant solved the problem. Help me, please, my head is so heavy with this :-(
I draw the triangles, make changes, and store it in Linked List. After finished drawing, and make changes, I click save button and save it in Notepad.txt with hope that I will get the output in Notepad like this:
40 60 50 this line represents vertices Xs of triangle 1
40 40 50 this line represents vertices Ys of triangle 1
60 80 70 triangle 2
60 60 70
100 120 110 triangle 3
100 100 110
If you just want to store co-ordinates, and only want to write one way (into the file) then you should write an override method on your Polygon:
String toString() {
return this.x + ", " + this.y;
}
or something similar.
Of course the data is unreadable. It is "Data", not "Text". You have to read the file again with the ObjectInputStream class. Use the method `readObject(); This method returns an Object. Of course you have to cast it on this way:
Object o = ois.readObject(); // ois is the ObjectInputStream
List<Polygon> list = new ArrayList<Polygon>((List) o));
I think you just want to save the triangle to continue working with it after closing your program.
Nobody actually posted the absolute simplest way to do this, so here it goes.
Take a Polygon p, output a string representing the x/y coordinates of p (assuming p has at least 1 point) of the form "(x1 y1, x2 y2, x3 y3, ...)":
System.out.print("(" + p.xpoints[0] + p.ypoints[0]);
for (int i = 0; i < p.npoints; i++) {
System.out.print(", " + p.xpoints[i] + " " + p.ypoints[i]);
}
System.out.println(")");
I start with a test case.
import java.awt.Polygon;
import junit.framework.TestCase;
public class PolygonTest extends TestCase {
public void testToString() throws Exception {
Polygon polygon = new Polygon();
polygon.addPoint(0, 1);
polygon.addPoint(1, 1);
polygon.addPoint(1, 0);
assertEquals("(0,1;1,1;1,0)", polygon.toString());
}
}
I'm assuming here that you are using the awt Polygon class. This test fails, because awt's Polygon class doesn't override the default behavior. But Polygon has lots of good stuff in it you don't want to lose (maybe), so to add the new behavior we want (a toString() method), let's change this just a little bit:
import java.awt.Polygon;
import junit.framework.TestCase;
public class PolygonTest extends TestCase {
public void testToString() throws Exception {
Polygon polygon = new Triangle();
polygon.addPoint(0, 1);
polygon.addPoint(1, 1);
polygon.addPoint(1, 0);
assertEquals("(0,1;1,1;1,0)", polygon.toString());
}
}
This doesn't even compile, because the Triangle class doesn't exist yet. So let's create it (I'm using eclipse; I'll run QuickFix to create the class for me):
import java.awt.Polygon;
public class Triangle extends Polygon {
}
And now the test compiles, but fails as before. So let's write the toString() method:
import java.awt.Polygon;
public class Triangle extends Polygon {
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("(");
for (int i = 0; i < npoints; i++)
sb.append(String.format("%s,%s;", xpoints[i], ypoints[i]));
sb.deleteCharAt(sb.length() - 1); // get rid of the final semicolon
sb.append(")");
return sb.toString();
}
}
and now the test passes.
Note that I changed the format a little from what you requested, because I think you probably want to be able to distinguish between the point (5, 17) and the point (51, 7).

Categories