Unable to down scale gray scale image - java

I have an grayscale image with dimension 256*256.I am trying to downscale it to 128*128.
I am taking an average of two pixel and writing it to the ouput file.
class Start {
public static void main (String [] args) throws IOException {
File input= new File("E:\\input.raw");
File output= new File("E:\\output.raw");
new Start().resizeImage(input,output,2);
}
public void resizeImage(File input, File output, int downScaleFactor) throws IOException {
byte[] fileContent= Files.readAllBytes(input.toPath());
FileOutputStream stream= new FileOutputStream(output);
int i=0;
int j=1;
int result=0;
for(;i<fileContent.length;i++)
{
if(j>1){
// skip the records.
j--;
continue;
}
else {
result = fileContent[i];
for (; j < downScaleFactor; j++) {
result = ((result + fileContent[i + j]) / 2);
}
j++;
stream.write( fileContent[i]);
}
}
stream.close();
}
}
Above code run successfully , I can see the size of output file size is decreased but when I try to convert
output file (raw file) to jpg online (https://www.iloveimg.com/convert-to-jpg/raw-to-jpg) it is giving me an error saying that file is corrupt.
I have converted input file from same online tool it is working perfectly. Something is wrong with my code which is creating corrupt file.
How can I correct it ?
P.S I can not use any library which directly downscale an image .

Your code is not handling image resizing.
See how-to-resize-images-in-java.
Which, i am copying a simple version here:
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageResizer {
public static void resize(String inputImagePath,
String outputImagePath, int scaledWidth, int scaledHeight)
throws IOException {
// reads input image
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// extracts extension of output file
String formatName = outputImagePath.substring(outputImagePath
.lastIndexOf(".") + 1);
// writes to output file
ImageIO.write(outputImage, formatName, new File(outputImagePath));
}
public static void resize(String inputImagePath,
String outputImagePath, double percent) throws IOException {
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
int scaledWidth = (int) (inputImage.getWidth() * percent);
int scaledHeight = (int) (inputImage.getHeight() * percent);
resize(inputImagePath, outputImagePath, scaledWidth, scaledHeight);
}
public static void main(String[] args) {
String inputImagePath = "resources/snoopy.jpg";
String outputImagePath1 = "target/Puppy_Fixed.jpg";
String outputImagePath2 = "target/Puppy_Smaller.jpg";
String outputImagePath3 = "target/Puppy_Bigger.jpg";
try {
// resize to a fixed width (not proportional)
int scaledWidth = 1024;
int scaledHeight = 768;
ImageResizer.resize(inputImagePath, outputImagePath1, scaledWidth, scaledHeight);
// resize smaller by 50%
double percent = 0.5;
ImageResizer.resize(inputImagePath, outputImagePath2, percent);
// resize bigger by 50%
percent = 1.5;
ImageResizer.resize(inputImagePath, outputImagePath3, percent);
} catch (IOException ex) {
System.out.println("Error resizing the image.");
ex.printStackTrace();
}
}
}

Related

Given a 200x200 RGB PNG file , extract the 2 least significant bits of each pixel data to create a new 200x200 image saved to disk

Here is the code, I am getting black image.
package example;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class imageCopy {
public static void main(String[] args) {
BufferedImage img = null;
File f = null;
try {
f = new File("E:\\unnamed.png");
img = ImageIO.read(f);
}catch(Exception e) {
e.printStackTrace();
}
int width = img.getWidth();
int height = img.getHeight();
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
int p = img.getRGB(j, i);
int k = p << -2 >>> -2;
img.setRGB(j, i, k);
}
}
try {
f = new File("E:\\Output.png");
ImageIO.write(img, "png", f);
}catch(Exception e) {
e.printStackTrace();
}
}
}
png

Getting transparent images when writing an image

I was using openCv to apply filters and ran into a problem.
What I did in this specific code was first try and get a grayscale image but preserve the color channels it works fine but when I write to file using Image IO I find the alpha has been altered. So I checked for BGRA and ABGR colorspaces but it still does not work and gives me a transparent image.
public static BufferedImage sepia(BufferedImage image,int intensity)
{
Mat imageMat = bufferedToMat(image);
int sepiaDepth = 20;
int width = image.getWidth();
int height = image.getHeight();
Mat grayScaleMat = new Mat(imageMat.height(),imageMat.width(),CvType.CV_8UC4);
imageMat.copyTo(grayScaleMat);
// double[] test = imageMat.get(0, 0);
// System.out.println(test[0]+" "+test[1]+" "+test[2]+" "+test[3]);
for(int i=0;i<grayScaleMat.cols();i++)
{
for(int j=0;j<grayScaleMat.rows();j++)
{
//can be optimised
double[] data = grayScaleMat.get(j, i);
//System.out.println(data.length);
double blue = data[0];
double green = data[1];
double red = data[2];
//System.out.println(red+" "+blue+" "+green);
double gray = (red + blue + green)/3.0;
//data[0] = gray;
data[0] = gray;
data[1] = gray;
data[2] = gray;
grayScaleMat.put(j, i, data);
}
}
return (Utility.matToBuffered(grayScaleMat));
}
//Only Testing Remove Later
public static void main(String[] args)
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
int beta = 25;
String imagePath = "/home/arjun/Pictures/Lenna.png";
BufferedImage image = null;
try{
image = ImageIO.read(new File(imagePath));
}catch(IOException e)
{
e.printStackTrace();
}
int x = image.getType();
System.out.println(x);
BufferedImage output = sepia(image,beta);
int y = output.getType();
System.out.println(y);
File outputfile = new File("/home/arjun/Pictures/sepia2.png");
try{
ImageIO.write(output, "png", outputfile);
}catch(IOException e)
{
e.printStackTrace();
}
}
And the Buffered and Mat conversions here
public static Mat bufferedToMat(BufferedImage image)
{
byte[] pixels = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
Mat imageMat = new Mat(image.getHeight(),image.getWidth(),CvType.CV_8UC4);
imageMat.put(0, 0, pixels);
return imageMat;
}
public static BufferedImage matToBuffered(Mat imageMat)
{
BufferedImage out;
byte[] data = new byte[imageMat.cols()*imageMat.rows()*(int)imageMat.elemSize()];
imageMat.get(0, 0,data);
int type = BufferedImage.TYPE_3BYTE_BGR;
if(imageMat.channels() == 1)
{
type = BufferedImage.TYPE_BYTE_GRAY;
}
else if(imageMat.channels() == 3)
{
type = BufferedImage.TYPE_3BYTE_BGR;
}
else if(imageMat.channels() == 4)
{
type = BufferedImage.TYPE_4BYTE_ABGR;
}
out = new BufferedImage(imageMat.cols(),imageMat.rows(),type);
out.getRaster().setDataElements(0,0,imageMat.cols(),imageMat.rows(),data);
return out;
}
Input Image:
Output Image:

Create JavaFX Image from PGM or TIFF as fast as possible

I'm capturing images from a scanner device with java. The input format ist PGM or TIFF. I have to show up live results in the user interface. Actually I'm using ImageJ to read the source input stream as tiff, because ImageJ can also handle incomplete streams. After that the ImagePlus object is converted into a BufferedImage and finally into a JavaFX Image.
ImagePlus imagePlus = new Opener().openTiff(inputStream, "");
BufferedImage bufferedImage = imagePlus.getBufferedImage();
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
This is very slow. I need a faster way to create the JavaFX Image from the PGM or TIFF stream. It seems that JavaFX has actually no support for this formats and I don't found a usefull library.
Any idea?
Edit #1
I've decided to optimze the image capturing in two steps. At first I need a better state control when updating the image in the ui. This is actually done and works fine. Now update requests are dropped, when the conversion thread is busy. The second step is to use a self implemented pnm reader (based on the suggested implementation) and update the image in my model incrementally... until the scan process is complete. This should reduce the required recources when loading an image from the device. I need to change some parts of my architecture to make this happen.
Thanks # all for comments.
btw: java 8 lambdas are great :)
Edit #2
My plan doesn't work, because of JavaFX's thread test :(
Currently I have a WritableImage in my backend wich should be filled step by step with data. This image instance is set to an ObjectProperty that is finally bound to the ImageView. Since the WritableImage is connected to the ImageView it's impossible to fill it with data by using a PixelWriter. This causes an exception.
java.lang.IllegalStateException: Not on FX application thread; currentThread = pool-2-thread-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:210) ~[jfxrt.jar:na]
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:393) ~[jfxrt.jar:na]
at javafx.scene.Scene.addToDirtyList(Scene.java:529) ~[jfxrt.jar:na]
at javafx.scene.Node.addToSceneDirtyList(Node.java:417) ~[jfxrt.jar:na]
at javafx.scene.Node.impl_markDirty(Node.java:408) ~[jfxrt.jar:na]
at javafx.scene.Node.transformedBoundsChanged(Node.java:3789) ~[jfxrt.jar:na]
at javafx.scene.Node.impl_geomChanged(Node.java:3753) ~[jfxrt.jar:na]
at javafx.scene.image.ImageView.access$700(ImageView.java:141) ~[jfxrt.jar:na]
at javafx.scene.image.ImageView$3.invalidated(ImageView.java:285) ~[jfxrt.jar:na]
at javafx.beans.WeakInvalidationListener.invalidated(WeakInvalidationListener.java:83) ~[jfxrt.jar:na]
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:135) ~[jfxrt.jar:na]
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80) ~[jfxrt.jar:na]
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74) ~[jfxrt.jar:na]
at javafx.scene.image.Image$ObjectPropertyImpl.fireValueChangedEvent(Image.java:568) ~[jfxrt.jar:na]
at javafx.scene.image.Image.pixelsDirty(Image.java:542) ~[jfxrt.jar:na]
at javafx.scene.image.WritableImage$2.setArgb(WritableImage.java:170) ~[jfxrt.jar:na]
at javafx.scene.image.WritableImage$2.setColor(WritableImage.java:179) ~[jfxrt.jar:na]
My workaround is to create a copy of the image, but I don't like this solution. Maybe it's possible to prevent the automatic change notification and do this manually?
As an experiment, and to learn some JavaFX, I decided to see for myself how hard it would be to implement what I suggested in the comment above... :-)
The PGM reading is adapted from my PNM ImageIO plugin, and it seems to work okay. Read times is reported to be around 70-90 ms for my 640x480 sample images (feel free to send me some more samples if you have!).
An uncompressed TIFF should be readable in roughly the same time, although the TIFF IFD structure is more complex to parse than the very simple PGM header. TIFF compression will add some decompression overhead, depending on compression type and settings.
import java.io.DataInputStream;
import java.io.IOException;
import javax.imageio.IIOException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class PGMTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
Label root = new Label();
Image image;
long start = System.currentTimeMillis();
DataInputStream input = new DataInputStream(getClass().getResourceAsStream("/house.l.pgm"));
try {
image = readImage(input);
} finally {
input.close();
}
System.out.printf("Read image (%f x %f) in: %d ms\n", image.getWidth(), image.getHeight(), System.currentTimeMillis() - start);
root.setGraphic(new ImageView(image));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private Image readImage(final DataInputStream input) throws IOException {
// First parse PGM header
PNMHeader header = PNMHeader.parse(input);
WritableImage image = new WritableImage(header.getWidth(), header.getHeight());
PixelWriter pixelWriter = image.getPixelWriter();
int maxSample = header.getMaxSample(); // Needed for normalization
// PixelFormat<ByteBuffer> gray = PixelFormat.createByteIndexedInstance(createGrayColorMap());
byte[] rowBuffer = new byte[header.getWidth()];
for (int y = 0; y < header.getHeight(); y++) {
input.readFully(rowBuffer); // Read one row
// normalize(rowBuffer, maxSample);
// pixelWriter.setPixels(0, y, width, 1, gray, rowBuffer, 0, width); // Gives weird NPE for me...
// As I can't get setPixels to work, we'll set pixels directly
// Performance is probably worse than setPixels, but it seems "ok"-ish
for (int x = 0; x < rowBuffer.length; x++) {
int gray = (rowBuffer[x] & 0xff) * 255 / maxSample; // Normalize [0...255]
pixelWriter.setArgb(x, y, 0xff000000 | gray << 16 | gray << 8 | gray);
}
}
return image;
}
private int[] createGrayColorMap() {
int[] colors = new int[256];
for (int i = 0; i < colors.length; i++) {
colors[i] = 0xff000000 | i << 16 | i << 8 | i;
}
return colors;
}
/**
* Simplified version of my PNMHeader parser
*/
private static class PNMHeader {
public static final int PGM = 'P' << 8 | '5';
private final int width;
private final int height;
private final int maxSample;
private PNMHeader(final int width, final int height, final int maxSample) {
this.width = width;
this.height = height;
this.maxSample = maxSample;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getMaxSample() {
return maxSample;
}
public static PNMHeader parse(final DataInputStream input) throws IOException {
short type = input.readShort();
if (type != PGM) {
throw new IIOException(String.format("Only PGM binay (P5) supported for now: %04x", type));
}
int width = 0;
int height = 0;
int maxSample = 0;
while (width == 0 || height == 0 || maxSample == 0) {
String line = input.readLine(); // For PGM I guess this is ok...
if (line == null) {
throw new IIOException("Unexpeced end of stream");
}
if (line.indexOf('#') >= 0) {
// Skip comment
continue;
}
line = line.trim();
if (!line.isEmpty()) {
// We have tokens...
String[] tokens = line.split("\\s");
for (String token : tokens) {
if (width == 0) {
width = Integer.parseInt(token);
} else if (height == 0) {
height = Integer.parseInt(token);
} else if (maxSample == 0) {
maxSample = Integer.parseInt(token);
} else {
throw new IIOException("Unknown PBM token: " + token);
}
}
}
}
return new PNMHeader(width, height, maxSample);
}
}
}
I should probably add that I wrote, compiled and ran the above code on Java 7, using JavaFX 2.2.
Update: Using a predefined PixelFormat I was able to use PixelWriter.setPixels and thus further reduce read times to 45-60 ms for the same 640x480 sample images. Here's a new version of readImage (the code is otherwise the same):
private Image readImage(final DataInputStream input) throws IOException {
// First parse PGM header
PNMHeader header = PNMHeader.parse(input);
int width = header.getWidth();
int height = header.getHeight();
WritableImage image = new WritableImage(width, height);
PixelWriter pixelWriter = image.getPixelWriter();
int maxSample = header.getMaxSample(); // Needed to normalize
PixelFormat<ByteBuffer> format = PixelFormat.getByteRgbInstance();
byte[] rowBuffer = new byte[width * 3]; // * 3 to hold RGB
for (int y = 0; y < height; y++) {
input.readFully(rowBuffer, 0, width); // Read one row
// Expand gray to RGB triplets
for (int i = width - 1; i > 0; i--) {
byte gray = (byte) ((rowBuffer[i] & 0xff) * 255 / maxSample); // Normalize [0...255];
rowBuffer[i * 3 ] = gray;
rowBuffer[i * 3 + 1] = gray;
rowBuffer[i * 3 + 2] = gray;
}
pixelWriter.setPixels(0, y, width, 1, format, rowBuffer, 0, width * 3);
}
return image;
}
Download jai_imageio.jar and include it in your project.
Code to convert tiff images into fx readable images is below:
String pathToImage = "D:\\ABC.TIF";
ImageInputStream is;
try {
is = ImageIO.createImageInputStream(new File(pathToImage)); //read tiff using imageIO (JAI component)
if (is == null || is.length() == 0) {
System.out.println("Image is null");
}
Iterator<ImageReader> iterator = ImageIO.getImageReaders(is);
if (iterator == null || !iterator.hasNext()) {
throw new IOException("Image file format not supported by ImageIO: " + pathToImage);
}
ImageReader reader = (ImageReader) iterator.next();
reader.setInput(is);
int nbPages = reader.getNumImages(true);
BufferedImage bf = reader.read(0); //1st page of tiff file
BufferedImage bf1 = reader.read(1); //2nd page of tiff file
WritableImage wr = null;
WritableImage wr1 = null;
if (bf != null) {
wr= SwingFXUtils.toFXImage(bf, null); //convert bufferedImage (awt) into Writable Image(fx)
}
if (bf != null) {
wr1= SwingFXUtils.toFXImage(bf1, null); //convert bufferedImage (awt) into Writable Image(fx)
}
img_view1.setImage(wr);
img_view2.setImage(wr1);
} catch (FileNotFoundException ex) {
Logger.getLogger(Image_WindowController.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Image_WindowController.class.getName()).log(Level.SEVERE, null, ex);
}
This is my first answer on Stack Overflow. Hope it helps!

Resizing image in java - what do i need to change?

I was just wondering how I would resize an image in java?
This is for an assignment where I have to locate an image and then save it as a .png file that is half the resolution as the original.
This is my code so far;
enter code here
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class saveimage {
public static void main(String[] args) // IOException
{
String sourceLocation;
sourceLocation = (args[0]);
int width = 963;
int height = 640;
int halfwidth = width / 2;
int halfheight = height / 2;
BufferedImage image1 = null;
BufferedImage imagehalf = null;
File readfile = null;
try {
readfile = new File(sourceLocation);
image1 = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
image1 = ImageIO.read(readfile);
imagehalf = new BufferedImage(halfwidth, halfheight,
BufferedImage.TYPE_INT_ARGB);
imagehalf = ImageIO.read(readfile);
System.out.println("reading complete");
}
catch (IOException e) {
System.out.println("Error: " + e);
}
try {
readfile = new File("LOCATION OF FILE");
ImageIO.write(image1, "png", readfile);
System.out.println("Writing complete");
} catch (IOException fail1) {
System.out.println("Error:" + fail1);
}
try {
readfile = new File "LOCATION OF OUTPUT");
ImageIO.write(imagehalf, "png", readfile);
System.out.println("writing half is complete");
} catch (IOException fail2) {
System.out.println("Error:" + fail2);
}
}
}
As you can see I have just halved the integer values at the start as I thought it would have just halved the output size but it didn't...is there anything i am doing wrong?
The next part of the assignment is that i need to tile the image but i am just doing one step at a time :)
Thanks in advance
AFAIK imagehalf = ImageIO.read(readfile); would just read the image file and create a BufferedImage of the original size. What you're basically doing is create a fresh BufferedImage and then replace it with one read from the file, which can't work.
What you'd have to do instead: read the original image, create a half sized BufferedImage and draw the original image to the half sized one.
Use the getGraphics() method and call drawImage(...) with the necessary parameters on the returned Graphics object.
Note that you could use BufferedImage#getScaledInstance(...) but you might want to start using the Graphics object to be prepared for your future assignments.
Hey feel free to use this code i posted below:
public ImageIcon resizeImage(ImageIcon imageIcon, int width, int height, boolean max)
{
Image image = imageIcon.getImage();
Image newimg = image.getScaledInstance(-1, height, java.awt.Image.SCALE_SMOOTH);
int width1 = newimg.getWidth(null);
if ((max && width1 > width) || (!max && width1 < width))
newimg = image.getScaledInstance(width, -1, java.awt.Image.SCALE_SMOOTH);
return new ImageIcon(newimg);
}
I actually don't know what the boolean max does i found it on the internet somewhere.
You need to get a graphics context for the resizedImage and then draw the original image into it with the dimensions you want. Depending on how it looks you may want to look at Java's RenderingHints as well.
BufferedImage imageHalf = new BufferedImage(halfwidth, halfheight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = imageHalf.createGraphics();
g.drawImage(fullImage, 0, 0, halfwidth, halfheight, null);
g.dispose();

how to convert image from coordinate x,y values in java?

In my project we need spot the difference among a set of images,so at first i tried it for three images and I have written code to differentiate between three images based on RGB values.I have stored coordinate values from this values i need to get a image.
import java.io.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
class spe
{
public static void main(String args[])
throws IOException
{
long start = System.currentTimeMillis();
int q=0;
File file1 = new File("filename.txt");
FileWriter fw = new FileWriter(file1.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
File file= new File("2010.png");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth(null);
int height = image.getHeight(null);
int[][] clr= new int[width][height];
File files= new File("2011.png");
BufferedImage images = ImageIO.read(files);
int widthe = images.getWidth(null);
int heighte = images.getHeight(null);
File file2=new File("2009.png");
BufferedImage image2=ImageIO.read(file2);
int wid=image2.getWidth(null);
int heig=image2.getHeight(null);
int[][] colo=new int[wid][heig];
int[][] clre= new int[widthe][heighte];
int smw=0;
int smh=0;
int p=0;
// bw.write("hai");
//CALUCLATING THE SMALLEST VALUE AMONG WIDTH AND HEIGHT
if(width>widthe)
{
smw =widthe;
}
else
{
smw=width;
}
if(height>heighte)
{
smh=heighte;
}
else
{
smh=height;
}
//CHECKING NUMBER OF PIXELS SIMILARITY
for(int a=0;a<smw;a++)
{
for(int b=0;b<smh;b++)
{
clre[a][b]=images.getRGB(a,b);
clr[a][b]=image.getRGB(a,b);
colo[a][b]=image2.getRGB(a,b);
if(clr[a][b]==clre[a][b] && colo[a][b]==clre[a][b])
{
p=p+1;
bw.write("\t");
bw.write(Integer.toString(a));
bw.write("\t");
bw.write(Integer.toString(b));
bw.write("\n");
System.out.println(a+"\t"+b);
}
else
q=q+1;
}
}
float w,h=0;
if(width>widthe)
{
w=width;
}
else
{
w=widthe;
}
if(height>heighte)
{
h = height;
}
else
{
h = heighte;
}
float s = (smw*smh);
//CALUCLATING PERCENTAGE
float x =(100*p)/s;
System.out.println("THE PERCENTAGE SIMILARITY IS APPROXIMATELY ="+x+"%");
long stop = System.currentTimeMillis();
System.out.println("TIME TAKEN IS ="+(stop-start));
System.out.println("NO OF PIXEL GETS VARIED:="+q);
System.out.println("NO OF PIXEL GETS MATCHED:="+p);
}
}

Categories

Resources