In CSV semicolon file I have saved grayscale values of pixels from my image. I want to import this values into my program as BufferedImage class object. I can but result image is more faded.
There are steps:
public static BufferedImage loadImageFromCSV(File file) throws Exception {
BufferedImage bufferedImage = null;
//load CSV file data to memory
List<String> linesFromCsvFile = CSVUtils.parseCSV(file);
//calculate width and height
int width = getWidthFromCSVLines(linesFromCsvFile);
int height = getHeightFromCSVLines(linesFromCsvFile);
//get values form CSV lines
Integer[][] pixels = asTwoDimensionalArray(linesFromCsvFile);
//generate image
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x) {
int rgb = pixels[y][x] | (pixels[y][x] << 8) | (pixels[y][x] << 16);
bufferedImage.setRGB(x, y, rgb );
}
}
return bufferedImage;
}
Below on the left side grayscale image and on the right side imported image to my program:
CSV file looks ok: https://filebin.net/9mp7nifqu045b48e
Please help
Related
I have a requirement to create a BMP image (black & white) from the hex string created through Excel Macro. I have next to zero experience working on this and need some help. Below is the Hex String, output image example of the hex, and little code snippet that I am trying :
String:
001E00FE07FE3FE03C003C003F801FFE03FE007E3E003FE03FFC0FFE0E3E0FFE3FFC3FE03E0000000FF83FFC3FFE300630063006380E180C00003E003FE03FFC0FFE0E3E0FFE3FFC3FE03E00000000003FFE3FFE3FFE01F807F01FC03FFE3FFE3FFE0000000E000E000E3FFE3FFE3FFE000E000E000E0000
Image to be created of the above string:
Code Snippet :
public void createImageFromHex() throws IOException {
String hex="001E00FE07FE3FE03C003C003F801FFE03FE007E3E003FE03FFC0FFE0E3E0FFE3FFC3FE03E0000000FF83FFC3FFE300630063006380E180C00003E003FE03FFC0FFE0E3E0FFE3FFC3FE03E00000000003FFE3FFE3FFE01F807F01FC03FFE3FFE3FFE0000000E000E000E3FFE3FFE3FFE000E000E000E0000";
byte[] imageInByte= ByteString.decodeHex(hex).toByteArray();
for (byte b : imageInByte) {
System.out.println("Byte : " + b);
}
InputStream in = new ByteArrayInputStream(imageInByte);
Font font = new Font("Arial", Font.PLAIN, 12);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.BITMASK);
Graphics2D g2d = img.createGraphics();
FontMetrics fm = g2d.getFontMetrics(font);
g2d.dispose();
int width = fm.stringWidth(hex);
int height = fm.getHeight();
img = new BufferedImage(width, height, BufferedImage.BITMASK);
g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.BLACK);
g2d.setFont(font);
g2d.drawString(hex, 0, fm.getAscent());
g2d.dispose();
try {
ImageIO.write(img, "bmp", new File("Hex.bmp"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
The clue here is the format of the hex/binary data. You need to know this from some kind of specification, from the device/software/service that produces the hex string. From the data and sample image, I believe #tgdavies has correctly reverse-engineered it.
Each pixel is one bit. The white pixels are stored as 0, black as 1. Each column of pixels is stored as two bytes. Each column is stored bottom-up.
Assuming that format is correct, it's quite trivial to write code to convert it:
public void createImageFromHex() throws IOException {
// Assumption: hex contains a bitmap format, where
// * each pair of bytes is one *column*
// * each column is stored "bottom-up" (LSB is bottom pixel, MSB is top pixel)
String hex = "001E00FE07FE3FE03C003C003F801FFE03FE007E3E003FE03FFC0FFE0E3E0FFE3FFC3FE03E0000000FF83FFC3FFE300630063006380E180C00003E003FE03FFC0FFE0E3E0FFE3FFC3FE03E00000000003FFE3FFE3FFE01F807F01FC03FFE3FFE3FFE0000000E000E000E3FFE3FFE3FFE000E000E000E0000";
// (result is 120 bytes)
byte[] imageInByte = ByteString.decodeHex(hex).toByteArray();
int height = 16; // 16 according to sample
int width = imageInByte.length / 2; // 60 according to the sample, but as we know each column is 16 bits or 2 bytes, we can calculate it
// Create a BufferedImage of correct type: For a bitmap this is TYPE_BYTE_BINARY
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
// Loop over pixels and insert black or white
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int pos = height * x + y;
int bytePos = pos / 8;
int bitPos = 7 - (pos % 8);
byte value = imageInByte[bytePos];
int bit = (value >> bitPos) & 1;
// Each pixel is either all white (0) or all black (1)
int rgb = bit != 0 ? 0x000000 : 0xFFFFFF;
img.setRGB(x, height - 1 - y, rgb);
}
}
// Write to BMP format
File output = new File("Hex.bmp");
if (!ImageIO.write(img, "bmp", output)) {
System.err.printf("Could not write %s in BMP format...%n", output.getAbsolutePath());
}
}
Result file:
I have a program that is supposed to take the RGB values of an image and then multiply them by some constants, and then draw the new image on a JPanel. The problem is that if my image is over a certain height, specifically over 187 pixels, the new colored image is different than an image with a height of less than 187px.
The JPanel shows this: example.
Notice how the longer recolored image is different than the shorter one. I'm sure that the shorter image's colors are correct, and I have no idea how it's getting messed up.
public class RecolorImage extends JPanel {
public static int scale = 3;
public static BufferedImage walk, walkRecolored;
public static BufferedImage shortWalk, shortWalkRecolored;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(200*scale, 400*scale);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RecolorImage());
walk = ImageLoader.loadImage("/playerWalk.png");
walkRecolored = recolor(walk);
shortWalk = ImageLoader.loadImage("/playerWalkShort.png");
shortWalkRecolored = recolor(shortWalk);
frame.setVisible(true);
}
#Override
public void paint(Graphics graphics) {
Graphics2D g = (Graphics2D) graphics;
g.scale(scale, scale);
g.drawImage(walk, 10, 10, null);
g.drawImage(walkRecolored, 40, 10, null);
g.drawImage(shortWalk, 70, 10, null);
g.drawImage(shortWalkRecolored, 100, 10, null);
}
The recolor method:
public static BufferedImage recolor(BufferedImage image) {
BufferedImage outputImage = deepCopy(image);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
Color c = new Color(rgb);
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
r *= 0.791;
g *= 0.590;
b *= 0.513;
int newRGB = (rgb & 0xff000000) | (r << 16) | (g << 8) | b;
outputImage.setRGB(x, y, newRGB);
}
}
return outputImage;
}
How I load the images and make deep copies:
public static BufferedImage loadImage(String path) {
try {
return ImageIO.read(ImageLoader.class.getResource(path));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static BufferedImage deepCopy(BufferedImage image) {
ColorModel colorModel = image.getColorModel();
boolean isAlphaPremultiplied = colorModel.isAlphaPremultiplied();
WritableRaster raster = image.copyData(null);
return new BufferedImage(colorModel, raster, isAlphaPremultiplied, null);
}
My original images: the tall image and short image. Thanks for any help!
Your source images have different color models:
the short image uses 4 bytes per pixel (RGB and alpha)
the tall image uses 1 byte per pixel (index into a palette of 256 colors)
Your recolored images use the same color model as the source images (thanks to the deepCopy method), therefore the recolored image for the tall image also uses the same color palette as the source image, meaning that it cannot contain all the colors you want.
Since your recoloring code overwrites each pixel of the output image anyway the deep copy operation is unnecessary. Instead you would better create a full color image as target image like this:
public static BufferedImage recolor(BufferedImage image) {
BufferedImage outputImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
//... code as before
}
Currently working on Image manipulation in Java
I have the byte array(PPM) of size 921600 (640*480*3)
byte[] image; // PPM
BufferedImage image = ImageIO.read(new ByteArrayInputStream(image));
image is null.
Tried with ImageMagic and JAI libraries. But it does not help me.
Is it possible to get the RGB components from byte array and convert it to JPG file.
Any help is appreciated.
Below is the Code (which will convert PPM(byte array to Buffered image and you can save buffered image to the file)
// Method Call
BufferedImage image = ppm(width, height, 255, byte[]);
//Method Definition
static public BufferedImage ppm(int width, int height, int maxcolval, byte[] data){
if(maxcolval<256){
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
int r,g,b,k=0,pixel;
if(maxcolval==255){ // don't scale
for(int y=0;y<height;y++){
for(int x=0;(x<width)&&((k+3)<data.length);x++){
r=data[k++] & 0xFF;
g=data[k++] & 0xFF;
b=data[k++] & 0xFF;
pixel=0xFF000000+(r<<16)+(g<<8)+b;
image.setRGB(x,y,pixel);
}
}
}
else{
for(int y=0;y<height;y++){
for(int x=0;(x<width)&&((k+3)<data.length);x++){
r=data[k++] & 0xFF;r=((r*255)+(maxcolval>>1))/maxcolval; // scale to 0..255 range
g=data[k++] & 0xFF;g=((g*255)+(maxcolval>>1))/maxcolval;
b=data[k++] & 0xFF;b=((b*255)+(maxcolval>>1))/maxcolval;
pixel=0xFF000000+(r<<16)+(g<<8)+b;
image.setRGB(x,y,pixel);
}
}
}
return image;
}
else{
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
int r,g,b,k=0,pixel;
for(int y=0;y<height;y++){
for(int x=0;(x<width)&&((k+6)<data.length);x++){
r=(data[k++] & 0xFF)|((data[k++] & 0xFF)<<8);r=((r*255)+(maxcolval>>1))/maxcolval; // scale to 0..255 range
g=(data[k++] & 0xFF)|((data[k++] & 0xFF)<<8);g=((g*255)+(maxcolval>>1))/maxcolval;
b=(data[k++] & 0xFF)|((data[k++] & 0xFF)<<8);b=((b*255)+(maxcolval>>1))/maxcolval;
pixel=0xFF000000+(r<<16)+(g<<8)+b;
image.setRGB(x,y,pixel);
}
}
return image;
}
}
You can use a WritableRaster to set the pixels in the image for you:
For a grayscale image, you will have a byte array like this:
byte[] arr = new byte[width * height];
To make an image, use:
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
img.getRaster().setDataElements(0, 0, width, height, arr);
For a color image, you will have an array like this:
byte[] arr = new byte[width * height * 3];
So, to make an image, use:
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
img.getRaster().setDataElements(0, 0, width, height, arr);
You may need to mess this the TYPE in the first line. See here to choose which type your image is.
I am currently trying to read in an image pixel by pixel and change each colored pixel to the rgb value of (100,100,100). For whatever reason when I check the values of each pixel one the image is saved it has all the colored pixels as (46,46,46) instead.
Here is the original image
After running my program this is the image it gives to me
Here is the code
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Cmaps {
public static void main(String[] args){
File originalImage = new File("C:\\Users\\Me\\Desktop\\0005.bmp");
BufferedImage img = null;
try{
img = ImageIO.read(originalImage);
for(int i = 0; i < img.getHeight(); i++){
for(int j = 0; j < img.getWidth(); j++){
//get the rgb color of the image and store it
Color c = new Color(img.getRGB(i, j));
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
//if the pixel is white then leave it alone
if((r == 255) && (g == 255) && (b == 255)){
img.setRGB(i, j, c.getRGB());
continue;
}
//set the colored pixel to 100,100,100
r = 100;// red component 0...255
g = 100;// green component 0...255
b = 100;// blue component 0...255
int col = (r << 16) | (g << 8) | b;
img.setRGB(i, j, col);
}
}
File f = new File("C:\\Users\\Me\\Desktop\\2\\1.png");
try {
ImageIO.write(img, "PNG", f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e){
e.printStackTrace();
}
}
}
I have no clue why it doesn't set the pixels to the expected rgb value. I eventually want to be able to basically increment the rgb color as I move down rows and columns in the x and y so what the final image will look like is it will start off dark in the top left corner and then have a fade out effect as you get from that side to the bottom right corner.
Okay, based on the comments:
If the BufferedImage has an IndexColorModel (palette based color model), using setRGB to set a pixel to an arbitrary RGB value will not work. Instead, the color will be looked up, and the pixel will get the color that is considered the closest match in the palette.
Formats like BMP, GIF and PNG may all use IndexColorModel when read using ImageIO.
To convert the image to "true color" (either DirectColorModel or ComponentColorModel in Java will do), you can use:
BufferedImage img; // your original palette image
int w = img.getWidth();
int h = img.getHeight();
BufferedImage trueColor = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = trueColor.createGraphics();
try {
g.drawImage(img, 0, 0, null);
}
finally {
g.dispose();
}
img = trueColor;
After this, getRGB(x, y) should return what you specify, using setRGB(x, y, argb).
I'm converting a image to gray scale in Java with the following code:
BufferedImage originalImage = ImageIO.read(new File("/home/david/input.bmp"));
BufferedImage grayImage = new BufferedImage(originalImage.getWidth()
, originalImage.getHeight()
, BufferedImage.TYPE_BYTE_GRAY);
ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp colorConvert = new ColorConvertOp(gray, null);
colorConvert.filter(originalImage, grayImage);
ImageIO.write(grayImage, "bmp", new File("/home/david/output_java.bmp"));
That seems to work, but the problem is that the output image is very different from the gray scale image generated by gimp (see examples below).
Can I control someway how is the image generated?
How I can make the result more similar to the gimp result?
Original image:
Gray scale image generated in Java:
Gray scale image generated in Gimp (Image -> Mode -> Grayscale):
BTW: I have a bunch of images coming from ffmpeg (with gray option) and they are like Gimp images so because of that I want my image in that way.
Finally I've wrote GrayscaleFilter class implementing BufferedImageOp interface.
I've followed this really good guide about Java image processing.
This is the relevant code fragment:
public class GrayscaleFilter extends AbstractFilter
{
public final static double[] METHOD_AVERAGE = {1.0/3.0, 1.0/3.0, 1.0/3.0};
public final static double[] METHOD_GIMP_LUMINOSITY = {0.21, 0.71, 0.07};
public GrayscaleFilter(final double[] rgb)
{
this(rgb[0], rgb[1], rgb[2]);
}
public BufferedImage filter(BufferedImage src, BufferedImage dest)
{
if (src.getType() == BufferedImage.TYPE_BYTE_GRAY)
{
dest = src;
return dest;
}
if (dest == null)
dest = createCompatibleDestImage(src, null);
final int width = src.getWidth();
final int height = src.getHeight();
int[] inPixels = new int[width * height];
GraphicsUtilities.getPixels(src, 0, 0, width, height, inPixels);
byte[] outPixels = doFilter(inPixels);
GraphicsUtilities.setPixels(dest, 0, 0, width, height, outPixels);
return dest;
}
private byte[] doFilter(int[] inputPixels)
{
int red, green, blue;
int i = 0;
byte[] outPixels = new byte[inputPixels.length];
for(int pixel : inputPixels)
{
// Obtengo valores originales
red = (pixel >> 16) & 0xFF;
green = (pixel >> 8) & 0xFF;
blue = pixel & 0xFF;
// Calculo valores nuevos
outPixels[i++] = (byte)(
red * red_part +
green * green_part +
blue * blue_part
);
}
return outPixels;
}
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM)
{
return new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
}
}
Find out the conversion formula used by Gimp. It probably takes some human color perception into account, while the Java implementation is mathematical (R+G+B)/ 3.