I want to try up scale image up to 3 times.
For example,
Up Scaled Image
I am using this library for Image Resizing.
The following code snipped does the trick,
public static BufferedImage getScaledSampledImage(BufferedImage img,
int targetWidth, int targetHeight, boolean higherQuality) {
ResampleOp resampleOp = new ResampleOp(targetWidth, targetHeight);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage rescaledImage = resampleOp.filter(img, null);
return rescaledImage;
}
You can see there a resized images are lower quality. I want that I can up scale images at least 3 times than the original image without quality lost.
Is it Pposible? Should I need to change existing library ?
Thanks
The fact is that when you scale an image up, it has to create data where there was none. (Roughly speaking). To do this, you have to interpolate between the existing pixels to fill in the new ones. You may be able to get better results by trying different kinds of interpolation - but the best method will be different for different kinds of images.
Since your sample image is just squares, nearest-neighbour interpolation will likely give you the best results. If you are scaling up an image of scenery or maybe a portrait you'll need a more clever algorithm.
The result will rarely look perfect, and it's best to start with a larger image if possible!
Take a look here to get an understanding of the problem. http://en.wikipedia.org/wiki/Image_scaling#Scaling_methods
Related
So here is the problem: I am loading an image which is of unknown resolution. I need to scale it to 500px width to fit within my UI, preserving aspect ratio. The image quality must be good as i need to use it later, specifically to calculate an angle between two objects within the image.
So far i have tried the following:
In the following examples, we have an existing UI element ImageView imageView;
Method one: using scale on load in JavaFX image constructor:
public void setImage(String path){
Image image = new Image(path, 550, 412, true, true);
imageView.setImage(image);
}
This method achieves the required scaling, but lacks the quality required for an accurate calculation of angle later on.
Method two: using ImageView scaling to scale the displayed image:
public void setImage(String path){
Image image = new Image(path);
imageView.setFitWidth(550);
imageView.setPreserveRatio(true);
imageView.setImage(image);
}
This achieves the required quality and scaling, but the image contained within the view is not actually scaled, which means the calculations done later down the line are using an image not representative of the one being displayed.
Is there a way i can alter either of these solutions to work better or is there a better approach i can take? thank you.
You will have to use,
imageView.setSmooth(true);
to achieve better quality image after scaling.
EDIT:
It is because, the two methods are essentially different. The first method loads a bad quality image in the first place (with lesser pixels). One thing you can try is, to use AWT Image class for loading the image, using ImageIO, and call scaledImage = image.getScaledInstance(width, height). Then use something like (pseudo code):
create bufferedImage of scaled size
bufferedImage.createGraphics()
.drawImage(scaledImage, 0, 0, null)
to get scaled AWT Image. Then use SwingFXUtils to convert to image for FX application. This whole thing can probably be done in 3 lines of code by chaining the methods. I was able to achieve better quality this way in one of my previous projects.
I was trying to do really the same functionality of resizing images like in MS Word.
I want to resize BufferedImage but I’m losing some information during process of resizing.
I tried to implement two approaches, but both produced same result.
Before any resizing:
Picture after few resize actions in my application:
First approach:
image = Thumbnails.of(image).size(w,h).asBufferedImage();
Second approach:
image = toBufferedImage(image.getScaledInstance(w, h, Image.SCALE_SMOOTH));
image is instance of BufferedImage, w is new width of image and h is new hight of image
Any idea, what I’m doing wrong?
You're constantly losing information from your image after each resizing attempt. If you want solution (like in MS Word) you have to keep somewhere original image but show only resized copy.
The best solution would be creating an object to store original image and making resized copy on demand. You can improve quality of this solution adding simple cache so you don't actually generate another resized copy of your image for every request but only if your application demands image with different height or width than last time.
I hope I helped you a bit.
I'm making a small game in Java, and it uses a pixel-graphics style, with many sprites 16x16 or 32x32 pixels. However, when I rotate them, I do not want "jaggies" along the side, so I used the RenderingHint
RenderingHint.KEY_INTERPOLATION
RenderingHint.VALUE_INTERPOLATION_BILINEAR
Unfortunately, because many of the images used are very small (16x16, 32x32) the resulting image is completely unusable. Output:
http://imgur.com/a/roRh4
As you can see, the small graphics are blurred. This is the intended effect for large images, but for small images, it is very bad.
One solution is to increase the resolution of all my graphics, while keeping the "blocky" effect. That would be a pain, so is there another way to tweak the interpolation?
Thank you guys so much.
Upscale your tiny images and use that instead:
BufferedImage tiny = ImageIO.read(new File("..."));
BufferedImage bigger = new BufferedImage(tiny.getWidth()*10, tiny.getHeight()*10, tiny.getType());
Graphics2D g = bigger.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.drawImage(tiny, 0, 0, bigger.getWidth(), bigger.getHeight(), 0, 0, tiny.getWidth(), tiny.getHeight(), null);
Replace the 10 scaling factor by the smallest value that gives acceptable results.
Do the rest of your rendering with high quality interpolation.
I am looking for the simplest (and still non-problematic) way to resize a BufferedImage in Java.
In some answer to a question, the user coobird suggested the following solution, in his words (very slightly changed by me):
**
The Graphics object has a method to draw an Image while also performing a resize operation:
Graphics.drawImage(Image, int, int, int, int, ImageObserver)
method can be used to specify the location along with the size of the image when drawing.
So, we could use a piece of code like this:
BufferedImage originalImage = // .. created somehow
BufferedImage newImage = new BufferedImage(SMALL_SIZE, SMALL_SIZE, BufferedImage.TYPE_INT_RGB);
Graphics g = newImage.createGraphics();
g.drawImage(originalImage, 0, 0, SMALL_SIZE, SMALL_SIZE, null);
g.dispose();
This will take originalImage and draw it on the newImage with the width and height of SMALL_SIZE.
**
This solution seems rather simple. I have two questions about it:
Will it also work (using the exact same code), if I want to resize an image to a larger size, not only a smaller one?
Are there any problems with this solution?
If there is a better way to do this, please suggest it.
Thanks
The major problem with single step scaling is they don't generally produce quality output, as they focus on taking the original and squeezing into a smaller space, usually by dropping out a lot of pixel information (different algorithms do different things, so I'm generalizing)
Will drawGraphics scale up and down, yes, will it do it efficiently or produce a quality output? These will come down to implementation, generally speaking, most of the scaling algorithms used by default are focused on speed. You can effect these in a little way, but generally, unless you're scaling over a small range, the quality generally suffers (from my experience).
You can take a look at The Perils of Image.getScaledInstance() for more details and discussions on the topic.
Generally, what is generally recommend is to either use a dedicated library, like imgscalr, which, from the ten minutes I've played with it, does a pretty good job or perform a stepped scale.
A stepped scale basically steps the image up or down by the power of 2 until it reaches it's desired size. Remember, scaling up is nothing more then taking a pixel and enlarging it a little, so quality will always be an issue if you scale up to a very large size.
For example...
Quality of Image after resize very low -- Java
Scale the ImageIcon automatically to label size
Java: JPanel background not scaling
Remember, any scaling is generally an expensive operation (based on the original and target size of the image), so it is generally best to try and do those operations out side of the paint process and in the background where possible.
There is also the question whether you want to maintain the aspect ratio of the image? Based on you example, the image would be scaled in a square manner (stretched to meet to the requirements of the target size), this is generally not desired. You can pass -1 to either the width or height parameter and the underlying algorithm will maintain the aspect ratio of the original image or you could simply take control and make more determinations over whether you want to fill or fit the image to a target area, for example...
Java: maintaining aspect ratio of JPanel background image
In general, I avoid using drawImage or getScaledInstance most of the time (if your scaling only over a small range or want to do a low quality, fast scale, these can work) and rely more on things like fit/fill a target area and stepped scaling. The reason for using my own methods simply comes down to not always being allowed to use outside libraries. Nice not to have to re-invent the wheel where you can
It will enlarge the original if you set the parameters so. But: you should use some smart algorithm which preserves edges because simply enlarging an image will make it blurry and will result in worse perceived quality.
No problems. Theoretically this can even be hardware-accelerated on certain platforms.
I want to scale a large 1920x1080 buffered image into smaller 200x200 size using progressive bicubic approach.
I start with the 1024x768 and scale down to nearly 80% of original and then want to store this temp image somewhere in some format so that in next iteration i perform again the scaling to 80% on this image and continuing the procedure till i obtain 200x200 image which i finally display on my JFrame.
WHAT IS THE METHOD OR WAY TO STORE THIS TEMP IMAGE?OR CAN ANYONE SUGGEST A SIMPLE APPROACH TO IMPLEMENT THIS PROGRESSIVE BICUBIC SCALING.
The expected code looks similar to this(though it needs various modifications ,i need just the way to store temp image)
int sizew=1920,sizeh=1080;
int deltaw = (int)(0.20 *1920);
int deltah= (int)(0.20*1920);
while(sizew>200&&sizeh>200)
{
sizew=sizew-deltaw;
sizeh=sizeh-deltah;
if(sizew<200||sizeh<200)
{
sizew=200;
sizeh=200;
temp=new BufferedImage(sizew,sizeh,BufferedImage.TYPE_INT_RGB);
//but using this how would i give reference to my original 1920x1080 image or temp image???
break;
}
else
temp=new BufferedImage(sizew,sizeh,BufferedImage.TYPE_INT_RGB);
}
No easy task; here's an outline of the brute-force approach:
Tile the image into manageable pieces using an available approach suited to the source, for example
Java getSubImage(), seen here.
Ossim, designed for geodetic data, but usable for imagery.
Resample the tiles as warranted by the intended use, for example
AffineTransform, seen here, using TYPE_NEAREST_NEIGHBOR.
ImageJ, which may be scripted.
Reassemble the tiles; the approach depends on the destination.