Programmatically determine if 2 images look the same using Java [closed] - java

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 5 years ago.
Improve this question
In JAVA I am trying to programmatically tell if 2 images are equal when displayed on the screen (AKA same image even though they have different color spaces. Is there a piece of code that will return a boolean when presented 2 images?
One of the examples I have is a RGB PNG that I converted to a greyscale PNG. Both images look the same and I would like to prove this programmatically. Another example is two images where they display the exact same color pixels to the screen but the color used for 100% transparent pixels has changed.

I looked at all of the solutions and determined that they could tell you how different the images were or worked for some types of images, but not all of them. Here is the solution I came up with...
package image.utils;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods used to interact with images.
*/
public class ImageUtils {
private final static Logger logger = LoggerFactory.getLogger(ImageUtils.class);
private static final boolean equals(final int[] data1, final int[] data2) {
final int length = data1.length;
if (length != data2.length) {
logger.debug("File lengths are different.");
return false;
}
for(int i = 0; i < length; i++) {
if(data1[i] != data2[i]) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if((((data1[i] >> 24) & 0xff) == 0) && (((data2[i] >> 24) & 0xff) == 0)) {
logger.debug("Both pixles at spot {} are different but 100% transparent.", Integer.valueOf(i));
} else {
logger.debug("The pixel {} is different.", Integer.valueOf(i));
return false;
}
}
}
logger.debug("Both groups of pixels are the same.");
return true;
}
private static final int[] getPixels(final BufferedImage img, final File file) {
final int width = img.getWidth();
final int height = img.getHeight();
int[] pixelData = new int[width * height];
final Image pixelImg;
if (img.getColorModel().getColorSpace() == ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
pixelImg = img;
} else {
pixelImg = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(img, null);
}
final PixelGrabber pg = new PixelGrabber(pixelImg, 0, 0, width, height, pixelData, 0, width);
try {
if(!pg.grabPixels()) {
throw new RuntimeException();
}
} catch (final InterruptedException ie) {
throw new RuntimeException(file.getPath(), ie);
}
return pixelData;
}
/**
* Gets the {#link BufferedImage} from the passed in {#link File}.
*
* #param file The <code>File</code> to use.
* #return The resulting <code>BufferedImage</code>
*/
#SuppressWarnings("unused")
final static BufferedImage getBufferedImage(final File file) {
Image image;
try (final FileInputStream inputStream = new FileInputStream(file)) {
// ImageIO.read(file) is broken for some images so I went this
// route
image = Toolkit.getDefaultToolkit().createImage(file.getCanonicalPath());
//forces the image to be rendered
new ImageIcon(image);
} catch(final Exception e2) {
throw new RuntimeException(file.getPath(), e2);
}
final BufferedImage converted = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = converted.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return converted;
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* #param file1 First file to compare
* #param file2 Second image to compare
* #return <code>true</code> if they are equal, otherwise
* <code>false</code>.
*/
private final static boolean visuallyCompareJava(final File file1, final File file2) {
return equals(getPixels(getBufferedImage(file1), file1), getPixels(getBufferedImage(file2), file2));
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* #param file1 Image 1 to compare
* #param file2 Image 2 to compare
* #return <code>true</code> if both images are visually the same.
*/
public final static boolean visuallyCompare(final File file1, final File file2) {
logger.debug("Start comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
if(file1 == file2) {
return true;
}
boolean answer = visuallyCompareJava(file1, file2);
if(!answer) {
logger.info("The files \"{}\" and \"{}\" are not pixel by pixel the same image. Manual comparison required.", file1.getPath(), file2.getPath());
}
logger.debug("Finish comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
return answer;
}
/**
* #param file The image to check
* #return <code>true</code> if the image contains one or more pixels with
* some percentage of transparency (Alpha)
*/
public final static boolean containsAlphaTransparency(final File file) {
logger.debug("Start Alpha pixel check for {}.", file.getPath());
boolean answer = false;
for(final int pixel : getPixels(getBufferedImage(file), file)) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if(((pixel >> 24) & 0xff) != 255) {
logger.debug("The image contains Aplha Transparency.");
return true;
}
}
logger.debug("The image does not contain Aplha Transparency.");
logger.debug("End Alpha pixel check for {}.", file.getPath());
return answer;
}
}

For grayscale images I've used Mean Square Error as a measure of how different two images are before. Just plug the corresponding pixels from each image into the formula.
Not only can this tell you if they are exactly the same, but also it can tell you how different two images are, albeit in a rather crude manner.
https://en.wikipedia.org/wiki/Mean_squared_error
EDIT:
Note: This is C# code not Java (apologies but that's what I wrote it in originally), however it should be easily transferable.
//Calculates the MSE between two images
private double MSE(Bitmap original, Bitmap enhanced)
{
Size imgSize = original.Size;
double total = 0;
for (int y = 0; y < imgSize.Height; y++)
{
for (int x = 0; x < imgSize.Width; x++)
{
total += System.Math.Pow(original.GetPixel(x, y).R - enhanced.GetPixel(x, y).R, 2);
}
}
return (total / (imgSize.Width * imgSize.Height));
}

You can try this
Example
Wayback Machine to the rescue here
They explain how to compare two images

If you mean exactly the same, compare each pixel.
If you mean compare a RGB image and a greyscale image, you need to convert the RGB to greyscale first, for doing this, you need to know how you did RGB->Greyscale before, there're different ways of doing this and you could get different results.
Edit, if the method it used in RGB->Greyscale is liner, you could work out a,b,c in the formula grey = a*R + b*G + c*B by comparing 3 pixels.

One of the easiest approach I tried is getting the pixel array of both images and comparing them with Arrays.equals method.
Code sample :
package image_processing;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.ImageIO;
public class CheckPixels {
public static void main(String args[]) throws IOException {
File pic1 = new File("D:\\ani\\img1.png");
File pic2 = new File("D:\\ani\\img2.png");
if (Arrays.equals(returnPixelVal(pic1), returnPixelVal(pic2))) {
System.out.println("Match");
} else {
System.out.println("No match");
}
}
public static byte[] returnPixelVal(File in) {
BufferedImage img = null;
File f = null;
byte[] pixels = null;
// read image
try {
f = in;
img = ImageIO.read(f);
pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
} catch (IOException e) {
System.out.println(e);
}
return pixels;
}
}

Related

Create a png preview image from hex color palette files in java, batch process all those files in a directory

I am trying to create a simple class that will help me organize my hundred's of text files that represent distinct color palettes in hex format. No size restrictions but in most cases colors are less than 256 per file and support transparency also (6 or 8 hex digits).
the format is simply a text file like this (a value per line):
546A817F
A7AC827F
ACBFB97F
9DB3BA7F
...
The goal is to create a preview png image per every palette file in a direcory. (format is PNG in order to support transparency, and when viewed in image viewers easily see/get the actual color).
Preferably constructed in colored rectangles side by side, preferably with the option to set a title with the hex value.
I have tried with the following code, but there are problems in the constriction of the Graphics2D object.
The functions goes like this:
1.scan a directory for all the files,
2.for every file, we scan contents and create a list of the hex values that holds
3. we count those colors and create a png image with those colors as filled rectangles, side by side. (and maybe print the hex value also inside/top/bottom of every rectangle)
4. The best would be not to have a fixed size image, but a variable one, taking care the amount of colors per list/file.
a simple example of placing colors can be found here: http://www.java2s.com/Code/Java/2D-Graphics-GUI/ColorGradient.htm
I am not a java developer, just trying to develop simple tools to make my life easier for my personal projects. I do not care a about good code practices, I am interested only in the final result, so I'm sorry for the mixed up code or mistakes!
code till now, the alignment of rectangles is broken, loops for scanning I think work simply ok, but images I think overlay the previous graphics object on top of each other (best seen with transparency).
any contribution welcomed. Thanks in advance.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import static java.nio.charset.Charset.defaultCharset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.imageio.ImageIO;
/**
*
* #author
*/
public class ConvertFromHexColorListToImage {
public Color c = new Color (0,0,0,0);
public List<String> list = new ArrayList<>();
int count;
private BufferedImage buffer;
// the size of our image
private int IMAGE_SIZE = 800;
public ConvertFromHexColorListToImage() throws IOException {
}
protected BufferedImage getBuffer() throws IOException {
if (buffer == null) {
buffer = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE/2, BufferedImage.TYPE_INT_ARGB);
try (Stream<Path> filePathStream=Files.walk(Paths.get("data/multi_hex/hex_only/"))) {
filePathStream.forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
System.out.println(filePath);
count++;
System.out.println("count = " +count);
try {
//list = new ArrayList<>();
list = Files.readAllLines(filePath);
System.out.println("list = "+list);
// one image per list index
for (int i = 0; i < count; i++) {
for(int j = 0; j < list.size(); j++){
Graphics2D g = (Graphics2D) buffer.getGraphics();
//c = new Color(0,0,0,0);
c = HexToColor(list.get(j));
Random rand = new Random();
// Show all the predefined colors.
float size = 25;
float x = -size * list.size() / 8;
float y = -size * 3 / 2;
Rectangle2D r = new Rectangle2D.Float(
x + IMAGE_SIZE/12 * (float)j, y, IMAGE_SIZE/12, IMAGE_SIZE/12);
// c = HexToColor(list.get(j));
g.setPaint(c);
g.fill(r);
g.dispose();
}
}
File f = new File("data/image_pal/MyFile"+""+count+".png"); // i=files, j=colors
System.out.println("Created IMAGE = "+f);
if (!ImageIO.write(buffer, "PNG", f)) {
throw new RuntimeException("Unexpected error writing image");
}
}catch (IOException ex) {
Logger.getLogger(ConvertFromHexColorListToImage.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
return buffer;
}
//https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java
/**
* Converts a hex string to a color. If it can't be converted null is
* returned.
*
* #param hex (i.e. #CCCCCCFF or CCCCCC)
* #return Color
*/
public static Color HexToColor(String hex)
{
hex = hex.replace("#", "");
switch (hex.length()) {
case 6:
return new Color(
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16));
case 8:
return new Color(
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16),
Integer.valueOf(hex.substring(6, 8), 16)); //alpha FF
}
//return null;
return new Color(0, 0, 0, 0);
}
public static void main(String[] args) throws IOException {
ConvertFromHexColorListToImage test0 = new ConvertFromHexColorListToImage();
test0.getBuffer();
System.out.println("bufferedimage = "+test0.buffer);
}
}

Java - resize image without losing quality

I have 10,000 photos that need to be resized so I have a Java program to do that. Unfortunately, the quality of the image is poorly lost and I don't have access to the uncompressed images.
import java.awt.Graphics;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* This class will resize all the images in a given folder
* #author
*
*/
public class JavaImageResizer {
public static void main(String[] args) throws IOException {
File folder = new File("/Users/me/Desktop/images/");
File[] listOfFiles = folder.listFiles();
System.out.println("Total No of Files:"+listOfFiles.length);
BufferedImage img = null;
BufferedImage tempPNG = null;
BufferedImage tempJPG = null;
File newFilePNG = null;
File newFileJPG = null;
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
img = ImageIO.read(new File("/Users/me/Desktop/images/"+listOfFiles[i].getName()));
tempJPG = resizeImage(img, img.getWidth(), img.getHeight());
newFileJPG = new File("/Users/me/Desktop/images/"+listOfFiles[i].getName()+"_New");
ImageIO.write(tempJPG, "jpg", newFileJPG);
}
}
System.out.println("DONE");
}
/**
* This function resize the image file and returns the BufferedImage object that can be saved to file system.
*/
public static BufferedImage resizeImage(final Image image, int width, int height) {
int targetw = 0;
int targeth = 75;
if (width > height)targetw = 112;
else targetw = 50;
do {
if (width > targetw) {
width /= 2;
if (width < targetw) width = targetw;
}
if (height > targeth) {
height /= 2;
if (height < targeth) height = targeth;
}
} while (width != targetw || height != targeth);
final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setComposite(AlphaComposite.Src);
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(image, 0, 0, width, height, null);
graphics2D.dispose();
return bufferedImage;
}
An image I am working with is this:
This is the manual resizing I've done in Microsoft Paint:
and this is the output from my program [bilinear]:
UPDATE: No significant difference using BICUBIC
and this is the output from my program [bicubic]:
is there anyway to increase the quality of the program output so I don't have to manually resize all photos?
Thank you in advance!
Unfortunately, there is no recommended out-of-the-box scaling in Java that provides visually good results. Among others, here are the methods I recommend for scaling:
Lanczos3 Resampling (usually visually better, but slower)
Progressive Down Scaling (usually visually fine, can be quite fast)
One-Step scaling for up scaling (with Graphics2d bicubic fast and good results, usually not as good as Lanczos3)
Examples for every method can be found in this answer.
Visual Comparison
Here is your image scaled to 96x140 with different methods/libs. Click on the image to get the full size:
Morten Nobel's lib Lanczos3
Thumbnailator Bilinear Progressive Scaling
Imgscalr ULTRA_QUALTY (1/7 step Bicubic Progressive Scaling)
Imgscalr QUALTY (1/2 step Bicubic Progressive Scaling)
Morten Nobel's lib Bilinear Progressive Scaling
Graphics2d Bicubic interpolation
Graphics2d Nearest Neighbor interpolation
Photoshop CS5 bicubic as reference
Unfortunately a single image is not enough to judge a scaling algorithm, you should test icons with sharp edges, photos with text, etc.
Lanczos Resampling
Is said to be good for up- and especially downscaling. Unfortunately there is no native implementation in current JDK so you either implement it yourself and use a lib like Morten Nobel's lib. A simple example using said lib:
ResampleOp resizeOp = new ResampleOp(dWidth, dHeight);
resizeOp.setFilter(ResampleFilters.getLanczos3Filter());
BufferedImage scaledImage = resizeOp.filter(imageToScale, null);
The lib is published on maven-central which is not mentioned unfortunately. The downside is that it usually is very slow without any highly optimized or hardware accelerated implementations known to me. Nobel's implementation is about 8 times slower than a 1/2 step progressive scaling algorithm with Graphics2d. Read more about this lib on his blog.
Progressive Scaling
Mentioned in Chris Campbell's blog about scaling in Java, progressive scaling is basically incrementally scaling an image in smaller steps until the final dimensions are reached. Campbell describes it as halving width/height until you reach target. This produces good results and can be used with Graphics2D which can be hardware accelerated, therefore usually having very good performance with acceptable results in most cases. The major downside of this is if downscaled less than half using Graphics2D provides the same mediocre results since it is only scaled once.
Here is a simple example on how it works:
The following libs incorporate forms of progressive scaling based on Graphics2d:
Thumbnailator v0.4.8
Uses the progressive bilinear algorithm if the target is at least half of every dimension, otherwise it uses simple Graphics2d bilinear scaling and bicubic for upscaling.
Resizer resizer = DefaultResizerFactory.getInstance().getResizer(
new Dimension(imageToScale.getWidth(), imageToScale.getHeight()),
new Dimension(dWidth, dHeight))
BufferedImage scaledImage = new FixedSizeThumbnailMaker(
dWidth, dHeight, false, true).resizer(resizer).make(imageToScale);
It is as fast or slightly faster than one-step scaling with Graphics2d scoring an average of 6.9 sec in my benchmark.
Imgscalr v4.2
Uses progressive bicubic scaling. In the QUALITY setting it uses Campbell style algorithm with halving the dimensions every step while the ULTRA_QUALITY has finer steps, reducing the size every increment by 1/7 which generates generally softer images but minimizes the instances where only 1 iteration is used.
BufferedImage scaledImage = Scalr.resize(imageToScale, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, dWidth, dHeight, bufferedImageOpArray);
The major downside is performance. ULTRA_QUALITY is considerably slower than the other libs. Even QUALITY a bit slower than Thumbnailator's implementation. My simple benchmark resulted in 26.2 sec and 11.1 sec average respectively.
Morten Nobel's lib v0.8.6
Has also implementations for progressive scaling for all basic Graphics2d (bilinear, bicubic & nearest neighbor)
BufferedImage scaledImage = new MultiStepRescaleOp(dWidth, dHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR).filter(imageToScale, null);
A word on JDK Scaling Methods
Current jdk way to scale an image would be something like this
scaledImage = new BufferedImage(dWidth, dHeight, imageType);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
but most are very disappointed with the result of downscaling no matter what interpolation or other RenderHints are used. On the other hand upscaling seems to produce acceptable images (best would be bicubic). In previous JDK version (we talking 90s v1.1) Image.getScaledInstance() was introduced which provided good visual results with parameter SCALE_AREA_AVERAGING but you are discouraged to use it - read the full explanation here.
Thumbnailator is a library that was written to create high-quality thumbnails in a simple manner, and doing a batch conversion of existing images is one of its use cases.
Performing batch resizing
For example, to adapt your example using Thumbnailator, you should be able to achieve similar results with the following code:
File folder = new File("/Users/me/Desktop/images/");
Thumbnails.of(folder.listFiles())
.size(112, 75)
.outputFormat("jpg")
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
This will go ahead and takes all files in your images directory and proceed to process them one by one, try to resize them to fit in the dimensions of 112 x 75, and it will attempt to preserve the aspect ratio of the original image to prevent "warping" of the image.
Thumbnailator will go ahead and read all files, regardless of image types (as long as the Java Image IO supports the format, Thumbnailator will process it), perform the resizing operation and output the thumbnails as JPEG files, while tacking on a thumbnail. to the beginning of the file name.
The following is an illustration of how the file name of the original will be used in the file name of the thumbnail if the above code is executed.
images/fireworks.jpg -> images/thumbnail.fireworks.jpg
images/illustration.png -> images/thumbnail.illustration.png
images/mountains.jpg -> images/thumbnail.mountains.jpg
Generating high-quality thumbnails
In terms of image quality, as mentioned in Marco13's answer, the technique described by Chris Campbell in his The Perils of Image.getScaledInstance() is implemented in Thumbnailator, resulting in high-quality thumbnails without requiring any complicated processing.
The following is the thumbnail generated when resizing the fireworks image shown in the original question using Thumbnailator:
The above image was created with the following code:
BufferedImage thumbnail =
Thumbnails.of(new URL("http://i.stack.imgur.com/X0aPT.jpg"))
.height(75)
.asBufferedImage();
ImageIO.write(thumbnail, "png", new File("24745147.png"));
The code shows that it can also accept URLs as input, and that Thumbnailator is also capable of creating BufferedImages as well.
Disclaimer: I am the maintainer of the Thumbnailator library.
Given your input image, the method from the answer in the first link in the comments (kudos to Chris Campbell) produces one of the following thumbnails:
(The other one is the thumbnail that you created with MS Paint. It's hard to call one of them "better" than the other...)
EDIT: Just to point this out as well: The main problem with your original code was that you did not really scale the image in multiple steps. You just used a strange loop to "compute" the target size. The key point is that you actually perform the scaling in multiple steps.
Just for completeness, the MVCE
(Edit: I mentioned Chris Campbell and referred to the source via the comments, but to make this more clear here: The following is based on the article The Perils of Image.getScaledInstance() )
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
public class ResizeQuality
{
public static void main(String[] args) throws IOException
{
BufferedImage image = ImageIO.read(new File("X0aPT.jpg"));
BufferedImage scaled = getScaledInstance(
image, 51, 75, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
writeJPG(scaled, new FileOutputStream("X0aPT_tn.jpg"), 0.85f);
}
public static BufferedImage getScaledInstance(
BufferedImage img, int targetWidth,
int targetHeight, Object hint,
boolean higherQuality)
{
int type =
(img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality)
{
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
}
else
{
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do
{
if (higherQuality && w > targetWidth)
{
w /= 2;
if (w < targetWidth)
{
w = targetWidth;
}
}
if (higherQuality && h > targetHeight)
{
h /= 2;
if (h < targetHeight)
{
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
public static void writeJPG(
BufferedImage bufferedImage,
OutputStream outputStream,
float quality) throws IOException
{
Iterator<ImageWriter> iterator =
ImageIO.getImageWritersByFormatName("jpg");
ImageWriter imageWriter = iterator.next();
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(quality);
ImageOutputStream imageOutputStream =
new MemoryCacheImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);
IIOImage iioimage = new IIOImage(bufferedImage, null, null);
imageWriter.write(null, iioimage, imageWriteParam);
imageOutputStream.flush();
}
}
After days of research i would prefer javaxt.
use Thejavaxt.io.Image class has a constructor like:
public Image(java.awt.image.BufferedImage bufferedImage)
so you can do (another example):
javaxt.io.Image image = new javaxt.io.Image(bufferedImage);
image.setWidth(50);
image.setOutputQuality(1);
Here's the output:
We should not forget a TwelveMonkeys Library
It contains a really impressive filter collection.
Usage example:
BufferedImage input = ...; // Image to resample
int width, height = ...; // new width/height
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS);
BufferedImage output = resampler.filter(input, null);
Below are my own implementation of Progressive Scaling, without using any external library. Hope this help.
private static BufferedImage progressiveScaling(BufferedImage before, Integer longestSideLength) {
if (before != null) {
Integer w = before.getWidth();
Integer h = before.getHeight();
Double ratio = h > w ? longestSideLength.doubleValue() / h : longestSideLength.doubleValue() / w;
//Multi Step Rescale operation
//This technique is describen in Chris Campbellā€™s blog The Perils of Image.getScaledInstance(). As Chris mentions, when downscaling to something less than factor 0.5, you get the best result by doing multiple downscaling with a minimum factor of 0.5 (in other words: each scaling operation should scale to maximum half the size).
while (ratio < 0.5) {
BufferedImage tmp = scale(before, 0.5);
before = tmp;
w = before.getWidth();
h = before.getHeight();
ratio = h > w ? longestSideLength.doubleValue() / h : longestSideLength.doubleValue() / w;
}
BufferedImage after = scale(before, ratio);
return after;
}
return null;
}
private static BufferedImage scale(BufferedImage imageToScale, Double ratio) {
Integer dWidth = ((Double) (imageToScale.getWidth() * ratio)).intValue();
Integer dHeight = ((Double) (imageToScale.getHeight() * ratio)).intValue();
BufferedImage scaledImage = new BufferedImage(dWidth, dHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
return scaledImage;
}
The result seems to be better (than the result of your program), if you apply Gaussian blur before resizing:
This is the result I get, with sigma * (scale factor) = 0.3:
With ImageJ the code to do this is quite short:
import ij.IJ;
import ij.ImagePlus;
import ij.io.Opener;
import ij.process.ImageProcessor;
public class Resizer {
public static void main(String[] args) {
processPicture("X0aPT.jpg", "output.jpg", 0.0198, ImageProcessor.NONE, 0.3);
}
public static void processPicture(String inputFile, String outputFilePath, double scaleFactor, int interpolationMethod, double sigmaFactor) {
Opener opener = new Opener();
ImageProcessor ip = opener.openImage(inputFile).getProcessor();
ip.blurGaussian(sigmaFactor / scaleFactor);
ip.setInterpolationMethod(interpolationMethod);
ImageProcessor outputProcessor = ip.resize((int)(ip.getWidth() * scaleFactor), (int)(ip.getHeight()*scaleFactor));
IJ.saveAs(new ImagePlus("", outputProcessor), outputFilePath.substring(outputFilePath.lastIndexOf('.')+1), outputFilePath);
}
}
BTW: You only need ij-1.49d.jar (or equivalent for other version); there's no need to install ImageJ.

How do you work with packages? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Okay, I'm just a greenhorn here and I'm trying some various codes. Now this game GUI src I found have some image files inside a folder and its a necessity for the whole game to work.
I tried some methods, but I just can't understand how can I make the src connected to the folder. The program runs now but it only displays black screen because it can't connect to the images. Please, I need help.
What I just wanted is how can I make the program recognize the files I'm using as background images and such. The code line is there, but it displays an exception...
Am I still unclear? ._.
Well it goes like this:
package moon_lander;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
/**
* Actual game.
*
* #author www.gametutorial.net
*/
public class Game {
/**
* The space rocket with which player will have to land.
*/
private PlayerRocket playerRocket;
/**
* Landing area on which rocket will have to land.
*/
private LandingArea landingArea;
/**
* Game background image.
*/
private BufferedImage backgroundImg;
/**
* Red border of the frame. It is used when player crash the rocket.
*/
private BufferedImage redBorderImg;
public Game()
{
Framework.gameState = Framework.GameState.GAME_CONTENT_LOADING;
Thread threadForInitGame = new Thread() {
#Override
public void run(){
// Sets variables and objects for the game.
Initialize();
// Load game files (images, sounds, ...)
LoadContent();
Framework.gameState = Framework.GameState.PLAYING;
}
};
threadForInitGame.start();
}
/**
* Set variables and objects for the game.
*/
private void Initialize()
{
playerRocket = new PlayerRocket();
landingArea = new LandingArea();
}
/**
* Load game files - images, sounds, ...
*/
private void LoadContent()
{
try
{
URL backgroundImgUrl = this.getClass().getResource("/moon_lander/resources/images/background.jpg");
backgroundImg = ImageIO.read(backgroundImgUrl);
URL redBorderImgUrl = this.getClass().getResource("/moon_lander/resources/images/red_border.png");
redBorderImg = ImageIO.read(redBorderImgUrl);
}
catch (IOException ex) {
Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Restart game - reset some variables.
*/
public void RestartGame()
{
playerRocket.ResetPlayer();
}
/**
* Update game logic.
*
* #param gameTime gameTime of the game.
* #param mousePosition current mouse position.
*/
public void UpdateGame(long gameTime, Point mousePosition)
{
// Move the rocket
playerRocket.Update();
// Checks where the player rocket is. Is it still in the space or is it landed or crashed?
// First we check bottom y coordinate of the rocket if is it near the landing area.
if(playerRocket.y + playerRocket.rocketImgHeight - 10 > landingArea.y)
{
// Here we check if the rocket is over landing area.
if((playerRocket.x > landingArea.x) && (playerRocket.x < landingArea.x + landingArea.landingAreaImgWidth - playerRocket.rocketImgWidth))
{
// Here we check if the rocket speed isn't too high.
if(playerRocket.speedY <= playerRocket.topLandingSpeed)
playerRocket.landed = true;
else
playerRocket.crashed = true;
}
else
playerRocket.crashed = true;
Framework.gameState = Framework.GameState.GAMEOVER;
}
}
/**
* Draw the game to the screen.
*
* #param g2d Graphics2D
* #param mousePosition current mouse position.
*/
public void Draw(Graphics2D g2d, Point mousePosition)
{
g2d.drawImage(backgroundImg, 0, 0, Framework.frameWidth, Framework.frameHeight, null);
landingArea.Draw(g2d);
playerRocket.Draw(g2d);
}
/**
* Draw the game over screen.
*
* #param g2d Graphics2D
* #param mousePosition Current mouse position.
* #param gameTime Game time in nanoseconds.
*/
public void DrawGameOver(Graphics2D g2d, Point mousePosition, long gameTime)
{
Draw(g2d, mousePosition);
g2d.drawString("Press space or enter to restart.", Framework.frameWidth / 2 - 100, Framework.frameHeight / 3 + 70);
if(playerRocket.landed)
{
g2d.drawString("You have successfully landed!", Framework.frameWidth / 2 - 100, Framework.frameHeight / 3);
g2d.drawString("You have landed in " + gameTime / Framework.secInNanosec + " seconds.", Framework.frameWidth / 2 - 100, Framework.frameHeight / 3 + 20);
}
else
{
g2d.setColor(Color.red);
g2d.drawString("You have crashed the rocket!", Framework.frameWidth / 2 - 95, Framework.frameHeight / 3);
g2d.drawImage(redBorderImg, 0, 0, Framework.frameWidth, Framework.frameHeight, null);
}
}
}
And this is the Exception:
Exception in thread "Thread-2" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(ImageIO.java:1362)
at moon_lander.Framework.LoadContent(Framework.java:115)
at moon_lander.Framework.GameLoop(Framework.java:162)
at moon_lander.Framework.access$000(Framework.java:21)
at moon_lander.Framework$1.run(Framework.java:90)
Process completed.
How you load imagines doesn't have anything to do with packages.
Normally you find an image as a resource via class path. This can be arranged any way you wish.
I tried some methods, but I just can't understand how can I make the src connected to the folder.
Usually you build an application. When you run it, you use the build, not the src. i.e. you don't use the source when you run the program. Usually the images are copied with the same relative path you used in your source and this relative path is what you use to find and load your images.
I can't be more specific, as there is not enough detail in the questions such as what you directory structure is and which IDE or build system you are using.

How to convert 16 bit, tiff, Gray-Scale image into 32 bit ,tiff, Gray-Scale Image in java?

I m making DesktopApp in java with netbeans platform. In my app i used 16 bit, tiff, Gray-scale Image and processing on that image. Now, i want to make 32 bit, tiff, Gray-Scale image from using 16 bit, tiff, Gray-Scale image (or data of 16 bit image).So how can i convert 16 bit image into 32 bit image in java?
What you need to do is pass it through an image processor object and then calibrate it. Probably some thing like this :
import java.awt.*;
import java.awt.image.*;
import ij.*;
import ij.gui.*;
import ij.measure.*;
/** converting an ImagePlus object to a different type. */
public class ImageConverter {
private ImagePlus imp;
private int type;
private static boolean doScaling = true;
/** Construct an ImageConverter based on an ImagePlus object. */
public ImageConverter(ImagePlus imp) {
this.imp = imp;
type = imp.getType();
}
/** Convert your ImagePlus to 32-bit grayscale. */
public void convertToGray32() {
if (type==ImagePlus.GRAY32)
return;
if (!(type==ImagePlus.GRAY8||type==ImagePlus.GRAY16||type==ImagePlus.COLOR_RGB))
throw new IllegalArgumentException("Unsupported conversion");
ImageProcessor ip = imp.getProcessor();
imp.trimProcessor();
Calibration cal = imp.getCalibration();
imp.setProcessor(null, ip.convertToFloat());
imp.setCalibration(cal); //update calibration
}
/** Set true to scale to 0-255 when converting short to byte or float
to byte and to 0-65535 when converting float to short. */
public static void setDoScaling(boolean scaleConversions) {
doScaling = scaleConversions;
IJ.register(ImageConverter.class);
}
/** Returns true if scaling is enabled. */
public static boolean getDoScaling() {
return doScaling;
}
}
This way your calibrated image gets set to 32 bit, what ever the input may be . Remember to import the right jars though .
If your TIFF is loaded as a BufferedImage, you can reduce it this way:
BufferedImage convert(BufferedImage image) {
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel colorModel = new ComponentColorModel(
colorSpace, false, false, Transparency.OPAQUE,
DataBuffer.TYPE_USHORT);
BufferedImageOp converter = new ColorConvertOp(colorSpace, null);
BufferedImage newImage =
converter.createCompatibleDestImage(image, colorModel);
converter.filter(image, newImage);
return newImage;
}

getRGB() result doesn't match result received from MS Paint Eyedropper

When i use getRGB() and after that get pixel color Red or Green or Blue component (it does not matter because they equal in Gray image) and compare result with MS Paint Eyedropper result, its different things.
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
public class Separator {
BufferedImage inputImg;
private int _inpupImgWidth;
private int _inpupImgHeight;
public Separator(){
try {
inputImg = ImageIO.read(new File("inputImg.bmp"));
_inpupImgWidth = inputImg.getWidth();
_inpupImgHeight = inputImg.getHeight();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(getGrayPixelData(60, 44));
try {
ImageIO.write(inputImg, "BMP", new File("outputImg.bmp"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void getGrayPixelData(int x, int y){
Color myColor = new Color(inputImg.getRGB(x, y));
System.out.println("Red: " + myColor.getRed());
System.out.println("Green: " + myColor.getGreen());
System.out.println("Blue: " + myColor.getBlue());
}
public static void main(String[] args) {
new Separator();
System.out.println("The End");
}
}
here is the link of image i use http://postimage.org/image/t6tvlv941/
The image is in greyscale mode.
How you convert a greyscale value into R, G, B is quite arbitrary.
A naive way would be to assign an identical greyscale value to each of the R, G and B components.
A more sophisticated way would be to use some transformation that takes into account the eye's sensitivity to these different components, or which takes account of the profile of your monitor or other display device.
So clearly, Java and your program are using different transformations. But in either case, the precise R, G and B values are essentially meaningless: the original data is not in R, G, B format.

Categories

Resources