What I need to do is I have a input image file and I need to change it as user's parameters. For example if user wants to make it %30 darker, first I get all pixels with their RGB values and store them in an 2D array. Sample array given below.
114 121 140 //Pixel 1
114 121 140 //Pixel 2
114 121 140 //Pixel 3
.
.
.
50 57 83 //Pixel 2073601
After that I overwrite that RGB values (in our case if RGB values are 10:10:10, new values will be 7:7:7). Everything from that point is ok. But now I'm facing some difficulties about creating my output.jpg file using my new array of information. When I run my function, it does not creates any output.jpg file. Here is my function.
public static void createFinalImage(int height, int width, String[][] rgbArray, String outputFile) {
BufferedImage img;
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
File f;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
String[] data = rgbArray[y][x].split(" ");
int red = Integer.parseInt(data[0]);
int green = Integer.parseInt(data[1]);
int blue = Integer.parseInt(data[2]);
int rgb = new Color(red,green,blue).getRGB();
img.setRGB(x,y,rgb);
}
}
try
{
f = new File(outputFile);
ImageIO.write(img, "jpg", f);
}
catch(IOException e)
{
System.out.println("Error: " + e);
}
}
I cant understand what is the problem and why I cant get darker image using this function. (I know there is always easier and basic ways to do it but this is an multithreading assignment and I must do it like I explained.) If anyone help me, I would be appreciated.
The ImageIO.write(...) methods return a boolean indicating whether or not there is a plugin installed that can write the image in the given format. It's good practice to check this value. While there is always a JPEG plugin installed, in recent versions of Java the JPEG plugin no longer supports images with alpha channel. Most other software don't support 4 channel RGBA JPEGs anyway, so it's not a big loss...
All you need is to change BufferedImage.TYPE_INT_ARGB to a type without alpha, like BufferedImage.TYPE_INT_RGB or TYPE_3BYTE_BGR, and things will work. You don't seem to use the alpha channel anyway.
The important changes:
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Manipulate pixels
}
}
try {
File f = new File(outputFile);
if (!ImageIO.write(img, "JPEG", f)) {
System.err.println("No plugin to write " + img + " in JPEG format to " + f);
}
}
catch (IOException e) {
System.out.println("Error: " + e);
}
As #HaraldK said, in my function I was using BufferedImage.TYPE_INT_ARGB as parameter. But since I have no alpha value, I just changed it as BufferedImage.TYPE_INT_RGB. Modified function given below and it works as normal.
public static void createFinalImage(int height, int width, String[][] rgbArray, String outputFile) {
BufferedImage img;
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
File f;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
String[] data = rgbArray[y][x].split(" ");
int red = Integer.parseInt(data[0]);
int green = Integer.parseInt(data[1]);
int blue = Integer.parseInt(data[2]);
int rgb = new Color(red,green,blue).getRGB();
img.setRGB(x,y,rgb);
}
}
try
{
f = new File(outputFile);
ImageIO.write(img, "jpg", f);
}
catch(IOException e)
{
System.out.println("Error: " + e);
}
}
Related
This question already has answers here:
reading black/white image in java with TYPE_USHORT_GRAY
(2 answers)
Closed 2 years ago.
I have tried to grayscale a already black-white-gray picture and it become black.
When I try to grayscale a picture with Java, I do like this:
// This turns the image data to grayscale and return the data
private static RealMatrix imageData(File picture) {
try {
BufferedImage image = ImageIO.read(picture);
int width = image.getWidth();
int height = image.getHeight();
RealMatrix data = MatrixUtils.createRealMatrix(height * width, 1);
// Convert to grayscale
int countRows = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Turn image to grayscale
int p = image.getRGB(x, y);
int r = (p >> 16) & 0xff;
int g = (p >> 8) & 0xff;
int b = p & 0xff;
// calculate average and save
int avg = (r + g + b) / 3;
data.setEntry(countRows, 0, avg);
countRows++;
}
}
return data;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
The problem what I see is that p is an 32-bit value and I only want 8-bit value. Even if the picture is already grayscaled, the p value is already a 32-bit value. That cause trouble for me.
So if I grayscale a gray picture, it will become black. Or at least darker.
And I want 0..255 values of p, which is a 32-bit integer value.
Do you have any suggestions how to read pictures as they where 8-bit?
It's for image classification.
Summarize:
I need help to get each pixels from a picture in 0..255 format.
One way is to gray scale it, but how can I verify if the picture is already gray scaled?
Update:
I have tried to read a picture as it was 8-bit values. It works. Then I try to save the picture with the same values. The picture becomes very dark.
I have a matlab example I want to show.
First I read my picture:
image = imread("subject01.normal");
And then I save the picture.
imwrite(uint8(image), "theSameImage.gif")
If I try with a minimal Java code snipped for reading an image.
private static void imageData(File picture) {
try {
BufferedImage image = ImageIO.read(picture);
int width = image.getWidth();
int height = image.getHeight();
DataBuffer buffer = image.getRaster().getDataBuffer();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int p = buffer.getElem(x + y * width);
image.setRGB(x, y, p);
}
}
File output = new File(picture.getName());
ImageIO.write(image, "gif", output);
return data;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I will get this picture:
So even if there is a marked answer in this question, it's still not going to help you.
You mentioned that the image you're reading is a grayscale image, and that getRGB returns values like 23241 and 23551.
That means your image uses a CS_GRAY ColorSpace, not an RGB color space. You can confirm this by calling getType(), which would return TYPE_USHORT_GRAY.
That means that your p value is a gray-level in range 0 - 65535. Since you want the result to be a double in range 0 - 255, you need to calculate:
double avg = p * 255.0 / 65535.0;
Unless you're 100% sure the input image will always be grayscale, you should check the type in the code and handle the p value accordingly.
I am new to programming and I'm currently working on a program that rotates an image to the right and upside down. I was able to get the upside down method working but not the rotate to the right (90 degrees clockwise). It keeps giving me an out of bounds error, and I'm not sure why as I have looked at other examples. Any help would be appreciated.
Here's is the method that I'm working on:
public Image rotateRight()
{
Image right = new Image (this);
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int width = right.img.getWidth();
int height = right.img.getHeight();
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
}
return right;
}
Here's the rest of the code:
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class Image {
private BufferedImage img = null;
int width;
int height;
private Image()
{
}
public Image (int w, int h)
{
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB );
width = w;
height = h;
}
public Image (Image anotherImg)
{
width = anotherImg.img.getWidth();
height = anotherImg.img.getHeight();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
this.img.setRGB(j,i,anotherImg.img.getRGB(j,i)) ;
}
}
public String toString()
{
return "Width of Image:" +width+"\nHeight of Image:"+height;
}
public Image (String filename)
{
try
{
img = ImageIO.read(new File(filename));
width = img.getWidth();
height = img.getHeight();
}
catch (IOException e)
{
System.out.println(e);
}
}
public void save(String filename, String extension)
{
try
{
File outputfile = new File(filename);
ImageIO.write(img, extension, outputfile);
}
catch (IOException e)
{
System.out.println(e);
}
}
public Image copy()
{
Image copiedImage = new Image(this);
return copiedImage;
}
Here's Main:
public static void main (String args[])
{
Image srcimg = new Image("apple.jpg");
System.out.println(srcimg);
Image copy = srcimg.copy();
copy.save("apple-copy.jpg", "jpg");
Image copy2 = srcimg.copy();
Image right = copy2.rotateRight();
right.save("apple-rotateRight.jpg", "jpg");
}
The reason you are getting an ArrayIndexOutOfBoundsException when rotating your image is as stated. Something is out of bounds. It could be either your i variable that has exceeded its bounds or your j variable that has exceeded its bounds and this is generally easy to test for by just adding a print statement within your for loop and checking which one of the two values is out of bounds. It is good practice to try to resolve these problems yourself as you will start learning what causes these and where the problem lies.
Anyways enough of my rambling. The problem that you seem to have is that you are trying to turn the image without changing the size of the image.
You are creating a new Image with the same width and height parameters as the original
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );
However when you want to rotate an image by 90 degrees you actually want to flip the width and height parameters. If you think about it, it makes sense when you rotate an image by 90 degrees the width will become the height and the height will become the width.
So your problem is here:
this.img.setRGB(height-j-1,i,right.img.getRGB(i,j));
In your case the bounds for the x parameter in the setRGB function is from 0 to the WIDTH of your image and the y parameter is from 0 to the HEIGHT of your image. Therefore because your height variable is different from your width. If for example your WIDTH is 200 and your HEIGHT is 100. When you put this in to the function the greatest value for the x parameter will be:
'100 - 199 - 1 = -100' which is clearly out of bounds. However if we change your code to.
img = new BufferedImage(height, width, BufferedImage.TYPE_INT_RGB );
now when we do the same thing as before where we get the maximum possible value.
WIDTH = 100, HEIGHT = 200;
'200 - 99 - 1 = 100' which is inside the bounds
i have 2D array( it's only 1 -0 values) but its type is int[][].
Now i want to convert that array into image ( binary image black and white). But i couldn't find suitable answer for my question. I have searched google and this website. Can anyone help me??
I have tried this following code, but it
String path = "C:\\Users\\Cyrus\\Desktop\\test.jpg";
BufferedImage image = new BufferedImage(b.length, b[0].length, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < b.length; x++) { // b is my 2D array
for (int y = 0; y < b[x].length; y++) {
image.setRGB(x, y, b[x][y]);
}
}
File ImageFile = new File(path);
try {
ImageIO.write(image, "jpg", ImageFile);
} catch (IOException e) {
e.printStackTrace();
}
// after i modify my code
String path = "C:\\Users\\Cyrus\\Desktop\\test.jpg";
BufferedImage image = new BufferedImage(a.length, a[0].length, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < a.length; x++) {
for (int y = 0; y < a[x].length; y++) {
int value ;
if(a[x][y]==1) value = new Color(255,255,255).getRGB();
else value = new Color(0,0,0).getRGB();
image.setRGB(x, y, value);
}
}
File ImageFile = new File(path);
try {
ImageIO.write(image, "jpg", ImageFile);
} catch (IOException e) {
e.printStackTrace();
}
But it return wrong image
Can you be more specific on the result you get? Did it throw some exceptions? or the program finished normally but didn't produce the result you want?
You should notice that here you want to work with binary image, then is there any specific reason to choose JPG? As I know, JPG is not a native representation of color triplet RGB (as bmp for example). a jpeg file is a "container" of data sequence, in which there are a lot of information in its header (EXIF, QT,...), marked by markers. To deal with pixel value "directly" as in your array, the data sequence in jpg file must be "decoded", then after you play it the image, the main image data will be "encoded" again to be jpg stream.
To play directly with pixel value, I suggest you work with other formats (such as TGA, png,...)
I am working with a LayeredPane that contains two images, one on each layer. I have been working on a method that obtains the image positions (based on the label positions the images are in) and then save the bottom image (lower one from within the layeredPane) and also the top one if it is at all covering the bottom image (may only be a part of the image), however I have been having some trouble with this and I'm a bit unsure on how to get it working properly.
I have been stuck working on this for quite a while now so any help with my existing code or thoughts on how I should approach this another way would be a big help for me.
Thanks in advance.
public void saveImageLayering(BufferedImage topImg,BufferedImage bottomImg, JLabel topLabel, JLabel bottomLabel) {
int width = bottomImg.getWidth();
int height = bottomImg.getHeight();
Point bottomPoint = new Point();
Point topPoint = new Point();
bottomPoint = bottomLabel.getLocation();
topPoint = topLabel.getLocation();
System.out.println("image x coordinate " + bottomPoint.x);
System.out.println("image y coordinate " + bottomPoint.y);
//arrays to store the bottom image
int bottomRedImgArray[][] = new int[width][height];
int bottomGreenImgArray[][] = new int[width][height];
int bottomBlueImgArray[][] = new int[width][height];
//arrays to store the top image
int topRedImgArray[][] = new int[width][height];
int topGreenImgArray[][] = new int[width][height];
int topBlueImgArray[][] = new int[width][height];
//loop through the bottom image and get all pixels rgb values
for(int i = bottomPoint.x; i < width; i++){
for(int j = bottomPoint.y; j < height; j++){
//set pixel equal to the RGB value of the pixel being looked at
pixel = new Color(bottomImg.getRGB(i, j));
//contain the RGB values in the respective RGB arrays
bottomRedImgArray[i][j] = pixel.getRed();
bottomGreenImgArray[i][j] = pixel.getGreen();
bottomBlueImgArray[i][j] = pixel.getBlue();
}
}
//create new image the same size as old
BufferedImage newBottomImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//set values within the 2d array to the new image
for (int x1 = 0; x1 < width; x1++){
for (int y1 = 0; y1 < height; y1++){
//putting values back into buffered image
int newPixel = (int) bottomRedImgArray[x1][y1];
newPixel = (newPixel << 8) + (int) bottomGreenImgArray[x1][y1];
newPixel = (newPixel << 8) + (int) bottomBlueImgArray[x1][y1];
newBottomImage.setRGB(x1, y1, newPixel);
}
}
//create rectangle around bottom image to check if coordinates of top in inside and save only the ones that are
Rectangle rec = new Rectangle(bottomPoint.x, bottomPoint.y, bottomImg.getWidth(), bottomImg.getHeight());
//loop through the top image and get all pixels rgb values
for(int i = bottomPoint.x; i < bottomImg.getWidth(); i++){
for(int j = bottomPoint.y; j < bottomImg.getHeight(); j++){
//if top image is inside lower image then getRGB values
if (rec.contains(topPoint)) { //___________________________________________________________doesnt contain any..
if (firstPointFound == true) {
//set pixel equal to the RGB value of the pixel being looked at
pixel = new Color(topImg.getRGB(i, j));
//contain the RGB values in the respective RGB arrays
topRedImgArray[i][j] = pixel.getRed();
topGreenImgArray[i][j] = pixel.getGreen();
topBlueImgArray[i][j] = pixel.getBlue();
} else {
firstPoint = new Point(i, j);
firstPointFound = true;
}
}
}
}
//create new image the same size as old
BufferedImage newTopImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//set values within the 2d array to the new image
for (int x1 = 0; x1 < topImg.getWidth(); x1++){
for (int y1 = 0; y1 < topImg.getHeight(); y1++){
//putting values back into buffered image
int newPixel = (int) topRedImgArray[x1][y1];
newPixel = (newPixel << 8) + (int) topGreenImgArray[x1][y1];
newPixel = (newPixel << 8) + (int) topBlueImgArray[x1][y1];
newTopImage.setRGB(x1, y1, newPixel);
}
}
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//uses the Graphics.drawImage() to place them on top of each other
Graphics g = newImage.getGraphics();
g.drawImage(newBottomImage, bottomPoint.x, bottomPoint.y, null);
g.drawImage(newTopImage, firstPoint.x, firstPoint.y, null);
try {
//then save as image once all in correct order
File outputfile = new File("saved_Layered_Image.png");
ImageIO.write(newImage, "png", outputfile);
JOptionPane.showMessageDialog(null, "New image saved successfully");
} catch (IOException e) {
e.printStackTrace();
}
}
I'm not really sure why you're messing around with the pixels, however, the idea is relatively simple
Basically, you want to create a third "merged" image which is the same size as the bottomImage. From there, you simply want to paint the bottomImage onto the merged image at 0x0.
Then you need to calculate the distance that the topImage is away from bottomImage's location and paint it at that point.
BufferedImage merged = new BufferedImage(bottomImg.getWidth(), bottomImg.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = master.createGraphics();
g2d.drawImage(bottomImg, 0, 0, this);
int x = topPoint .x - bottomPoint .x;
int y = topPoint .y - bottomPoint .y;
g2d.drawImage(topImg, x, y, this);
g2d.dispose();
Using this basic idea, I was able to produce these...
What I'm trying to do is to compute 2D DCT of an image in Java and then save the result back to file.
Read file:
coverImage = readImg(coverPath);
private BufferedImage readImg(String path) {
BufferedImage destination = null;
try {
destination = ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
return destination;
}
Convert to float array:
cover = convertToFloatArray(coverImage);
private float[] convertToFloatArray(BufferedImage source) {
securedImage = (WritableRaster) source.getData();
float[] floatArray = new float[source.getHeight() * source.getWidth()];
floatArray = securedImage.getPixels(0, 0, source.getWidth(), source.getHeight(), floatArray);
return floatArray;
}
Run the DCT:
runDCT(cover, coverImage.getHeight(), coverImage.getWidth());
private void runDCT(float[] floatArray, int rows, int cols) {
dct = new FloatDCT_2D(rows, cols);
dct.forward(floatArray, false);
securedImage.setPixels(0, 0, cols, rows, floatArray);
}
And then save it as image:
convertDctToImage(securedImage, coverImage.getHeight(), coverImage.getWidth());
private void convertDctToImage(WritableRaster secured, int rows, int cols) {
coverImage.setData(secured);
File file = new File(securedPath);
try {
ImageIO.write(coverImage, "png", file);
} catch (IOException ex) {
Logger.getLogger(DCT2D.class.getName()).log(Level.SEVERE, null, ex);
}
}
But what I get is: http://kyle.pl/up/2012/05/29/dct_stack.png
Can anyone tell me what I'm doing wrong? Or maybe I don't understand something here?
This is a piece of code, that works for me:
//reading image
BufferedImage image = javax.imageio.ImageIO.read(new File(filename));
//width * 2, because DoubleFFT_2D needs 2x more space - for Real and Imaginary parts of complex numbers
double[][] brightness = new double[img.getHeight()][img.getWidth() * 2];
//convert colored image to grayscale (brightness of each pixel)
for ( int y = 0; y < image.getHeight(); y++ ) {
raster.getDataElements( 0, y, image.getWidth(), 1, dataElements );
for ( int x = 0; x < image.getWidth(); x++ ) {
//notice x and y swapped - it's JTransforms format of arrays
brightness[y][x] = brightnessRGB(dataElements[x]);
}
}
//do FT (not FFT, because FFT is only* for images with width and height being 2**N)
//DoubleFFT_2D writes data to the same array - to brightness
new DoubleFFT_2D(img.getHeight(), img.getWidth()).realForwardFull(brightness);
//visualising frequency domain
BufferedImage fd = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
outRaster = fd.getRaster();
for ( int y = 0; y < img.getHeight(); y++ ) {
for ( int x = 0; x < img.getWidth(); x++ ) {
//we calculate complex number vector length (sqrt(Re**2 + Im**2)). But these lengths are to big to
//fit in 0 - 255 scale of colors. So I divide it on 223. Instead of "223", you may want to choose
//another factor, wich would make you frequency domain look best
int power = (int) (Math.sqrt(Math.pow(brightness[y][2 * x], 2) + Math.pow(brightness[y][2 * x + 1], 2)) / 223);
power = power > 255 ? 255 : power;
//draw a grayscale color on image "fd"
fd.setRGB(x, y, new Color(c, c, c).getRGB());
}
}
draw(fd);
Resulting image should look like big black space in the middle and white spots in all four corners. Usually people visualise FD so, that zero frequency appears in the center of the image. So, if you need classical FD (one, that looks like star for reallife images), you need to upgrade "fd.setRGB(x, y..." a bit:
int w2 = img.getWidth() / 2;
int h2 = img.getHeight() / 2;
int newX = x + w2 >= img.getWidth() ? x - w2 : x + w2;
int newY = y + h2 >= img.getHeight() ? y - h2 : y + h2;
fd.setRGB(newX, newY, new Color(power, power, power).getRGB());
brightnessRGB and draw methods for the lazy:
public static int brightnessRGB(int rgb) {
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
return (r+g+b)/3;
}
private static void draw(BufferedImage img) {
JLabel picLabel = new JLabel(new ImageIcon(img));
JPanel jPanelMain = new JPanel();
jPanelMain.add(picLabel);
JFrame jFrame = new JFrame();
jFrame.add(jPanelMain);
jFrame.pack();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
}
I know, I'm a bit late, but I just did all that for my program. So, let it be here for those, who'll get here from googling.