Comparing icons as strings always returning false? - java

I'm currently working on a Tic-Tac-Toe game with java swing and figuring out how to create a checkWin method. The Tic-Tac-Toe board is initialized as a 2D array of buttons. Each button is assigned an image when clicked (alternating x's and o's).
The problem is, even when comparing two icons with the same string description, it returns false. Here's my code for
The Image assignment
public ImageIcon getImage(){
BufferedImage img = null;
String name="";
try{
if(this.num()== 1){
img = ImageIO.read(new FileInputStream(new File("x.jpg")));
name="x";
}else{
img = ImageIO.read(new FileInputStream(new File("o.jpg")));
name="o";
}
}catch(Exception e){
System.out.println(e);
System.out.println("null :(");
return null;
}
Image scaledImage = img.getScaledInstance(40, 40,Image.SCALE_SMOOTH);
ImageIcon imageIcon = new ImageIcon(scaledImage,name);
return imageIcon;
}
Here's the code snippet for equality comparison (also I have no idea why, but my 2d array prints out column major order rather than row major order)
buttons[i][j].getIcon().equals(buttons[i-1][j].getIcon()));
comparing the two o's below returns false
This is my first time posting on overflow please be patient with me :)

You should use integers instead, to represent 'x's and 'o's(like 1 and 0). And then, show them as images on the screen?

It'd be better to use an enumeration to compare, rather than the icons or integers as others have suggested. Why not integers? Because they're not as readable as using constants from an enumeration - you have to remember what 1 or 0 mean. There are other reasons to prefer an enumeration, too:
An integer field allows any value that fits, but there are only a limited set of possibilities. It's misleading for a reader. Strings would have the same problem.
Since the enumeration is a limited set of possibilities, an IDE can automatically suggest them all when you do want to compare, or otherwise use the values.

Related

How to Compare two ImageIcons?

Basically, i'm using 2 images for a board game type of thing, and i change it from time to time,
So i need to be able to check if two has the same imageIcon.
For example if both uses "pirosfigura.png" from the resources folder.
public String malomcheck() {
String pirosicon=lblNewLabel.getIcon().toString();
String pirosfilenev = pirosicon.substring(pirosicon.lastIndexOf("/" ) + 1);
String iconfilenev = labelhely_1.getIcon().toString();
String filenev = iconfilenev.substring(iconfilenev.lastIndexOf("/" ) + 1);
if(filenev==pirosfilenev) {
lblJtkos.setText("piros malom.");
JOptionPane.showMessageDialog(null, "working");
return "lefutott";
}
return "notworking. very sad.";
}
By the way the return value of the getIcon().toString() is javax.swing.ImageIcon#cd7e8021
which is refers to the memory place i guess(?) so it's random with every run and for every image therefore it's seems unusable.
One way you can achieve this, is to keep your own mapping of ImageIcons to files, so that whenever you load an ImageIcon you store it in a Map as a key and its file or some symbolic name/enum as value. This way when you want to compare imIc1 and imIc2 you would write something like:
if (map.get(imIc1).equals(map.get(imIc2)) { ... }
or (if you have descriptive string values )
if (map.get(imIc1).equals("NOT_WORKING_ICON") { ... }
or (if you are using enum values )
if (map.get(imIc1) == NOT_WORKING_ICON ) { ... }
it's so weird for me that there is no method to get to the filepath the Jlabel is using for an image.
Makes perfect sense. A JLabel displays an Icon.
Why should a JLabel know or care about the file path?
You could implement the Icon interface yourself and do the custom painting for the Icon. So not all Icons will have a file path. Only an ImageIcon is created from a file.
The property for the file name belongs to the ImageIcon.
By the way the return value of the getIcon().toString() is javax.swing.ImageIcon#cd7e8021
Image piros=new ImageIcon(this.getClass().getResource("pirosfigura.png")).getImage();
celpont.setIcon(new ImageIcon(piros));
Look at the above code that you are using.
You area creating an Icon from an Image, so the file information is lost.
Instead you should just create the ImageIcon directly:
ImageIcon icon = new ImageIcon( this.getClass().getResource("pirosfigura.png") );
celpont.setIcon( icon );
System.out.println( celpont.getIcon() );
I believe the ImageIcon will then save the filename as the "description" for the ImageIcon. It appears the toString() will return the description.

Matching images from file with Sikuli

I just found about Sikuli when I was looking for a library to find matches of a given image within a larger image (both loaded from files).
By default, Sikuli only supports loading the searched image from file, but relies on a proprietary class Screen to take screenshots to use as base for the search... And I'd like to have the ability to use a image file instead.
Looking for a solution has led me to this question, but the answer is a bit vague when you consider that I have no prior experience with Sikuli and the available documentation is not particularly helpful for my needs.
Does anyone have any examples on how to make a customized implementation of Screen, ScreenRegion, ImageScreen and ImageScreenLocation? Even a link to a more detailed documentation on these classes would be a big help.
All I want is to obtain the coordinates of an image match within another image file, so if there's another library that could help with this task I'd more than happy to learn about it!
You can implement it by yourself with something like this:
class MyImage{
private BufferedImage img;
private int imgWidth;
private int imgHeight;
public MyImage(String imagePath){
try{
img = ImageIO.read(getClass().getResource(imagePath));
}catch(IOException ioe){System.out.println("Unable to open file");}
init();
}
public MyImage(BufferedImage img){
this.img = img;
init();
}
private void init(){
imgWidth = img.getWidth;
imgHeight = img.getHeight();
}
public boolean equals(BufferedImage img){
//Your algorithm for image comparison (See below desc for your choices)
}
public boolean contains(BufferedImage subImage){
int subWidth = subImage.getWidth();
int subHeight = subImage.getHeight();
if(subWidth > imgWidth || subHeight > imgHeight)
throw new IllegalArgumentException("SubImage is larger than main image");
for(int x=0; x<(imgHeight-subHeight); x++)
for(int y=0; y<(imgWidth-subWidth); y++){
BufferedImage cmpImage = img.getSumbimage(x, y, subWidth, subHeight);
if(subImage.equals(cmpImage))
return true;
}
return false;
}
}
The contains method will grab a subimage from the main image and compare with the given subimage. If it is not the same, it will move on to the next pixel until it went through the entire image. There might be other more efficient ways than moving pixel by pixel, but this should work.
To compare 2 images for similarity
You have at least 2 options:
Scan pixel by pixel using a pair of nested loop to compare the RGB value of each pixel. (Just like how you compare two int 2D array for similarity)
It should be possible to generate a hash for the 2 images and just compare the hash value.
Aah... Sikuli has an answer for this too... You just didnt look close enough. :)
Answer : The FINDER Class
Pattern searchImage = new Pattern("abc.png").similar((float)0.9);
String ScreenImage = "xyz.png"; //In this case, the image you want to search
Finder objFinder = null;
Match objMatch = null;
objFinder = new Finder(ScreenImage);
objFinder.find(searchImage); //searchImage is the image you want to search within ScreenImage
int counter = 0;
while(objFinder.hasNext())
{
objMatch = objFinder.next(); //objMatch gives you the matching region.
counter++;
}
if(counter!=0)
System.out.println("Match Found!");
In the end I gave up on Sikuli and used pure OpenCV in my Android project: The Imgproc.matchTemplate() method did the trick, giving me a matrix of all pixels with "scores" for the likehood of that being the starting point of my subimage.
With Sikuli, you can check for the presence of an image inside another one.
In this example code, the pictures are loaded from files.
This code tell us if the second picture is a part of the first picture.
public static void main(String[] argv){
String img1Path = "/test/img1.png";
String img2Path = "/test/img2.png";
if ( findPictureRegion(img1Path, img2Path) == null )
System.out.println("Picture 2 was not found in picture 1");
else
System.out.println("Picture 2 is in picture 1");
}
public static ScreenRegion findPictureRegion(String refPictureName, String targetPictureName2){
Target target = new ImageTarget(new File(targetPictureName2));
target.setMinScore(0.5); // Precision of recognization from 0 to 1.
BufferedImage refPicture = loadPicture(refPictureName);
ScreenRegion screenRegion = new StaticImageScreenRegion(refPicture);
return screenRegion.find(target);
}
public static BufferedImage loadPicture(String pictureFullPath){
try {
return ImageIO.read(new File(pictureFullPath));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
To use Sikuli package, I added this dependency with Maven :
<!-- SIKULI libraries -->
<dependency>
<groupId>org.sikuli</groupId>
<artifactId>sikuli-api</artifactId>
<version>1.1.0</version>
</dependency>

Java swing 2D pixel based sprite class not working correctly

I made me a pixel based sprite class for a simple game in java and swing, and I don't want to let some sprites go through other sprites. So I wrote two loops that are supposed to add the pixels of every other sprite to the "material" array of the level. Material should not be passable. With the level it does work. There the sprite can't pass through its material. But with other sprites it doesn't. It can go through them. And that's the bug I actually want to fix. It seems that the sprites' pixel arrays aren't appended.
Any help is greatly appreciated !
Code :
int applied_pixels=lvl.material.length;
Sprite[] others=new Sprite[] {other sprites};
/*EDIT : others[i].frameborders[others[i].frame].all is the point array of the sprites' pixels
others[i].frame is the frame of the sprite object, because they contain an array of BufferedImages. Frame is the one that should be taken*/
Level lvl=the level; //Containing a couple of point arrays of pixels of some types, for example containing the material array of pixels
int apply_pixels=0; //How many pixels are needed ?
for (int i=0; i < others.length; i++) {
if (others[i] != null) { //Isn't the sprite null
apply_pixels=apply_pixels+others[i].frameborders[others[i].frame].all.length; //How many points does it has to add ?
}
}
level=lvl.clone(); //Copy level to be able to later append points to the material array
level.material=new Point[apply_pixels];
System.arraycopy(lvl.material,0,level.material,0,lvl.material.length); //Copy old material array points
int appending_position=0;
appending_position=lvl.material.length; //Which destination position to append the points at ?
for (int i=0; i < others.length; i++) {
if (others[i] != null) { //Isn't the sprite null
System.arraycopy(others[i].frameborders[others[i].frame].all,0,level.material,appending_position,others[i].frameborders[others[i].frame].all.length); //Copy the points from the sprite to the material array
appending_position=appending_position+others[i].frameborders[others[i].frame].all.length; //Position to append at is now plus the length of appended points
}
}
I see two possible problems with your code as posted.
The first is that level.material=new Point[apply_pixels]; only allocates elements for the new pixels. It should probably read level.material=new Point[lvl.material.length + apply_pixels];. Alternatively, you can initialize apply_pixels as int apply_pixel = lvl.material.length instead of to zero.
The second problem is that you never show us how lvl replaces the original level. Presumably the code you posted is part of a method somewhere and level is an input that is passed in, but is accessed through a field by other parts of the program. Unless the modified lvl is correctly returned and replaces the original, the code here will have no effect. However, this is only speculation because OP refuses to post the relevant code.

(Java) Producing image by reading from a text-file filled with digits

I'm a complete beginner in Java programming and I'm interested to learn more about its concepts.
Recently, I've been given an exercise which instructs me to display two versions of a picture. The picture to be displayed is provided in the form of a data file of 40,000 digits that are arranged in rows (although there is no marker between rows) and it starts from the top of the picture. So the first digit represents the top left corner of the picture and the last is the bottom right.
Basically, what the exercise wants me to construct a program that plots a dot in one of two colours for each digit. If the digit is in the range 0 to 3 the output should be one colour and for digits in the range 4 to 9 the dot should be in the other colour.
I understand I have to use arrays and also loops to perform this. I'm familiar with the fillEllipse, drawEllipse, drawRectangle and fillRectangle but this exercise is nothing I've attempted before.
Any hints on how to make this work? Your help would be greatly appreciated.
As a hint, rather than a complete solution, I would suggest looking into creating a java.awt.image.BufferedImage, and then set the colors of the individual pixels using the setRGB() method. You would then display this image using drawImage() on your Graphics object.
All what you need is how to read the digits from the file and put it into two dimension array
check this tutorial for how to read a file
Then you have to draw each pixel on a fram or a Panel
check this Java basic graphics tutorial
I hope this could help!
use Scanner to read the data like :
Scanner sc = new Scanner(new File("path_to_your_digits_file"));
int[][] digits= new int [200][200];
String line;
while(sc.hasNext()){//this means there is still a line to go
line = sc.nextLine();
//split the line and fill the array . or read char by char ,
// i dont know how your file looks like, it's just some simple string manipulation here
}
int x;
BufferedImage img = new BufferedImage(200,200,BufferedImage.TYPR_INT_RGB);
for(int i=0;i<200;i++){
for(int j=0;i<200;j++){
if(digits[i][j]>0 && digits[i][j]<=3){
x=//some color code;
}else{
x=//some other color code;
} //not sure about this loop , again idk the structure of your file;
img.setRGB(i,j,x);
}
}
JLabel lbl = new JLabel();
lbl.setSize(200,200);
ImageIcon ico=new ImageIcon(img);
lbl.setIcone(ico);
lbl.setVisible(true);
JFrame frame = new Jframe();
frame.setSize(500,500);
frame.add(lbl);
frame.setVisible(true);

java cannot be applied to given types

so i got this error:
java cannot be applied to given types; required: java.lang.String,int,int; found:java.lang.String; reason: actual and formal argument lists differ in lenghhs
when i typed this in one Actor (im using Greenfoot):
public String getPunkte()
{
String stringPunkte = Integer.toString(punkte);
return(stringPunkte);
}
and this in the other:
public void malePunkte()
{
GreenfootImage img = new GreenfootImage(50, 10);
img.drawString(getPunkte());
}
for those who dont understand:
this is supposed to convert the int (punkte)(means points in german) into a String and then return the amount of points in one actor to the other, wich then displays that number.
if you still don't understand or you need another piece of code just ask.
Thx
Well error is quite self explanatory isn't it ?
what you expect to get back is String, int, int and you only 'supply' String
try this
public void malePunkte() {
GreenfootImage img = new GreenfootImage();
img.drawString(getPunkte(), 50, 10);
}
ps. on return statement you do not need to surround with bracket the variable you want to return. Just do
return stringpunkte
ps. i have no idea what the GreenfootImage is ;)
edit: According to helpful link provided by - Gyro Gearless
www.greenfoot.org/files/javadoc/greenfoot/GreenfootImage.html
drawImage(GreenfootImage image, int x, int y)
Draws the given Image onto this image
and
GreenfootImage(int width, int height)
Create an empty (transparent) image with the specified size.
As you can see drawImage draws on top of the created 'empty' image. So as Constructor argument you can specify the size of empty image, and as to a method you can specify the size of the new image that will go on top of the empty one

Categories