I want to generate a 64x64 pixel art for any image provided by the user. I'm currently lost on how to do it. OpenCV does not seem to provide any such functionality. Any pointers in the right direction would be gladly appreciated.
Edit
Pixel art is a pixelated image of a given image. The screen shot below shows what I've achieved so far.
Basically what I've done is as follows.
Scale the image with aspect ratios maintained so that it would fit within a 64x64 grid
Image sourceImage;
Rectangle imageBound = sourceImage.getBounds();
double sx = (double) 64 / (double) imageBound.width;
double sy = (double) 64 / (double) imageBound.height;
double s = Math.min(sx, sy);
int dx = (int) (s * imageBound.width);
int dy = (int) (s * imageBound.height);
Image scaledImage = new Image(d, sourceImage.getImageData().scaledTo(dx, dy));
Read each pixel from the scaled image and output it on the screen.
Following shows how I extract the color from each pixel. I use SWT framework.
Display d;
ImageData data = scaledImage.getImageData();
for(int i=0; i<data.width; i++) {
for(int j=0; j<data.height; j++) {
int pixel = data.getPixel(i,j);
int red = (pixel & 0x00ff0000) >> 16;
int green = (pixel & 0x0000ff00) >> 8;
int blue = pixel & 0x000000ff;
pixelGrid[i][j].setBackground(new Color(d, red, green, blue));
}
}
But as you can see, there is a major difference in the colors after resizing the image. What I want to know is whether I'm on the correct path to achieve this and if so, how can I retain the actual colors while scaling.
You probably have an image in RGBA format, and are extracting the wrong values from the image (as if it were ARGB). It looks very blue currently, and I fail to see any reds. That should have put you on the right track:
int red = (pixel>>24) & 0xff;
int green = (pixel>>16) & 0xff;
int blue = (pixel>>8) & 0xff;
int alpha = pixel & 0xff; // always 0xff for images without transparency
Related
I'm looking to use a very crude heightmap I've created in Photoshop to define a tiled isometric grid for me:
Map:
http://i.imgur.com/jKM7AgI.png
I'm aiming to loop through every pixel in the image and convert the colour of that pixel to a scale of my choosing, for example 0-100.
At the moment I'm using the following code:
try
{
final File file = new File("D:\\clouds.png");
final BufferedImage image = ImageIO.read(file);
for (int x = 0; x < image.getWidth(); x++)
{
for (int y = 0; y < image.getHeight(); y++)
{
int clr = image.getRGB(x, y) / 99999;
if (clr <= 0)
clr = -clr;
System.out.println(clr);
}
}
}
catch (IOException ex)
{
// Deal with exception
}
This works to an extent; the black pixel at position 0 is 167 and the white pixel at position 999 is 0. However when I insert certain pixels into the image I get slightly odd results, for example a gray pixel that's very close to white returns over 100 when I would expect it to be in single digits.
Is there an alternate solution I could use that would yield more reliable results?
Many thanks.
Since it's a grayscale map, the RGB parts will all be the same value (with range 0 - 255), so just take one out of the packed integer and find out what percent of 255 it is:
int clr = (int) ((image.getRGB(x, y) & 0xFF) / 255.0 * 100);
System.out.println(clr);
getRGB returns all channels packed into one int so you shouldn't do arithmetic with it. Maybe use the norm of the RGB-vector instead?
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
final int rgb = image.getRGB(x, y);
final int red = ((rgb & 0xFF0000) >> 16);
final int green = ((rgb & 0x00FF00) >> 8);
final int blue = ((rgb & 0x0000FF) >> 0);
// Norm of RGB vector mapped to the unit interval.
final double intensity =
Math.sqrt(red * red + green * green + blue * blue)
/ Math.sqrt(3 * 255 * 255);
}
}
Note that there is also the java.awt.Color class that can be instantiated with the int returned by getRGB and provides getRed, getGreen and getBlue methods if you don't want to do the bit manipulations yourself.
I want to convert coloured image to a monochrome, i thought to loop all pixel, but I don't know how to test if they are bright or dark.
for(int y=0;y<image.getHeight();y++){
for(int x=0;x<image.getWidth();x++){
int color=image.getRGB(x, y);
// ???how to test if its is bright or dark?
}
}
int color = image.getRGB(x, y);
// extract each color component
int red = (color >>> 16) & 0xFF;
int green = (color >>> 8) & 0xFF;
int blue = (color >>> 0) & 0xFF;
// calc luminance in range 0.0 to 1.0; using SRGB luminance constants
float luminance = (red * 0.2126f + green * 0.7152f + blue * 0.0722f) / 255;
// choose brightness threshold as appropriate:
if (luminance >= 0.5f) {
// bright color
} else {
// dark color
}
I suggest first converting the pixel to grayscale, then applying a threshold for converting it pure black&white.
There are libraries that will do this for you, but if you want to learn how images are processed, here you are:
Colour to grayscale
There are various formulas for converting (see a nice article here), I prefer the "luminosity" one. So:
int grayscalePixel = (0.21 * pRed) + (0.71 * pGreen) + (0.07 * pBlue)
I cannot tell what API you are using to manipulate the image, so I left the formula above in general terms. pRed, pGreen and pBlue are the red, green and blue levels (values) for the pixel.
Grayscale to b/w
Now, you can apply a threshold with:
int bw = grayscalePixel > THRESHOLD? 1: 0;
or even:
boolean bw = grayscalePixel > THRESHOLD;
Pixel will be white if above threshold, black if below. Find the right THRESHOLD by experimenting a bit.
I am making an image editing like program, and when I want to edit large images it really starts to slow down. What is a good way to edit large image quickly? This example adjusts the image's brightness, it works, but when I get large images such as 3456x2304 its really slow.
I have a slider, which calls this function every time it moves.
// Slider in a dialog box
private void sldBrightnessStateChanged(javax.swing.event.ChangeEvent evt) {
// Get the position of the slider
int val = sldBrightness.getValue();
// Set the text in the textbox
txtBrightness.setText("" + val);
// New Brightness class (see below)
Brightness adjustment = new Brightness();
adjustment.amount(val);
adjustment.applyFilter();
// get the result built by applyFilter();
Canvas.preview = Preview.getImage();
// Update main program
this.getParent().repaint();
}
Then the filter:
package pocketshop.graphics.adjustments;
import java.awt.image.BufferedImage;
import pocketshop.Canvas;
import pocketshop.graphics.Colors;
import pocketshop.graphics.Preview;
public class Brightness{
protected int amount = 0;
public void amount(int amount){
this.amount = amount;
}
public void applyFilter(){
int width = Canvas.image.getWidth();
int height = Canvas.image.getHeight();
int[] pixels = new int[width * height];
Canvas.image.getRGB(0, 0, width, height, pixels, 0, width);
for(int i = 0; i < pixels.length; i++){
int pixel = pixels[i];
//int pixel = Canvas.image.getRGB(x, y);
int red = Colors.red(pixel);
int green = Colors.green(pixel);
int blue = Colors.blue(pixel);
red += amount;
if(red > 255){
red = 255;
}else if(red < 0){
red = 0;
}
green += amount;
if(green > 255){
green = 255;
}else if(green < 0){
green = 0;
}
blue += amount;
if(blue > 255){
blue = 255;
}else if(blue < 0){
blue = 0;
}
pixels[i] = Colors.rgba(red, green, blue);
}
//BrightnessContrastDialog.preview.setRGB(0, 0, width, height, pixels, 0, width);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, width, height, pixels, 0, width);
Preview.setImage(img);
}
}
I have a slider, which calls this function every time it moves.
Don't adjust the image until the slider stops moving. I don't know Swing, but I'm betting there is a test for evt which says whether it is moving or has stopped.
The way you have it, applyFilter may be called 100 times or more as the slider is moved.
As I understand the picture is presented for user in order to give immediate feedback of changes that are made, what you can do us display downsampled version of picture and perform the brightness change to it while slider is moving which will be fast. Once user is satisfied with the value she selected using slider you can apply the change to original image. You can add apply button or something
I would suggest that you investigate OpenCL and its Java binding, JOCL. OpenCL is a library for interacting directly with the GPU on various different graphics cards. JOCL is a Java binding library for the OpenCL API.
Fair warning, this may be much more than you want to tackle, as you will be working at a much lower level than Swing.
I am not sure but it looks like you are using a BufferedImage of type BufferedImage.TYPE_INT_ARGB. This means that the BufferedImage is using a WritableRaster that is using a DataBuffer of type DataBufferInt. In its simplest form a DataBufferInt is nothing more than a wrapper around an int[]. If you can get a hold of the BufferedImage that the Canvas is using then get its WritableRaster and from there get the DataBufferInt:
WritableRaster raster = Canvas.image.getRaster();
DataBufferInt dataBuffer = (DataBufferInt)raster.getDataBuffer();
int[] pixels = dataBuffer.getData();
Now that you have the int[] that represents the pixels you can just loop over it and change the components:
for (int i = 0, len = pixels.len; i < len; ++i) {
int pixel = pixels[i];
int red = ((pixel & 0x00FF0000) >> 16) + amount;
if (red < 0) red = 0 else if (red > 255) red = 255;
int green = ((pixel & 0x0000FF00) >> 8) + amount;
if (green < 0) green = 0 else if (green > 255) green = 255;
int blue = (pixel & 0x000000FF) + amount;
if (blue < 0) blue = 0 else if (blue > 255) blue = 255;
pixels[i] = (pixels[i] & 0xFF000000) + (red << 16) + (green << 8) + blue;
}
This means that the pixels in the BufferedImage that the Preview has are being changed in-place without having to create another int[] of new pixels and another BufferedImage.
I am not sure if this will work but many times it helps in Java to cut out the middle-man and don't create as many objects.
If this does not work then look into Java Advanced Imaging.
How can I make a color picker, which gets a value of images pixel and refreshes any time I click on different pixel, shows it? It must be done in java.
Load the image in a frame.
Use the mouse coordinates from the upper left corner of the image.
Assuming your image is loaded into BufferedImage, you can use:
int x,y; //populated from Mouse coordinates
int rgb = myBufferedImage.getPixel(x,y);
//to extract colors
int red = (rgb & 0x00ff0000) >> 16;
int green = (rgb & 0x0000ff00) >> 8;
int blue = rgb & 0x000000ff;
// and to create a new Java color
Color c = new Color(red,blue,green);
I am reading pixel color in a BufferedImage as follows:
.....
InputStream is = new BufferedInputStream(conn.getInputStream());
BufferedImage image = ImageIO.read(is);
int color = image.getRGB(x, y);
int red = (colour & 0x00ff0000) >> 16;
int green = (colour & 0x0000ff00) >> 8;
int blue = colour & 0x000000ff;
Now this works fine except for png's with transparency. I find that if x,y refer to a transparent pixel with no color, i still read a color, generally the same color as used elsewhere in the image.
How do I detect that the pixel is actually transparent and not colored?
Thanks
int alpha = (colour>>24) & 0xff;
The result is also a value ranging from 0 (completely transparent) to 255 (completely opaque).