Java application for Android. There is the following piece of xml:
<TableRow>
<ImageView
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: layout_margin = "10dp"
android: src = "# drawable / icon_security" />
<TextView
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
style = "# style / DesignerTextStyle2"
android: layout_gravity = "center_vertical"
android: text = "# string / welcome_security_calls" />
</ TableRow>
I need to compare pixel image processing of the certain image on the screen (e.g. it is third image on the screen) with the famous image (i.e. this image - "# drawable / icon_security").
Can you show me an example for solving this problem?
This is the Java code that I use to compare two images using pixel values from URL
package imager;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.net.URL;
public class Imagecompare
{
public static void main(String args[])
{
String s1;
BufferedImage img1 = null;
BufferedImage img2 = null;
try {
URL url1 = new URL("http://www.lac.inpe.br/JIPCookbook/Resources/ImageSimilarity/d02.jpg");
URL url2 = new URL("http://www.lac.inpe.br/JIPCookbook/Resources/ImageSimilarity/s02.jpg");
img1 = ImageIO.read(url1);
img2 = ImageIO.read(url2);
} catch (IOException e) {
e.printStackTrace();
}
int width1 = img1.getWidth(null);
int width2 = img2.getWidth(null);
int height1 = img1.getHeight(null);
int height2 = img2.getHeight(null);
if ((width1 != width2) || (height1 != height2)) {
System.err.println("Error: Images dimensions mismatch");
System.exit(1);
}
long diff = 0;
for (int y = 0; y < height1; y++) {
for (int x = 0; x < width1; x++) {
int rgb1 = img1.getRGB(x, y);
int rgb2 = img2.getRGB(x, y);
int r1 = (rgb1 >> 16) & 0xff;
int g1 = (rgb1 >> 8) & 0xff;
int b1 = (rgb1 ) & 0xff;
int r2 = (rgb2 >> 16) & 0xff;
int g2 = (rgb2 >> 8) & 0xff;
int b2 = (rgb2 ) & 0xff;
diff += Math.abs(r1 - r2);
diff += Math.abs(g1 - g2);
diff += Math.abs(b1 - b2);
}
}
double n = width1 * height1 * 3;
double p = diff / n / 255.0;
double percnt = 100.0-(p*100.0);
System.out.println("PERCENT: " +percnt);
}
}
Related
This is the new Composite class for a Multiply(Overlay) effect made by Kristopher Ives(Howto perform a MULTIPLY composite effect using Graphics2D). As far as I can tell he's been inactive for quite some time. Every time I run the Main class all I get is "Expected integer sample type" exception which is thrown when:
'(r.getSampleModel().getDataType() != DataBuffer.TYPE_INT)'
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
public class MultiplyComposite implements Composite, CompositeContext {
protected void checkRaster(Raster r) {
if (r.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
throw new IllegalStateException("Expected integer sample type");
}
}
#Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
checkRaster(src);
checkRaster(dstIn);
checkRaster(dstOut);
int width = Math.min(src.getWidth(), dstIn.getWidth());
int height = Math.min(src.getHeight(), dstIn.getHeight());
int x, y;
int[] srcPixels = new int[width];
int[] dstPixels = new int[width];
for (y=0; y < height; y++) {
src.getDataElements(0, y, width, 1, srcPixels);
dstIn.getDataElements(0, y, width, 1, dstPixels);
for (x=0; x < width; x++) {
dstPixels[x] = mixPixel(srcPixels[x], dstPixels[x]);
}
dstOut.setDataElements(0, y, width, 1, dstPixels);
}
}
private static int mixPixel(int x, int y) {
int xb = (x) & 0xFF;
int yb = (y) & 0xFF;
int b = (xb * yb) / 255;
int xg = (x >> 8) & 0xFF;
int yg = (y >> 8) & 0xFF;
int g = (xg * yg) / 255;
int xr = (x >> 16) & 0xFF;
int yr = (y >> 16) & 0xFF;
int r = (xr * yr) / 255;
int xa = (x >> 24) & 0xFF;
int ya = (y >> 24) & 0xFF;
int a = Math.min(255, xa + ya);
return (b) | (g << 8) | (r << 16) | (a << 24);
}
#Override
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
return this;
}
#Override
public void dispose() {
}
public static final MultiplyComposite Multiply = new MultiplyComposite();
}
This is my code for blending the two photos together which are BufferedImage types. The Overlay is provided from a folder and converted to a buffered image in a separate method which you can find at the bottom, and the SS is provided by a screenshot that is run through another class to make it greyscale and is then converted to a BufferedImage and is returned(You can find that at the bottom too).
// BLENDING THE PHOTOS TOGETHER
public static BufferedImage photosBlender(BufferedImage SS, BufferedImage Overlay) {
try {
BufferedImage base = SS;
BufferedImage overlay = Overlay;
Graphics2D g2d = base.createGraphics();
g2d.setComposite(MultiplyComposite.Multiply);
int x = (base.getWidth() - overlay.getWidth()) / 2;
int y = (base.getHeight() - overlay.getHeight()) / 2;
g2d.drawImage(overlay, x, y, null);
g2d.dispose();
File f = new File("resources/OutputImages/OutputBlended.png");
ImageIO.write((RenderedImage) base, "png", f);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
GETTING THE OVERLAY: the args is provided by a random selection method for selecting random overlay files provided in resources
public static BufferedImage OverlayProcess(String args) {
BufferedImage OverlayInput = null;
JFrame OverlayFrame = null;
try {
OverlayInput = ImageIO.read(new File(args));
ImageIcon screenShotIcon = new ImageIcon(OverlayInput);
//To Display selected Overlay for Testing purposes
/*OverlayFrame = new JFrame();
OverlayFrame.setLayout(new FlowLayout());
OverlayFrame.setSize(1500, 800);
JLabel lbl = new JLabel();
lbl.setIcon(screenShotIcon);
OverlayFrame.add(lbl);
OverlayFrame.setVisible(true);
OverlayFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);*/
} catch (IOException e) {
}
return OverlayInput;
}
GREYSCALING THE SS
public class GreyscaleTheImage {
public static BufferedImage main(String args) throws IOException {
BufferedImage img = null;
File f = null;
//read image
try {
f = new File(args);
img = ImageIO.read(f);
} catch (IOException e) {
System.out.println(e);
}
//get image width and height
int width = img.getWidth();
int height = img.getHeight();
//convert to grayscale
int x = 0;
int y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
int p = img.getRGB(x, y);
int a = (p >> 24) & 0xff;
int r = (p >> 16) & 0xff;
int g = (p >> 8) & 0xff;
int b = p & 0xff;
//calculate average
int avg = (r + g + b) / 3;
//replace RGB value with avg
p = (a << 24) | (avg << 16) | (avg << 8) | avg;
img.setRGB(x, y, p);
}
}
BufferedImage finalImage = null;
try {
finalImage = img;
} catch (Exception e) {
System.out.println(e);
}
//write image
try {
f = new File("resources/OutputImages/Output.png");
ImageIO.write(img, "png", f);
} catch (IOException e) {
System.out.println(e);
}
return finalImage;
}//main() ends here
}//class ends here
I've already tried changing the Raster of the image but it's just too much for my current skill level. I simply can't understand what sampleModels are or what it means to have a DataType of 3. I have a suspicion that it might have something to do with the image possibly having something other than a 32 bit "integer" buffer (whatever that means), because of Kristopher's resources saying that's all it will work with.
I made a new method that converts the image to ARGB, thank you to Harald K for the help he left in the comment section. The ARGB image works with the method I was having issues with.
I'm trying to analyze an image-based 3digit number captcha from an online resource. The numbers do not move at all. I use BufferedImage's getSubimage(...) method to extract each number from the captcha. I have saved (0-9) for each of the ones, tens and hundreds place. (So 30 numbers in total)
I read the bytes of the online image into a byte[] and then create a BufferedImage object like this:
BufferedImage captcha = ImageIO.read(new ByteArrayInputStream(captchaBytes));
Then I compare this image to a list of images on my drive:
BufferedImage[] nums = new BufferedImage[10];
//Load images into the array here... The code is removed.
for(int i = 0; i < nums.length; i++) {
double x;
System.out.println(x = bufferedImagesEqualConfidence(nums[i], firstNumberImage));
if(x > 0.98) {
System.out.println("equal to image " + i + ".jpeg");
isNewEntry = false;
break;
}
}
This is how I compare two images:
static double bufferedImagesEqualConfidence(BufferedImage img1, BufferedImage img2) {
double difference = 0;
int pixels = img1.getWidth() * img1.getHeight();
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
for (int x = 0; x < img1.getWidth(); x++) {
for (int y = 0; y < img1.getHeight(); y++) {
int rgbA = img1.getRGB(x, y);
int rgbB = img2.getRGB(x, y);
int redA = (rgbA >> 16) & 0xff;
int greenA = (rgbA >> 8) & 0xff;
int blueA = (rgbA) & 0xff;
int redB = (rgbB >> 16) & 0xff;
int greenB = (rgbB >> 8) & 0xff;
int blueB = (rgbB) & 0xff;
difference += Math.abs(redA - redB);
difference += Math.abs(greenA - greenB);
difference += Math.abs(blueA - blueB);
}
}
} else {
return 0.0;
}
return 1-((difference/(double)pixels) / 255.0);
}
The image is loaded completely from a HttpURLConnection object wrapped in my own HttpGet object. And so I do: byte[] captchaBytes = hg.readAndGetBytes(); Which I know works because when I save BufferedImage captcha = ImageIO.read(new ByteArrayInputStream(captchaBytes));, it saves as a valid image on my drive.
However, even though 2 images are actually the same, the result shows they are not similar at all. BUT, when I save the image I downloaded from the online resource first, re-read it, and compare, it shows they are equal. This is what I'm doing when I say I save it and re-read it:
File temp = new File("temp.jpeg");
ImageIO.write(secondNumberImage, "jpeg", temp);
secondNumberImage = ImageIO.read(temp);
Image format: JPEG
I know this may have something to do with compression from ImageIO.write(...), but how can I make it so that I don't have to save the image?
The problem was within my bufferedImagesEqualConfidence method. Simply comparing RGB was not enough. I had to compare individual R/G/B values.
My initial bufferedImagesEqualConfidence that didn't work was:
static double bufferedImagesEqualConfidence(BufferedImage img1, BufferedImage img2) {
int similarity = 0;
int pixels = img1.getWidth() * img1.getHeight();
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
for (int x = 0; x < img1.getWidth(); x++) {
for (int y = 0; y < img1.getHeight(); y++) {
if (img1.getRGB(x, y) == img2.getRGB(x, y)) {
similarity++;
}
}
}
} else {
return 0.0;
}
return similarity / (double)pixels;
}
(Source: Java Compare one BufferedImage to Another)
The bufferedImagesEqualConfidence that worked is:
static double bufferedImagesEqualConfidence(BufferedImage img1, BufferedImage img2) {
double difference = 0;
int pixels = img1.getWidth() * img1.getHeight();
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
for (int x = 0; x < img1.getWidth(); x++) {
for (int y = 0; y < img1.getHeight(); y++) {
int rgbA = img1.getRGB(x, y);
int rgbB = img2.getRGB(x, y);
int redA = (rgbA >> 16) & 0xff;
int greenA = (rgbA >> 8) & 0xff;
int blueA = (rgbA) & 0xff;
int redB = (rgbB >> 16) & 0xff;
int greenB = (rgbB >> 8) & 0xff;
int blueB = (rgbB) & 0xff;
difference += Math.abs(redA - redB);
difference += Math.abs(greenA - greenB);
difference += Math.abs(blueA - blueB);
}
}
} else {
return 0.0;
}
return 1-((difference/(double)pixels) / 255.0);
}
(Source: Image Processing in Java)
I guess to find similarity between two images you have to compare the individual R/G/B values for each pixel rather than just the whole RGB value.
I using Slick2D and LWJGL and i want to ask one question how to change game icon in the taskbar when i run it.
Actually depending on what you precisely want to do it can be quite hard.
The easyest way is to use Slick2d method: In GameContainer you can use the setIcon(String) method.
But on one of my personal project I had some difficulties loading images with Slick at start. So I looked for another solution with LWJGL :
public static void main(String[] args) {
AppGameContainer app;
try {
app = new AppGameContainer(new Main("Anode"));
org.lwjgl.opengl.Display.setIcon(loadIcon("resources/images/logo.png", app));
}
public static ByteBuffer[] loadIcon(String filepath,AppGameContainer app)
{
BufferedImage image = null;
try
{
image = ImageIO.read(app.getClass().getClassLoader().getResource(filepath));
}
catch (IOException e)
{
e.printStackTrace();
}
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = loadIconInstance(image, 128);
buffers[1] = loadIconInstance(image, 32);
buffers[2] = loadIconInstance(image, 16);
return buffers;
}
private static ByteBuffer loadIconInstance(BufferedImage image, int dimension)
{
BufferedImage scaledIcon = new BufferedImage(dimension, dimension, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledIcon.createGraphics();
double ratio = 1;
if(image.getWidth() > scaledIcon.getWidth())
{
ratio = (double) (scaledIcon.getWidth()) / image.getWidth();
}
else
{
ratio = (int) (scaledIcon.getWidth() / image.getWidth());
}
if(image.getHeight() > scaledIcon.getHeight())
{
double r2 = (double) (scaledIcon.getHeight()) / image.getHeight();
if(r2 < ratio)
{
ratio = r2;
}
}
else
{
double r2 = (int) (scaledIcon.getHeight() / image.getHeight());
if(r2 < ratio)
{
ratio = r2;
}
}
double width = image.getWidth() * ratio;
double height = image.getHeight() * ratio;
g.drawImage(image, (int) ((scaledIcon.getWidth() - width) / 2), (int) ((scaledIcon.getHeight() - height) / 2),
(int) (width), (int) (height), null);
g.dispose();
byte[] imageBuffer = new byte[dimension*dimension*4];
int counter = 0;
for(int i = 0; i < dimension; i++)
{
for(int j = 0; j < dimension; j++)
{
int colorSpace = scaledIcon.getRGB(j, i);
imageBuffer[counter + 0] =(byte)((colorSpace << 8) >> 24 );
imageBuffer[counter + 1] =(byte)((colorSpace << 16) >> 24 );
imageBuffer[counter + 2] =(byte)((colorSpace << 24) >> 24 );
imageBuffer[counter + 3] =(byte)(colorSpace >> 24 );
counter += 4;
}
}
return ByteBuffer.wrap(imageBuffer);
}
I really advice you to use the Slick2d solution and is you don't reach your goal then you can switch to the more complicated one
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I found this Java class online and have been using it to compare images. However I want to add an offset to it. So for example, if the 2 images are 99% or 98% similar, I want it to return true.
public int compareImage(File fileA, File fileB) {
try {
// take buffer data from botm image files //
BufferedImage biA = ImageIO.read(fileA);
DataBuffer dbA = biA.getData().getDataBuffer();
int sizeA = dbA.getSize();
BufferedImage biB = ImageIO.read(fileB);
DataBuffer dbB = biB.getData().getDataBuffer();
int sizeB = dbB.getSize();
// compare data-buffer objects //
if (sizeA == sizeB) {
for (int i = 0; i < sizeA; i++) {
if (dbA.getElem(i) != dbB.getElem(i)) {
return false;
}
}
return true;
} else {
return false;
}
} catch (Exception e) {
System.out.println("Failed to compare image files ...");
return 0;
}
}
What is the best way to do this?
To see if they are 99% or 98% similar, you have to compare all the pixels, instead of returning false at the first instance of dbA.getElem(i) != dbB.getElem(i)
Try a counter:
int total = 0;
int is_silimar = 0;
for (int i = 0; i < sizeA; i++) {
total++;
if (dbA.getElem(i) == dbB.getElem(i)) { //change it to ==
is_similar ++;
}
}
//don't return anything yet
Then, you can return true when is_similar/total is 98% or 99%
Edit: change sizeA to min(sizeA, sizeB) if you want to test cases when the image sizes are different as well.
There are many approaches for image similarities, some of them requiring advanced AI algorithms. This Wikipedia post offers a pixel by pixel colour-distance image comparison (but it works for equal-sized images only). I am just copy pasting the Java implementation from the above link.
*Note that if you wanted absolute pixel equality (and not colour distance on a single pixel) you should just keep a counter with different pixels and no distance checking would be required.
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.net.URL;
public class ImgDiffPercent
{
public static void main(String args[])
{
BufferedImage img1 = null;
BufferedImage img2 = null;
try {
URL url1 = new URL("http://rosettacode.org/mw/images/3/3c/Lenna50.jpg");
URL url2 = new URL("http://rosettacode.org/mw/images/b/b6/Lenna100.jpg");
img1 = ImageIO.read(url1);
img2 = ImageIO.read(url2);
} catch (IOException e) {
e.printStackTrace();
}
int width1 = img1.getWidth(null);
int width2 = img2.getWidth(null);
int height1 = img1.getHeight(null);
int height2 = img2.getHeight(null);
if ((width1 != width2) || (height1 != height2)) {
System.err.println("Error: Images dimensions mismatch");
System.exit(1);
}
long diff = 0;
for (int y = 0; y < height1; y++) {
for (int x = 0; x < width1; x++) {
int rgb1 = img1.getRGB(x, y);
int rgb2 = img2.getRGB(x, y);
int r1 = (rgb1 >> 16) & 0xff;
int g1 = (rgb1 >> 8) & 0xff;
int b1 = (rgb1 ) & 0xff;
int r2 = (rgb2 >> 16) & 0xff;
int g2 = (rgb2 >> 8) & 0xff;
int b2 = (rgb2 ) & 0xff;
diff += Math.abs(r1 - r2);
diff += Math.abs(g1 - g2);
diff += Math.abs(b1 - b2);
}
}
double n = width1 * height1 * 3;
double p = diff / n / 255.0;
System.out.println("diff percent: " + (p * 100.0));
}
}
i am trying to get difference between two images ( same size ) i found this code :
BufferedImage img1 = null;
BufferedImage img2 = null;
try{
URL url1 = new URL("http://rosettacode.org/mw/images/3/3c/Lenna50.jpg");
URL url2 = new URL("http://rosettacode.org/mw/images/b/b6/Lenna100.jpg");
img1 = ImageIO.read(url1);
img2 = ImageIO.read(url2);
} catch (IOException e) {
e.printStackTrace();
}
int width1 = img1.getWidth(null);
int width2 = img2.getWidth(null);
int height1 = img1.getHeight(null);
int height2 = img2.getHeight(null);
if ((width1 != width2) || (height1 != height2)) {
System.err.println("Error: Images dimensions mismatch");
System.exit(1);
}
long diff = 0;
for (int i = 0; i < height1; i++) {
for (int j = 0; j < width1; j++) {
int rgb1 = img1.getRGB(i, j);
int rgb2 = img2.getRGB(i, j);
int r1 = (rgb1 >> 16) & 0xff;
int g1 = (rgb1 >> 8) & 0xff;
int b1 = (rgb1 ) & 0xff;
int r2 = (rgb2 >> 16) & 0xff;
int g2 = (rgb2 >> 8) & 0xff;
int b2 = (rgb2 ) & 0xff;
diff += Math.abs(r1 - r2);
diff += Math.abs(g1 - g2);
diff += Math.abs(b1 - b2);
}
}
double n = width1 * height1 * 3;
double p = diff / n / 255.0;
System.out.println("diff percent: " + (p * 100.0)); `
it works fine for the two images given in the url , but when i changed the images given i get this exception :
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds!
at sun.awt.image.ByteInterleavedRaster.getDataElements(ByteInterleavedRaster.java:299)
at java.awt.image.BufferedImage.getRGB(BufferedImage.java:871)
at Main.main(Main.java:77)
I changed the code to :
File sourceimage1 = new File("C:\\lo.jpg");
File sourceimage2 = new File("C:\\lo1.jpg");
img1 = ImageIO.read(sourceimage1);
img2 = ImageIO.read(sourceimage2);
the two images are black and white , and their dimensions are smaller than the two previous images (lenna50 and lenna100)
the lo.jpg and lo1.jpg are the same image to test the algorithm also they are in black and white
how can I change the code to make it work for any image dimension ?
Toggle the i and j
in the following code as I have done below:
int rgb1 = img1.getRGB(j, i);
int rgb2 = img2.getRGB(j, i);
Your error clearly says that while reading rgb point as code in line img1.getRGB(i, j); it is going out of Array for image RGB. Check the values of i & j inside your inner for loop and check whether something you are doing wrong. As already Hirak pointed may be that you are not initializing your variables properly and so the reason it is going out of height or width.