I am trying to find out why I get "Coordinate out of bounds!" when trying to implement the flood fill. It's a black and white image, when there is white nothing should happen when flood filling, and it doesn't so that is good. All black areas is gonna be flood filled with red and some areas become red until I get the error message that the coordinates are out of bounds. Here is the source code:
public class FloodFiller extends JPanel implements MouseListener {
private BufferedImage img;
public void turnBlacknWhite() {
int x, y;
int w = img.getWidth();
int h = img.getHeight();
// first compute the mean intensity
int totintensity = 0;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int rgb = img.getRGB(x, y);
totintensity += (rgb >> 16) & 0xFF + (rgb >> 8) & 0xFF + rgb
& 0xFF;
}
}
int meanintensity = totintensity / (w * h);
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int rgb = img.getRGB(x, y);
int intensity = (rgb >> 16) & 0xFF + (rgb >> 8) & 0xFF + rgb
& 0xFF;
if (intensity < meanintensity) { // it's darker than mean
// intensity
img.setRGB(x, y, 0); // turn black
} else { // it's lighter
img.setRGB(x, y, 0xFFFFFF); // turn white
}
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
floodFill(e.getX(), e.getY(), 0xFF0000);
this.repaint();
}
/**
* Fill the black area including and around (x,y) with color. If (x,y) is
* not black, do nothing.
*/
public void floodFill(int x, int y, int color) {
// TODO!
int rgb = img.getRGB(x, y);
int black = Color.black.getRGB();
if (rgb == black) {
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y + 1, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y - 1, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x + 1, y, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x - 1, y, color);
}
}
}
// public void isValid (int width, int height) {
// int coordinate = 0;
// int width = img.getWidth();
// int height = img.getHeight();
// if (width && height => coordinate) {
//
// }
// }
public FloodFiller(String fileName) {
URL imgUrl = getClass().getClassLoader().getResource(fileName);
if (imgUrl == null) {
System.err.println("Couldn't find file: " + fileName);
} else {
try {
img = ImageIO.read(imgUrl);
} catch (IOException ex) {
ex.printStackTrace();
}
}
turnBlacknWhite();
setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
this.addMouseListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
g.drawImage(img, 0, 0, null);
}
public static void main(String[] args) {
final String fileName = args[0];
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Flood Filler");
frame.setContentPane(new FloodFiller(fileName));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
Anyone who might know why this happens? :) Thanks!
The bounds on the parameters to the calls to floodFill() are not properly checked.
Look at these lines:
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y + 1, color);
}
Say your image is 100 pixels tall and wide. The pixels are numbered 0-99 on each axis. Say floodfill() was just called with x = 30, y = 99. The if statement checks out, so you get to the next two lines, and now you are calling floodFill(30, 100, [color]). That call will try to run the first line in floodFill() as int rgb = img.getRGB(30, 100), and now y is out of bounds because your y-pixels only go up to 99.
Similar things happen on other image edges in the rest of floodFill().
Related
I want to layer two images together. A background and foreground. The foreground is stitched together as a grid of smaller images (3x3). I have been able to make all white pixels transparent as a workaround, however the inside of the shapes are white and I only want pixels outside the shapes transparent.
Say for example the grid of images contained a circle or square in each grid location. Is there a way I can iterate over each pixel and create two arrays of pixel locations - those outside the images making them transparent, and those inside the images where I can set the colour?
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
// Stitches a grid of images together, scales a background image to fit and layers them.
public class Layer {
public static void layerImages() {
// Grid layout of images to stitch.
int rows = 3;
int cols = 3;
int chunks = rows * cols;
int chunckWidth, chunkHeight;
// Image files to stitch
File[] imgFiles = new File[chunks];
for(int i = 0; i < chunks; i++) {
imgFiles[i] = new File("ocarina_sprite" + (i + 1) + ".png");
}
// Read images into array.
try {
BufferedImage[] buffImages = new BufferedImage[chunks];
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
}
chunckWidth = buffImages[0].getWidth();
chunkHeight = buffImages[0].getHeight();
BufferedImage finalImage = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);
// Calculate background width and height to cover stitched image.
int bwidth = 0;
int bheight = 0;
for(int i = 0; i < rows; i++) {
bwidth += buffImages[i].getWidth();
}
for(int i = 0; i < cols; i++) {
bheight += buffImages[i].getHeight();
}
// Background image
File dory = new File("dory.png");
BufferedImage original = ImageIO.read(dory);
// Scale background image.
BufferedImage background = scale(original, bwidth, bheight);
// Prepare final image by drawing background first.
Graphics2D g = finalImage.createGraphics();
g.drawImage(background, 0, 0, null);
// Prepare foreground image.
BufferedImage foreground = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);
// Stitch foreground images together
int num = 0;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < rows; j++) {
foreground.createGraphics().drawImage(buffImages[num],chunckWidth * j, chunkHeight * i, null);
num++;
}
}
// Set white pixels to transparent.
for (int y = 0; y < foreground.getHeight(); ++y) {
for (int x = 0; x < foreground.getWidth(); ++x) {
int argb = foreground.getRGB(x, y);
if ((argb & 0xFFFFFF) > 0xFFFFEE) {
foreground.setRGB(x, y, 0x00FFFFFF);
}
}
}
// Draw foreground image to final image.
Graphics2D g3 = finalImage.createGraphics();
g3.drawImage(foreground, 0, 0, null);
// Output final image
ImageIO.write(finalImage, "png", new File("finalImage.png"));
}
catch (Exception e) {
System.out.println(e);
}
}
// Scale image
public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight) {
BufferedImage scaledImage = null;
if (imageToScale != null) {
scaledImage = new BufferedImage(dWidth, dHeight, imageToScale.getType());
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
}
return scaledImage;
}
}
The floodfill solution mentioned in the comment was what I needed to solve the problem, however the recursion over a million+ pixels didn't work out so I implemented the forest fire algorithm which is floodfill using queues instead of recursion.
public static void forestFire(int width, int height, int x, int y) {
// Check if already set
int argb = foreground.getRGB(x, y);
if (((argb >> 24) & 0xFF) == 0) {
return;
}
coords.add(new Point(x, y));
// Set transparent pixel
foreground.setRGB(x, y, 0x00FFFFFF);
Point currentCoord = new Point();
while(!coords.isEmpty()) {
currentCoord.setLocation(coords.poll());
// Get current coordinates
x = (int)currentCoord.getX();
y = (int)currentCoord.getY();
// North
if(y != 0) {
int north = foreground.getRGB(x, y - 1);
// Check if transparent (already set) and check target colour (white)
if (((north >> 24) & 0xFF) > 0 && (north & 0xFFFFFF) > 0x111100) {
// Set transparent pixel
foreground.setRGB(x, y - 1, 0x00FFFFFF);
coords.add(new Point(x, y - 1));
}
}
// East
if(x != width - 1) {
int east = foreground.getRGB(x + 1, y);
if (((east >> 24) & 0xFF) > 0 && (east & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x + 1, y, 0x00FFFFFF);
coords.add(new Point(x + 1, y));
}
}
// South
if(y != height - 1) {
int south = foreground.getRGB(x, y + 1);
if (((south >> 24) & 0xFF) > 0 && (south & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x, y + 1, 0x00FFFFFF);
coords.add(new Point(x, y + 1));
}
}
// West
if(x != 0) {
int west = foreground.getRGB(x - 1, y);
if (((west >> 24) & 0xFF) > 0 && (west & 0xFFFFFF) > 0x111100) {
foreground.setRGB(x - 1, y, 0x00FFFFFF);
coords.add(new Point(x - 1, y));
}
}
}
I have to create a simple 2D animation without using various primitives for drawing line, circle etc for the purpose. It has to be done by manipulating pixels and implementing one of the algorithms for drawing line, circle etc by coloring pixels.
I thought of using Turbo C for the purpose, but I use ubuntu. So I tried using dosbox to install and run turbo C but to no avail.
Now my only option is Java. Is it possible to manipulate pixels in Java? I couldn't find myself any good tutorials for the same. It would be great if a sample code for the same can be given.
The class java.awt.BufferedImage has a method setRGB(int x, int y, int rgb) which sets the color of an individual pixel. Additionally, you might want to look at java.awt.Color, especially its getRGB() method, which can convert Colors into integers that you can put into the int rgb parameter of setRGB.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DirectDrawDemo extends JPanel {
private BufferedImage canvas;
public DirectDrawDemo(int width, int height) {
canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
fillCanvas(Color.BLUE);
drawRect(Color.RED, 0, 0, width/2, height/2);
}
public Dimension getPreferredSize() {
return new Dimension(canvas.getWidth(), canvas.getHeight());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(canvas, null, null);
}
public void fillCanvas(Color c) {
int color = c.getRGB();
for (int x = 0; x < canvas.getWidth(); x++) {
for (int y = 0; y < canvas.getHeight(); y++) {
canvas.setRGB(x, y, color);
}
}
repaint();
}
public void drawLine(Color c, int x1, int y1, int x2, int y2) {
// Implement line drawing
repaint();
}
public void drawRect(Color c, int x1, int y1, int width, int height) {
int color = c.getRGB();
// Implement rectangle drawing
for (int x = x1; x < x1 + width; x++) {
for (int y = y1; y < y1 + height; y++) {
canvas.setRGB(x, y, color);
}
}
repaint();
}
public void drawOval(Color c, int x1, int y1, int width, int height) {
// Implement oval drawing
repaint();
}
public static void main(String[] args) {
int width = 640;
int height = 480;
JFrame frame = new JFrame("Direct draw demo");
DirectDrawDemo panel = new DirectDrawDemo(width, height);
frame.add(panel);
frame.pack();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
alt text http://grab.by/grabs/39416148962d1da3de12bc0d95745341.png
Another bit of fun I had today where I used #Jave Cavas, Color, Graphics and #Swing JFrame to create a simply colouring pixels class all we are doing is creating square a JFrame 400×400 pixels (few extra pixels required for the frame it self) and then we extend the Canvas and colour the pixels symmetrically.
package gcclinux.co.uk;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class ColouringPixels extends Canvas {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 407; // Additional pixels needed for the frame
private static final int HEIGHT = 427; // Additional pixels needed for the frame
#Override
public void paint(Graphics g) {
super.paint(g);
for (int r = 0; r <= 2; r++) {
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
if (x >= 1 && x <= 100 && y >= 1 && y <=100){
g.setColor(Color.WHITE);
} else if (x >= 101 && x <= 200 && y >= 101 && y <=200){
g.setColor(Color.RED);
} else if (x >= 201 && x <= 300 && y >= 201 && y <=300){
g.setColor(Color.WHITE);
} else if (x >= 301 && x <= 399 && y >= 301 && y <=400){
g.setColor(Color.RED);
} else
{
g.setColor(Color.BLUE);
}
g.drawLine(x, y, x, y);
}
}
for(int x = 0; x < HEIGHT; x++) {
for(int y = 0; y < WIDTH; y++) {
if (x >= 1 && x <= 100 && y >= 1 && y <=100){
g.setColor(Color.RED);
} else if (x >= 101 && x <= 200 && y >= 101 && y <=200){
g.setColor(Color.WHITE);
} else if (x >= 201 && x <= 300 && y >= 201 && y <=300){
g.setColor(Color.RED);
} else if (x >= 301 && x <= 399 && y >= 301 && y <=400){
g.setColor(Color.WHITE);
} else
{
g.setColor(Color.BLUE);
}
g.drawLine(x, y, x, y);
}
}
}
try {
Thread.sleep(2000); // Sleep for 2 seconds
System.exit(0); // Closed the program
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("ColouringPixels - Lesson 9");
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.add(new ColouringPixels());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
You can accomplish this using java's builtin 2D Graphics package.
I'm begginer in java game programming and I have a small actually big problem (for me) with game.
I'm trying making collision between enemy and blocks it doesnt work and i dont know why. It should worked but it just slow game on one fps per second and dont do anything.
I have main class called Game
with this main Init() function
public void init(){
WIDTH = getWidth();
HEIGHT = getHeight();
tex = new Texture();
BufferImageLoader loader = new BufferImageLoader();
level = loader.loadImage("/level.png"); // loading level
cloud = loader.loadImage("/cloud.png"); // loading clouds
handler = new Handler();
cam = new Camera(0,0);
LoadImageLevel(level);
this.addKeyListener(new KeyInput(handler));
}
and than LoadImageLevel function where I read level.png pixel by pixel and by the differents color I'm setting position of every objects.
private void LoadImageLevel (BufferedImage image){
int w = image.getWidth();
int h = image.getHeight();
//System.out.println(w + " , " + h);
for(int xx = 0; xx < h; xx++){
for(int yy = 0; yy < w ; yy++){
int pixel = image.getRGB(xx, yy);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
if(red == 255 && green == 255 && blue == 255)
handler.addObject(new Block(xx*32,yy*32,1,ObjectId.Block));
if(red == 0 && green == 0 && blue == 255)
handler.addObject(new Player(xx*32,yy*32,1,handler,ObjectId.Player));
if(red == 0 && green == 255 && blue == 0)
handler.addObject(new Enemy(xx*32,yy*32,handler,ObjectId.Enemy));
}
}
}
In class Player is two important functions tick and collision where in tick is collison called.
public class Player extends GameObject{
private float width = 32, // 48
height = 64; // 96
private float gravity = 0.5f;
private final float MAX_SPEED = 10;
private int facing = 1;
private int last = 0; // last position left or right
private Handler handler;
Texture tex = Game.getInstance();
private int type;
private Animation playerWalk, playerWalkLeft,jump;
public Player(float x, float y,int type , Handler handler ,ObjectId id) {
super(x, y, id);
this.handler = handler;
this.type = type;
playerWalk = new Animation(2,tex.player[2],tex.player[3],
tex.player[4],tex.player[5]);
playerWalkLeft = new Animation(2,tex.player[7],tex.player[8],
tex.player[9],tex.player[10]);
jump = new Animation(2,tex.player[11],tex.player[12]);
}
public void tick(LinkedList<GameObject> object) {
x += velX;
y += velY;
if(velX < 0) facing = -1;
else if(velX > 0) facing = 1;
if(falling || jumping){
velY += gravity;
if(velY > MAX_SPEED){
velY = MAX_SPEED;
}
}
Collision(object);
//System.out.println(velX + " " + velY);
playerWalk.runAnimation();
playerWalkLeft.runAnimation();
jump.runAnimation();
}
private void Collision(LinkedList<GameObject> object){
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
y = tempObject.getY() + 32;
velY = 0;
}
if(getBounds().intersects(tempObject.getBounds())){
y = tempObject.getY() - height;
velY = 0;
falling = false;
jumping = false;
}else
falling = true;
if(getBoundsRight().intersects(tempObject.getBounds())){
x = tempObject.getX() - width;
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
x = tempObject.getX() + 35;
}
}
/* new */
}
}
public void render(Graphics g) {
/*
g.setColor(Color.blue);
g.fillRect((int)x,(int)y,(int)width,(int)height);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.red);
g2d.draw(getBounds());
g2d.draw(getBoundsRight());
g2d.draw(getBoundsLeft());
g2d.draw(getBoundsTop());
*/
if(velX != 0){
if (facing == 1){
playerWalk.drawAnimation(g,(int) x, (int)y,32,64);
last = 1;
}
else{
playerWalkLeft.drawAnimation(g,(int) x, (int)y,32,64);
last = 0;
}
}
else
if (last == 1)
g.drawImage(tex.player[1], (int)x,(int) y,32,64,null);
else
g.drawImage(tex.player[6], (int)x,(int) y,32,64,null); // 6 ,32,64
//System.out.println("Y: " + y); // 513 je max
if (y >= 513){
g.setColor(Color.red);
g.drawString("Game Over", (int) x, 200);
}
}
public Rectangle getBounds() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int) ((int)y+(height/2)),(int)width/2,(int)height/2);
}
public Rectangle getBoundsTop() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int)y,(int)width/2,(int)height/2);
}
public Rectangle getBoundsRight() {
return new Rectangle((int) ((int)x+width-5),(int)y+5,(int)5,(int)height-10);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y+5,(int)5,(int)height-10);
}
Player dont have any problem with block collision.
public class Block extends GameObject {
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y,int type,ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(LinkedList<GameObject> object) {
}
public void render(Graphics g) {
if(type == 0)
g.drawImage(tex.block[0], (int) x, (int) y ,null);
if(type == 1)
g.drawImage(tex.block[1], (int) x, (int) y ,null);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}
}
But when i tried created Enemy class and make it same like in Player class I mean collision it just make game slower and nothing else.
public class Enemy extends GameObject{
private Handler handler;
public Enemy(float x, float y,Handler handler, ObjectId id) {
super(x, y, id);
this.handler = handler;
}
public void tick(LinkedList<GameObject> object) {
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
}
if(getBounds().intersects(tempObject.getBounds())){
}
if(getBoundsRight().intersects(tempObject.getBounds())){
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
}
}
}
}
public void render(Graphics g) {
g.setColor(Color.red);
g.fillRect((int)x,(int) y, 32, 32);
}
public Rectangle getBoundsTop() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsRight() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}}
I know that bounds should not have return same "new Rectangle" and that theres no any movements of enemy anyway when i set in tick method x--; for just trying if enemy stop when it come to the edge of block but it doesnt work i dont know whats wrong with it i spend more than two days with fixing this. If it can help you there is a link for whole project (Eclipse) You can download it from dropbox
I just wanted to have an enemy which move left and right and have collison with block it means when he "touch" by his left side to the block he "turn around" and move to right side until he "touch" by his right side etc... other collisions between Player and Enemy is not problem for me. But just this.
I'm so thankful for every advice :)
The problem is with your getBounds() method.
You are saying in getBounds() method to return a rectangle with width=32 and height=32. And since your rectangle is 32 by 32 (as mentioned in fillrect(x,y,32,32) ) so getBounds() returns with the intersection in height and width.
In other words, try not to collide the returned Top left bottom or right bounds with themselves.
And in enemy(), you are declaring set.color = red while in loading you are using green. Try red==255, green==0, blue==0 instead of if(red == 0 && green == 255 && blue == 0)
I've put all the black pixels of the image in an array and I want them to get the color of their left neighbor. I run the code without errors but the result is not really what I'm expecting.
Where those black stripes comes form? I was expecting it to be all red.
Here's my code and results.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.*;
public class ImageTest {
public static BufferedImage Threshold(BufferedImage img) {
int height = img.getHeight();
int width = img.getWidth();
BufferedImage finalImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
int r = 0;
int g = 0;
int b = 0;
List<Integer> blackpixels = new ArrayList<Integer>();
for (int x = 0; x < width; x++) {
try {
for (int y = 0; y < height; y++) {
//Get RGB values of pixels
int rgb = img.getRGB(x, y);
r = ImageTest.getRed(rgb);
g = ImageTest.getGreen(rgb);
b = ImageTest.getBlue(rgb);
int leftLoc = (x-1) + y*width;
if ((r < 5) && (g < 5) && (b < 5)) {
blackpixels.add(rgb);
Integer[] simpleArray = new Integer[ blackpixels.size() ];
System.out.print(simpleArray.length);
int pix = 0;
while(pix < simpleArray.length) {
r = leftLoc;
pix = pix +1;
}
}
finalImage.setRGB(x,y,ImageTest.mixColor(r, g,b));
}
}
catch (Exception e) {
e.getMessage();
}
}
return finalImage;
}
private static int mixColor(int red, int g, int b) {
return red<<16|g<<8|b;
}
public static int getRed(int rgb) {
return (rgb & 0x00ff0000) >> 16;
}
public static int getGreen(int rgb) {
return (rgb & 0x0000ff00) >> 8;
}
public static int getBlue(int rgb) {
return (rgb & 0x000000ff) >> 0;
}
}
The following might work.
The main change is that it first collects the locations of ALL dark pixels, then goes over them to assign the colour from their left neighbours.
import java.awt.image.BufferedImage;
import java.util.*;
public class BlackRedImage
{
public static BufferedImage Threshold( BufferedImage img )
{
int height = img.getHeight();
int width = img.getWidth();
BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
List<Integer> blackpixels = new ArrayList<Integer>();
for ( int x = 0; x < width; x++ )
{
for ( int y = 0; y < height; y++ )
{
int rgb = img.getRGB(x, y); // Get the pixel in question
int r = BlackRedImage.getRed(rgb);
int g = BlackRedImage.getGreen(rgb);
int b = BlackRedImage.getBlue(rgb);
if ( (r < 5) && (g < 5) && (b < 5) )
{ // record location of any "black" pixels found
blackpixels.add(x + (y * width));
}
finalImage.setRGB(x, y, rgb);
}
}
// Now loop through all "black" pixels, setting them to the colour found to their left
for ( int blackPixelLocation: blackpixels )
{
if ( blackPixelLocation % width == 0 )
{ // these pixels are on the left most edge, therefore they do not have a left neighbour!
continue;
}
int y = blackPixelLocation / width;
int x = blackPixelLocation - (width * y);
int rgb = img.getRGB(x - 1, y); // Get the pixel to the left of the "black" pixel
System.out.println("x = " + x + ", y = " + y + ", rgb = " + rgb);
finalImage.setRGB(x, y, rgb);
}
return finalImage;
}
private static int mixColor( int red, int g, int b )
{
return red << 16 | g << 8 | b;
}
public static int getRed( int rgb )
{
return (rgb & 0x00ff0000) >> 16;
}
public static int getGreen( int rgb )
{
return (rgb & 0x0000ff00) >> 8;
}
public static int getBlue( int rgb )
{
return (rgb & 0x000000ff) >> 0;
}
}
EDIT: Here is a simpler version (doesn't collect the black pixels)
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.*;
public class ColourMove
{
public static BufferedImage Threshold( BufferedImage img )
{
int width = img.getWidth();
int height = img.getHeight();
BufferedImage finalImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for ( int x = 1; x < width; x++ ) // Start at 1 as the left most edge doesn't have a left neighbour
{
for ( int y = 0; y < height; y++ )
{
Color colour = new Color(img.getRGB(x, y));
int red = colour.getRed();
int green = colour.getGreen();
int blue = colour.getBlue();
if ( (red < 5) && (green < 5) && (blue < 5) )
{ // Encountered a "black" pixel, now replace it with it's left neighbour
finalImage.setRGB(x, y, img.getRGB(x - 1, y));
}
else
{ // Non-black pixel
finalImage.setRGB(x, y, colour.getRGB());
}
}
}
return finalImage;
}
}
Aloha,
i have trouble finding the error in my java code. In my opinion everything is fine and correct but the function is not executed correctly and I dont understand why. The function should detect the difference between the colors and calculate the arithmetic mean of them.
The resilt of it should be draw under the original picture. What did I miss, please help me?
package edge;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import javax.swing.JComponent;
import javax.swing.JFrame;
/**
*
* #author Alaska
*/
public class Edge extends JComponent {
final int W = 500;
final int H = 300;
Image m_TrgImg, m_SrcImg;
public Edge(JFrame father) {
try {
FileDialog diag = new FileDialog(father);
diag.setVisible(true);
m_SrcImg = getToolkit().getImage(diag.getDirectory() + diag.getFile()).getScaledInstance(W, H, Image.SCALE_SMOOTH);
MediaTracker mt = new MediaTracker(this);
mt.addImage(m_SrcImg, 0);
mt.waitForAll();
int[] srcPix = new int[W * H];
int[] trgPix = new int[W * H];
PixelGrabber grab = new PixelGrabber(m_SrcImg, 0, 0, W, H, srcPix, 0, W);
grab.getPixels();
MemoryImageSource imgProd = new MemoryImageSource(W, H, trgPix, 0, W);
m_TrgImg = createImage(imgProd);
detectEdges(srcPix, trgPix);
m_TrgImg.flush();
} catch (InterruptedException e) {
System.out.println(e);
}
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(m_SrcImg, 0, 0, this);
g.drawImage(m_TrgImg, 0, H, this);
}
#Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
#Override
public Dimension getMinimumSize() {
return new Dimension(W, H * 2);
}
private void detectEdges(int[] srcPix, int[] trgPix) {
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
trgPix[y * W + x] = compColor(srcPix, x, y);
}
}
}
private int getRed(int col) {
return (col >> 16) & 255;
}
private int getGreen(int col) {
return (col >> 8) & 255;
}
private int getBlue(int col) {
return col & 255;
}
private int compColor(int[] srcPix, int x, int y) {
int red = 0;
int green = 0;
int blue = 0;
int cnt = 0;
final int IDX = y * W + x;
final int RED = getRed(srcPix[IDX]);
final int GREEN = getGreen(srcPix[IDX]);
final int BLUE = getBlue(srcPix[IDX]);
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (dx != 0 || dy != 0) {
final int X = x + dx;
final int Y = y + dy;
final int LOCAL_IDX = Y * W + X;
if (0 <= X && X < W && 0 <= Y && Y < H) {
++cnt;
red += Math.abs(RED - getRed(srcPix[LOCAL_IDX]));
green += Math.abs(GREEN - getGreen(srcPix[LOCAL_IDX]));
blue += Math.abs(BLUE - getBlue(srcPix[LOCAL_IDX]));
}
}
}
}
return 0xff000000 | (255 - (red / cnt) << 16) | (255 - (green / cnt) << 8) | (255 - (blue / cnt));
}
public static void main(String[] args) throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.getContentPane().add(new Edge(f));
f.pack();
f.setVisible(true);
}
}
You need to grab.grabPixels(), not grab.getPixels().
http://docs.oracle.com/javase/7/docs/api/java/awt/image/PixelGrabber.html
Also what trashgod said about Initial Threads. You need to create your GUI with SwingUtilities.invokeLater().
Edit
The method is executed correctly but you are getting all black values on the input because your pixel array contains only the initialized values which is 0.