For my project, I'm able to print textures on objects. As soon I use nicer textures that use a color palette higher than 256 it will turn black or invisible...
Is anyone able to help me with this issue? Right now this is my code to transfer the .png into a useable texture:
public static Background getIndexedImage(int id, File file) throws IOException {
BufferedImage image = ImageIO.read(file);
List<Integer> paletteList = new LinkedList<>();
paletteList.add(0);
int width = image.getWidth();
int height = image.getHeight();
byte[] pixels = new byte[width * height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int rgb = image.getRGB(x, y);
int red = rgb >> 16 & 0xff;
int green = rgb >> 8 & 0xff;
int blue = rgb & 0xff;
int alpha = rgb & 0xff;
rgb = red << 16 | green << 8 | blue;
if (alpha == 255) {
rgb = 0;
}
int index = paletteList.indexOf(rgb);
if (index == -1) {
if (paletteList.size() < 256) {
index = paletteList.size();
paletteList.add(rgb);
} else {
throw new IllegalArgumentException("The target image has more than 255 color in the palette "+id);
}
}
pixels[x + y * width] = (byte) index;
}
}
int[] palette = new int[paletteList.size()];
final AtomicInteger index = new AtomicInteger(0);
for (int pallet = 0; pallet < paletteList.size(); pallet++) {
palette[index.getAndIncrement()] = paletteList.get(pallet);
}
return new Background(width, height, palette, pixels);
}
Related
I'm using JavaFX and I have a 16bit grayscale image that I'm able to show with the following code:
public Image createNewImageFromArrayPixels(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
int[] buffer = from2DArrayTo1DArray(pixels);
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY), //we have grayscale images
new int[]{16}, //bit depth: 16 bit per pixel
false,
false,
Transparency.OPAQUE,
DataBuffer.TYPE_INT); //every pixel has an integer intensity
WritableRaster raster = colorModel.createCompatibleWritableRaster(height, width);
DataBufferInt buff = (DataBufferInt) raster.getDataBuffer();
int[] bufferData = buff.getData();
System.arraycopy(buffer, 0, bufferData, 0, (buffer.length < bufferData.length ? buffer.length : bufferData.length));
BufferedImage bm = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
Now I want to transform it in a 48bit RGB image (16bit per channel), but I can't understand how.
At the moment I'm able to create a RGB 24bit image (8 bit per channel) by taking the int value of a pixel from the grayscale image and building manually the bytes that will compose the pixels with the following code:
private Image createRGBImageFromGrayPixels(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
BufferedImage bm = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int converted = from16to8(pixels[y][x]);
System.out.println("original " + pixels[y][x] + " = " + converted + " = " + from8to16(converted));
int rgb = converted;
rgb = (rgb << 8) + converted;
rgb = (rgb << 8) + converted;
bm.setRGB(x, y, rgb);
}
}
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
private int from16to8(int value) {
int originalStart = 0;
int originalEnd = 65535;
int newStart = 0;
int newEnd = 255;
double scale = (double)(newEnd - newStart) / (originalEnd - originalStart);
double res = newStart + ((value - originalStart) * scale);
System.out.println(res);
int result = Math.round(Math.round(res));
return result;
}
Similarly, I'm also able to create the same structure for 16bits obtaining the desired rgb value, but it is a long and is not accepted by the setRGB() method, so I'm not able to create the bufferedImage, whose type I can't specify.
Can anyone help me with this final steps, please? Thank you in advance.
private Image createRGBImageFromGrayPixels_16(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
BufferedImage bm = new BufferedImage(width, height, BufferedImage...); //BufferedImage.TYPE ???
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
long rgb = pixels[y][x];
rgb = (rgb << 16) + pixels[y][x];
rgb = (rgb << 16) + pixels[y][x];
System.out.println(pixels[y][x] + "\t->\t" + rgb);
System.out.println();
bm.setRGB(x, y, rgb); //ERROR: long type for rgb is not accepted!
}
}
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
If needed, I can also install external jar libraries (obviously, only if opersource) that can help me achieving this goal.
I have a a lot of pixel art images that need to be scaled up to double the size.
It needs to be done so that each pixel in the image turns into a 2x2 set of pixels of the same exact same color, with no blending of colors.
example:
f I use ImageIO to read in a .png image as a BufferedImage with
BufferedImage foo = ImageIO.read(new File("C:\\path\\to\\image.png"));
how would I go about up-scaling it so it wont blend the pixels?
Hope it helps you
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageCovertTest {
public static void main(String[] args) throws IOException {
BufferedImage foo = ImageIO.read(new File("path/to/image"));
BufferedImage rs = cover(foo, 2);// cover X2
ImageIO.write(rs, "png", new File("path/to/output"));
}
private static int[][] convertToPixels(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel + 3 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel + 2 < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
public static BufferedImage cover(BufferedImage image, int range) {
int[][] pixels = convertToPixels(image);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage imageResult = new BufferedImage(width* range, height* range, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width * range; x ++){
for (int y = 0; y < height * range; y++) {
imageResult.setRGB(x, y, pixels[y/ range][x/ range]);
}
}
return imageResult;
}
}
I need to decompose a given colored picture in three separate pictures, so that each color component (Y, Cb, Cr) is stored in one picture like here.
Maybe has an idea how I could get these three pictures with
separately Y, Cb or Cr color components? With following peace of code I can just read out the file and convert the color model from RGB to YCbCr.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class SpaceConverter {
static int [] colorComponentsYCbCr = new int[3];
static int [] colorComponentsRGB = new int[3];
public static void getRGBComponents (int color)
{
colorComponentsRGB [0] = (color & 0xff);
colorComponentsRGB [1] = (color & 0x00ff) >> 8;
colorComponentsRGB [2] = (color & 0x0000ff) >> 16;
}
public static void convertYCbCr2RGB(int [] componentsYCbCrToConvert)
{
int Y = componentsYCbCrToConvert [0];
int Cb = componentsYCbCrToConvert [1];
int Cr = componentsYCbCrToConvert [2];
colorComponentsRGB = new int [3];
colorComponentsRGB [0] = (int) (Y + 1.402 * (Cr - 128));
colorComponentsRGB [1] = (int) (Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128));
colorComponentsRGB [2] = (int) (Y + 1.772 * (Cb - 128));
}
public static void convertRGB2YCbCr(int [] componentsRGB)
{
int blue = componentsRGB [0];
int green = componentsRGB [1];
int red = componentsRGB [2];
colorComponentsYCbCr [0] = (int) (0.299 * red + 0.587 * green + 0.114 * blue);
colorComponentsYCbCr [1] = (int) (128-0.169 * red-0.331 * green + 0.500 * blue);
colorComponentsYCbCr [2] = (int) (128+0.500 * red - 0.419 * green - 0.081 * blue);
}
public static void getColoredCrPicture(BufferedImage image)
{
File f = null;
// get width and height
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y<height; y++)
{
for (int x = 0; x<width; x++)
{
int color = image.getRGB(x, y);
getRGBComponents(color);
convertRGB2YCbCr(colorComponentsRGB);
int Y = colorComponentsYCbCr[0];
int Cb = colorComponentsYCbCr[1];
int Cr = colorComponentsYCbCr[2];
Y = 0;
Cb = 0;
int p = (Y << 24) | (Cb << 16) | (Cr<<8);
image.setRGB(x, y, p);
}
}
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/outputX.jpg");
ImageIO.write(image, "jpg", f);
}
catch(IOException e)
{
System.out.println(e);
}
}
public static void getColoredCbPicture(BufferedImage image)
{
File f = null;
// get width and height
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y<height; y++)
{
for (int x = 0; x<width; x++)
{
int color = image.getRGB(x, y);
getRGBComponents(color);
convertRGB2YCbCr(colorComponentsRGB);
int Y = colorComponentsYCbCr[0];
int Cb = colorComponentsYCbCr[1];
int Cr = colorComponentsYCbCr[2];
Y = 0;
Cr = 0;
int p = (Y << 24) | (Cb<< 16) | (Cr <<8);
image.setRGB(x, y, p);
}
}
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/outputCb.jpg");
ImageIO.write(image, "jpg", f);
System.out.println("WRITE Status: OK");
}
catch(IOException e)
{
System.out.println(e);
}
}
public static BufferedImage loadPicture()
{
File f = null;
BufferedImage img = null;
// read Image
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/VILLA.JPG");
img = ImageIO.read(f);
System.out.println("READ Status: OK");
getColoredCbPicture(img);
}
catch(IOException e)
{
System.out.println(e);
}
return img;
}
public static void main(String[] args)
{
BufferedImage image = null;
loadPicture();
getColoredCbPicture(image);
}
}
It sounds like what you are looking to do is take an RGB image, convert it to YCbCr and display each of the three channels in YCbCr as a separate RGB image.
You already have code that converts from RGB to YCbCr . You will also need code that will do the reverse conversion so you can go from YCbCr to RGB.
You will want to use this same logic, but actually create three Y'CrCb images: (Y, 0, 0), (0, Cb, 0) and (0, 0, Cr). Then convert each of these three images to RGB. These three images will be an RGB representation of each of the three YCbCr channels.
Is there any way to convert a Bitmap to sepia?
I know to convert to grayScale is to set the setSaturation in ColorMatrix.
But what about Sepia?
If you have instance of image then you can use ColorMartix to draw it in Sepia. Let me describe way how you can do this using Drawable.
public static void setSepiaColorFilter(Drawable drawable) {
if (drawable == null)
return;
final ColorMatrix matrixA = new ColorMatrix();
// making image B&W
matrixA.setSaturation(0);
final ColorMatrix matrixB = new ColorMatrix();
// applying scales for RGB color values
matrixB.setScale(1f, .95f, .82f, 1.0f);
matrixA.setConcat(matrixB, matrixA);
final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrixA);
drawable.setColorFilter(filter);
}
Sample project was moved from Bitbucket to GitHub. Please check Release section to download APK binary to test without compiling.
I know the answer, but maybe if some have other better solution..
public Bitmap toSephia(Bitmap bmpOriginal)
{
int width, height, r,g, b, c, gry;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
int depth = 20;
Bitmap bmpSephia = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpSephia);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setScale(.3f, .3f, .3f, 1.0f);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
canvas.drawBitmap(bmpOriginal, 0, 0, paint);
for(int x=0; x < width; x++) {
for(int y=0; y < height; y++) {
c = bmpOriginal.getPixel(x, y);
r = Color.red(c);
g = Color.green(c);
b = Color.blue(c);
gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (depth * 2);
g = g + depth;
if(r > 255) {
r = 255;
}
if(g > 255) {
g = 255;
}
bmpSephia.setPixel(x, y, Color.rgb(r, g, b));
}
}
return bmpSephia;
}
I've improved on the OP's answer. This runs competitively fast when compared to the ColorMatrix method, but producing a nicer brown tone. (in my opinion)
public Bitmap toSepiaNice(Bitmap color) {
int red, green, blue, pixel, gry;
int height = color.getHeight();
int width = color.getWidth();
int depth = 20;
Bitmap sepia = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
color.getPixels(pixels, 0, width, 0, 0, width, height);
for (int i = 0; i < pixels.length; i++) {
pixel = pixels[i];
red = (pixel >> 16) & 0xFF;
green = (pixel >> 8) & 0xFF;
blue = pixel & 0xFF;
red = green = blue = (red + green + blue) / 3;
red += (depth * 2);
green += depth;
if (red > 255)
red = 255;
if (green > 255)
green = 255;
pixels[i] = (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
sepia.setPixels(pixels, 0, width, 0, 0, width, height);
return sepia;
}
I'm trying to get the DCT of a bufferedImage using JTransform. When I visualise the transform it currently looks like this http://tinypic.com/r/2vcxhzo/8
In order to use Jtransform I need to convert the BufferedImage to a 2d double array. I've tried two different methods to change the bufferedImage to a double array
public double[][] convertTo2DArray(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster()
.getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
double[][] result = new double[height][width];
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
if (hasAlphaChannel) {
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
} else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel] & 0xff); // blue
argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red
result[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
I've also tried
private double[][] bufferedImageToArray(BufferedImage image) {
int h = image.getHeight();
int w = image.getWidth();
int[][] array = new int[h][w];
double[][] result;
for (int count = 0; count < h; count++) {
for (int loop = 0; loop < w; loop++) {
int gray = image.getRGB(loop, count) & 0xFF;
// add values to array
array[count][loop] = gray;
}
}
result = toDoubleArray(array);
return result;
}
I've implemented the transform as
public double[][] applyDCT(double[][] image) {
DoubleDCT_2D transform = new DoubleDCT_2D(image.length, image[0].length);
transform.forward(image, true);
return image;
}
I tried using OpenCV's dct transform but it gives the same output as shown in the link.
Ty something like that (I kept only the blue channel for simplicity). It shows the energy compaction in the upper left corner of the result image.
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class TestDCT
{
public static void main(String[] args)
{
ImageIcon icon = new ImageIcon(args[0]);
Image image = icon.getImage();
int w = image.getWidth(null);
int h = image.getHeight(null);
GraphicsDevice gs = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(w, h, Transparency.OPAQUE);
img.getGraphics().drawImage(image, 0, 0, null);
int[] rgb1 = new int[w*h];
img.getRaster().getDataElements(0, 0, w, h, rgb1);
double[] array = new double[w*h];
for (int i=0; i<w*h; i++)
array[i] = (double) (rgb1[i] & 0xFF);
org.jtransforms.dct.DoubleDCT_2D tr = new org.jtransforms.dct.DoubleDCT_2D(w, h);
tr.forward(array, true);
for (int i=0; i<w*h; i++)
{
// Grey levels
int val= Math.min((int) (array[i]+128), 255);
rgb1[i] = (val <<16) | (val << 8) | val;
}
img.getRaster().setDataElements(0, 0, w, h, rgb1);
icon = new ImageIcon(img);
JFrame frame = new JFrame("FFT");
frame.setBounds(20, 30, w, h);
frame.add(new JLabel(icon));
frame.setVisible(true);
}
}