I'm trying to implement flood fill algorithm using to fill the closed shape with specific color.
I think my code is worked out, but i don't know why are"StackOverflowError" rising up !!
i looked for the solution more and more but without finding the perfect answer.
public void paintComponent(Graphics g){
indecies.clear();
float x1 = 20;
float y1 = 20;
float x2 = 350;
float y2 = 20;
/* put the points of first line in ArraList */
for(int i = (int) x1; i < x2 ; i++){
index = (int) (i + y1 * img.getWidth());
list.add(index);
}
/***************************************************/
x1 = 350;
y1 = 20;
x2 = 100;
y2 = 100;
/* put the points of second line in ArraList */
for(int i = (int) y1; i <= y2 ; i++){
index = (int) (x1 * img.getWidth());
list.add(index);
}
/***************************************************/
x1 = 100;
y1 = 100;
x2 = 20;
y2 = 100;
/* put the points of the third line in ArraList */
for(int i = (int) x2; i < x1 ; i++){
index = (int) (i + y1 * img.getWidth());
list.add(index);
}
/*****************************************************/
x1 = 20;
y1 = 100;
x2 = 20;
y2 = 20;
/* put the points of the forth line in ArraList */
for(int i = (int) y2; i < y1 ; i++){
index = (int) (x1 * img.getWidth());
list.add(index);
}
/**************************************************/
/* Get each pixel from ArrayList of indecies then print into data raster of image */
for (Integer integer : indecies) {
pixels[integer] = Color.yellow.getRGB();
}
/* Flood fill recursive algorithm */
/* border color is yellow */
/* green is the new colow must be filled inside the shape */
fill(50, 50, Color.yellow.getRGB(), Color.green.getRGB());
g.drawImage(img, 0, 0, this);
}
Here is the fill method !!
public void fill(int x, int y, int borderColor, int newColor){
if(x >= 0 && x < width && y >= 0 && y < height){
int index = x + y * width;
if(pixels[index] != borderColor && pixels[index] != newColor){
pixels[index] = newColor;
fill(x, y - 1, borderColor, newColor);
fill(x, y + 1, borderColor, newColor);
fill(x + 1, y, borderColor, newColor);
fill(x - 1, y, borderColor, newColor);
}
}
}
Exception Details ..
java.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowErrorjava.lang.StackOverflowError
at java.nio.Buffer.limit(Buffer.java:274)
at java.nio.Buffer.<init>(Buffer.java:201)
at java.nio.CharBuffer.<init>(CharBuffer.java:281)
at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:70)
at java.nio.CharBuffer.wrap(CharBuffer.java:373)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:823)
at java.lang.Throwable$WrappedPrintStream.println(Throwable.java:748)
at java.lang.Throwable.printStackTrace(Throwable.java:655)
at java.lang.Throwable.printStackTrace(Throwable.java:643)
at java.lang.Throwable.printStackTrace(Throwable.java:634)
at FillColorAlgorithm.fill(FillColorAlgorithm.java:170)
at FillColorAlgorithm.fill(FillColorAlgorithm.java:162)
......... etc
public void floodFill(int x, int y, int borderColor, int fillColor, int imgWidth, int imgHeight){
Queue<java.awt.Point> nodesList = new LinkedList<>();
if(borderColor == fillColor) return;
if(x >= 0 && x < imgWidth && y >= 0 && y < imgHeight){
int index = x + y * imgWidth;
if(pixels[index] == fillColor) return;
nodesList.add(new java.awt.Point(x, y));
}
while(!nodesList.isEmpty()) {
java.awt.Point currentNode = nodesList.element();
int index = currentNode.x + currentNode.y * imgWidth;
if(pixels[index] != fillColor){
java.awt.Point westNode = currentNode;
java.awt.Point eastNode = currentNode;
westNode = MoveWest(westNode, borderColor);
eastNode = MoveEast(eastNode, borderColor);
for (int j = westNode.x + 1; j < eastNode.x; j++) {
index = j + currentNode.y * imgWidth;
pixels[index] = fillColor;
java.awt.Point northNode = new java.awt.Point(j, currentNode.y - 1);
java.awt.Point southNode = new java.awt.Point(j, currentNode.y + 1);
index = northNode.x + northNode.y * imgWidth;
if(northNode.y >= 0 && pixels[index] != fillColor && pixels[index] != borderColor) nodesList.add(northNode);
index = southNode.x + southNode.y * imgWidth;
if(southNode.y < imgHeight && pixels[index] != fillColor && pixels[index] != borderColor) nodesList.add(southNode);
}
}
nodesList.remove();
}
}
java.awt.Point MoveWest(java.awt.Point w, int borderColor){
int index;
do{
--w.x;
index = w.x + w.y * width;
}
while(w.x >= 0 && pixels[index] != borderColor);
return new java.awt.Point(w.x, w.y);
}
java.awt.Point MoveEast(java.awt.Point e, int borderColor){
int index;
do{
++e.x;
index = e.x + e.y * width;
}
while( e.x < width && pixels[index] != borderColor);
return new java.awt.Point(e.x, e.y);
}
I have little experience with java programming, but I know my way around it a little. I want to pick up a project that was left behind by someone else. I was doing well fixing other errors here and there, but this one stumped me. Here it is:
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at Replacer.main(Replacer.java:19)
To my surprise, the program still opened. However, when I tried to open a picture, this happened, and displayed a picture of 0 x 0 pixels:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException:
2147483647
at ImageEditor.resize(ImageEditor.java:384)
at ImageEditor.resize(ImageEditor.java:308)
at ImageFrame.setImage(ImageFrame.java:438)
at ImageFrame.actionPerformed(ImageFrame.java:765)
at java.awt.Button.processActionEvent(Unknown Source)
at java.awt.Button.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Replacer:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.PrintStream;
import javax.imageio.ImageIO;
public class Replacer
{
public static void main(String[] args)
{
BufferedImage i = null;
BufferedImage i2 = null;
Color[][] blockColors = new Color[16][16];
ImageFrame b = new ImageFrame(i);
try
{
i2 = ImageIO.read(new File("terrain.png"));
int blockSize = i2.getWidth(b) / 16;
System.out.println("Analyzing terrain.png");
int[] buffer = ImageEditor.returnBuffer(i2, b);
int width = i2.getWidth(b);
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
if ((j <= 2) || (k <= 8))
{
int[] i3 = ImageEditor.crop(buffer, width, width, b, j * blockSize, k * blockSize, blockSize, blockSize);
blockColors[j][k] = ImageEditor.getAverageColor(i3, b);
}
}
}
Color[] c2 = new Color[100];
c2[0] = blockColors[1][8];
c2[1] = blockColors[2][10];
c2[2] = blockColors[1][11];
c2[3] = blockColors[1][9];
c2[4] = blockColors[1][7];
c2[5] = blockColors[0][4];
c2[6] = blockColors[2][13];
c2[7] = blockColors[1][13];
c2[8] = blockColors[1][12];
c2[9] = blockColors[2][7];
c2[10] = blockColors[2][11];
c2[11] = blockColors[2][8];
c2[12] = blockColors[2][9];
c2[13] = blockColors[2][12];
c2[14] = blockColors[1][14];
c2[15] = blockColors[1][10];
c2[16] = blockColors[1][0];
c2[17] = blockColors[2][0];
c2[18] = blockColors[2][1];
c2[19] = blockColors[3][1];
c2[20] = blockColors[8][4];
c2[21] = blockColors[5][2];
c2[22] = blockColors[4][2];
c2[23] = blockColors[6][7];
c2[24] = blockColors[4][0];
c2[25] = blockColors[0][1];
c2[26] = blockColors[0][11];
c2[27] = blockColors[7][0];
c2[28] = blockColors[6][1];
c2[29] = blockColors[7][1];
c2[30] = blockColors[8][1];
c2[31] = blockColors[0][9];
c2[32] = blockColors[10][4];
c2[33] = blockColors[9][6];
c2[34] = blockColors[7][6];
c2[35] = blockColors[8][6];
c2[36] = blockColors[2][4];
c2[37] = blockColors[6][3];
c2[38] = blockColors[1][1];
c2[39] = blockColors[5][1];
c2[40] = blockColors[4][1];
c2[41] = blockColors[4][7];
c2[42] = blockColors[5][7];
c2[43] = blockColors[0][3];
c2[44] = blockColors[3][4];
c2[45] = blockColors[8][8];
c2[46] = blockColors[8][9];
c2[47] = blockColors[8][10];
c2[48] = blockColors[8][11];
c2[49] = blockColors[8][12];
for (int j = 0; j < c2.length / 2; j++)
{
double shadowRed = 0.892D * c2[j].getRed() + 0.5D;
double shadowGreen = 0.892D * c2[j].getGreen() + 0.5D;
double shadowBlue = 0.892D * c2[j].getBlue() + 0.5D;
c2[(50 + j)] = new Color((int)shadowRed, (int)shadowGreen, (int)shadowBlue);
}
for (int j = 0; j < c2.length; j++) {
System.out.println("colors[" + j + "] = new Color(" + c2[j].getRed() + "," + c2[j].getGreen() + "," + c2[j].getBlue() + ");");
}
b.setColors(c2);
System.out.println("Done");
}
catch (Exception e)
{
e.printStackTrace();
}
b.repaint();
}
}
ImageEditor:
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.PrintStream;
public class ImageEditor
{
public static int[] returnBuffer(Image i, Component c)
{
MediaTracker tracker = new MediaTracker(c);
tracker.addImage(i, 0);
try
{
tracker.waitForAll();
}
catch (Exception e)
{
System.out.println("Image loading interrupted");
}
int width = i.getWidth(c);
int height = i.getHeight(c);
int[] buffer = new int[width * height];
PixelGrabber grabber = new PixelGrabber(i, 0, 0, width, height, buffer, 0, width);
try
{
grabber.grabPixels();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return buffer;
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors(width, height, buffer, c, colors, w);
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors2(i, buffer, c, colors, w);
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors, double[] weights)
{
int height = i.getHeight(c);
int width = i.getWidth(c);
int[] simple = new int[buffer.length];
float[] hsb1 = new float[3];
float[] hsb2 = new float[3];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
hsb1 = Color.RGBtoHSB(current.getRed(), current.getGreen(), current.getBlue(), null);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
if (test != null)
{
hsb2 = Color.RGBtoHSB(test.getRed(), test.getGreen(), test.getBlue(), null);
int diff = (int)(Math.pow(hsb1[0] - hsb2[0], 2.0D) + Math.pow(hsb1[1] - hsb2[1], 2.0D) + Math.pow(hsb1[2] - hsb2[2], 2.0D));
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
k2 = k;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
k2 = k;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image resize(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int getResizedHeight(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return newDim;
}
return (int)(newDim * 1.0D * h / w);
}
public static int getResizedWidth(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return (int)(newDim * 1.0D * w / h);
}
return newDim;
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resizebuff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resizebuff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize2(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2buff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2buff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return resized;
}
public static Image resize2(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resize(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resizebuff(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return resized;
}
public static int[] countColors(int[] buffer, Component c, Color[] colors)
{
int[] count = new int[colors.length];
for (int k = 0; k < count.length; k++) {
count[k] = 0;
}
Color col = Color.BLACK;
for (int j = 0; j < buffer.length; j++)
{
col = new Color(buffer[j]);
for (int k = 0; k < colors.length; k++) {
if ((colors[k] != null) && (colors[k].getRGB() == col.getRGB())) {
count[k] += 1;
}
}
}
return count;
}
(Had to cut it off b/c of character limit)
EDIT: Turns out the first error doesn't matter. The program tries to run textures from a separate file. If it isn't found, it skips it.
Any help is appreciated.
Addressing your second issue with the stack trace:
This line is your issue:
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
Specifically this part resized[(y * newWidth + x)] because [y * newWidth + x] can be far bigger than what resized allows.
Let's assume the image is 100x50 (WxH), this means that int[] resized = new int[newHeight * newWidth]; will create a new array that is 5000 long.
However the for loops will create something much higher:
for (int y = 0; y < newHeight; y++) in this instance y will go as high as newHeight or 100
vfor (int x = 0; x < newWidth; x++)in this instanceywill go as high asnewWidth` or 50
So:
resized[(y * newWidth + x)] = something; will be an issue because 100 * 100 + 50 can be as large as 10050, that is far bigger than 5000.
The solution is to make a larger resized array, or to rethink your for loops.
I am writing Canny's Algorithm, and I seem to have an issue with hysteresis. The Thresholds Appears to process, however my hysteresis does not seem to function at all. As well as method remove weak for some odd reason. Please help!
Low # 10
High # 75
After Hysteresis, with problem A, edges were not strengthen with method performHysteresis; B weak non-edges are not removed with method removeWeak.
Source code for the method as follows:
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
class CannyMethod {
private static final float[] sobelX = { 1.0f, 0.0f, -1.0f,
2.0f, 0.0f, -2.0f,
1.0f, 0.0f, -1.0f};
private static final float[] sobelY = { 1.0f, 2.0f, 1.0f,
0.0f, 0.0f, 0.0f,
-1.0f,-2.0f,-1.0f};
private static int low, high;
public CannyMethod() {}
private ConvolveOp getSobel(boolean xy) {
Kernel kernel;
if (xy) kernel = new Kernel(3, 3, sobelX);
else kernel = new Kernel(3, 3, sobelY);
return new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null);
}
public BufferedImage getCannyFilter(BufferedImage img) {
return getCannyFilter(img, low, high);
}
public BufferedImage getCannyFilter(BufferedImage img, int l, int h) {
int width = img.getWidth();
int height = img.getHeight();
low = l;
high = h;
int size = width * height;
int[] x = new int[size];
int[] y = new int[size];
int[] pixelM = new int[size];
double[] pixelD = new double[size];
int[] pixelNew = new int[size];
BufferedImage sobelXImg = getSobel(true).filter(img, null);
BufferedImage sobelYImg = getSobel(false).filter(img, null);
// returns arrays for x and y direction after convultion with Sobel Operator
sobelXImg.getRaster().getPixels(0, 0, width, height, x);
sobelYImg.getRaster().getPixels(0, 0, width, height, y);
// Calculates Gradient and Magnitude
for(int i = 0; i < size; i++) {
pixelM[i] = (int) Math.hypot(x[i], y[i]);
pixelD[i] = Math.atan2((double) y[i], (double) x[i]);
}
//Operations for Canny Algorithm takes magnitude and gradient and input into new array fo WritableRaster
normalizeDirection(pixelD);
nonMaximaSupression(pixelM, pixelD, pixelNew, width, height);
performHysteresis(pixelNew, width);
removeWeak(pixelNew);
BufferedImage result =
new BufferedImage(width, height,
BufferedImage.TYPE_BYTE_GRAY);
result.getRaster().setPixels(0, 0, width, height, pixelNew);
return result;
}
private void normalizeDirection(double[] dArray) {
//Round degrees
double pi = Math.PI;
for(double i : dArray) {
if (i < pi/8d && i >= -pi/8d) i = 0;
else if (i < 3d*pi/8d && i >= pi/8d) i = 45;
else if (i < -3d*pi/8d || i >= 3d*pi/8d) i = 90;
else if (i < -pi/8d && i >= -3d*pi/8d) i = 135;
}
}
private void nonMaximaSupression(int[] pixelM, double[] pixelD,
int[] pixelNew, int width, int height) {
//non-Maxima Supression
//Since array is not in 2-D, positions are calulated with width - functions properly
for(int i = 0; i < pixelNew.length; i++) {
if (i % width == 0 || (i + 1) % width == 0 ||
i <= width || i >= width * height - 1) pixelNew[i] = 0;
else {
switch ((int) pixelD[i]) {
case 0: if (pixelM[i] > pixelM[i+1]
&& pixelM[i] > pixelM[i-1])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 45: if (pixelM[i] > pixelM[i+(width-1)]
&& pixelM[i] > pixelM[i-(width-1)])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 90: if (pixelM[i] > pixelM[i+width]
&& pixelM[i] > pixelM[i-width])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 135:if (pixelM[i] > pixelM[i+width]
&& pixelM[i] > pixelM[i-width])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
default: pixelNew[i] = 0;
}
}
}
}
private void performHysteresis(int[] array, int width) {
//performs hysteresis
int[] temp;
for(int i = width; i < array.length - width; i++) {
if (i % width == 0 || (i + 1) % width == 0) {}
else {
if (array[i] == 255) {
//found strong one, track surrounding weak ones
//temp is the positions of surrounding pixels
temp = new int[]
{i - (width + 1), i - width, i - (width - 1),
i - 1, i + 1,
i + (width - 1), i + width, i + (width + 1)};
trackWeak(array, temp, width);
}
}
}
}
private void trackWeak(int[] array, int[] pos, int width) {
int[] temp;
for (int i : pos) {
if (array[i] > 0 && array[i] < 255) {
array[i] = 255;
//set weak one to strong one
if (i % width == 0 || (i + 1) % width == 0) {}
else {
//temp is the positions of surrounding pixels
temp = new int[]
{i - (width + 1), i - width, i - (width - 1),
i - 1, i + 1,
i + (width - 1), i + width, i + (width + 1)};
trackWeak(array, temp, width);
}
}
}
}
private void removeWeak(int[] array) {
//remove remaining weak ones from lew Threshold
for(int i : array) {
if (i < 255) {i = 0;}
}
}
private void setPixel(int pos, int value, int[] pixelNew) {
if (value > high) pixelNew[pos] = 255;
else if (value > low) pixelNew[pos] = 128;
else pixelNew[pos] = 0;
}
public void setThreshold(int l, int h) {
low = l;
high = h;
}
}
I figured it out. The hysteresis was working, it was just hard to tell given the quality of the image.
As for the remove weak, I used the enhanced for loop which I am starting to see that only a copy of the element is obtained and changed, not actually the element in the array itself. Once I changed that to a regular for loop it worked!
I have a set of bitmaps. They are all transparent to some extent, and I don't know in advance which parts are transparent. I would like to create a new bitmap out of the original bitmap that excludes the transparent parts, but in a square. I think this image explains it:
I know how to create a bitmap out of a existing bitmap, but I don't know how to find out which part is transparent and how to use that to achieve my goal.
This is how I plan on doing this:
public Bitmap cutImage(Bitmap image) {
Bitmap newBitmap = null;
int width = image.getWidth();
int height = image.getHeight();
newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
//This is where I need to find out correct values of r1 and r1.
Rect r1 = new Rect(?, ?, ?, ?);
Rect r2 = new Rect(?, ?, ?, ?);
canvas.drawBitmap(image, r1, r2, null);
return newBitmap;
}
Does anyone know how to achieve this?
EDIT:
I got it work using the following algorithm to find left, right, top and bottom values:
private int x1;
private int x2;
private int y1;
private int y2;
private void findRectValues(Bitmap image)
{
for(int x = 0; x < image.getWidth(); x++)
{
for(int y = 0; y < image.getHeight(); y++)
{
if(image.getPixel(x, y) != Color.TRANSPARENT)
{
System.out.println("X1 is: " + x);
x1 = x;
break;
}
}
if(x1 != 0)
break;
}
for(int x = image.getWidth()-1; x > 0; x--)
{
for(int y = 0; y < image.getHeight(); y++)
{
if(image.getPixel(x, y) != Color.TRANSPARENT)
{
System.out.println("X2 is: " + x);
x2 = x;
break;
}
}
if(x2 != 0)
break;
}
for(int y = 0; y < image.getHeight(); y++)
{
for(int x = 0; x < image.getWidth(); x++)
{
if(image.getPixel(x, y) != Color.TRANSPARENT)
{
System.out.println("Y1 is: " + y);
y1 = y;
break;
}
}
if(y1 != 0)
break;
}
for(int y = image.getHeight()-1; y > 0; y--)
{
for(int x = 0; x < image.getWidth(); x++)
{
if(image.getPixel(x, y) != Color.TRANSPARENT)
{
System.out.println("Y2 is: " + y);
y2 = y;
break;
}
}
if(y2 != 0)
break;
}
}
i think this is a bit more efficient and it works great for me
public Bitmap cropBitmapToBoundingBox(Bitmap picToCrop, int unusedSpaceColor) {
int[] pixels = new int[picToCrop.getHeight() * picToCrop.getWidth()];
int marginTop = 0, marginBottom = 0, marginLeft = 0, marginRight = 0, i;
picToCrop.getPixels(pixels, 0, picToCrop.getWidth(), 0, 0,
picToCrop.getWidth(), picToCrop.getHeight());
for (i = 0; i < pixels.length; i++) {
if (pixels[i] != unusedSpaceColor) {
marginTop = i / picToCrop.getWidth();
break;
}
}
outerLoop1: for (i = 0; i < picToCrop.getWidth(); i++) {
for (int j = i; j < pixels.length; j += picToCrop.getWidth()) {
if (pixels[j] != unusedSpaceColor) {
marginLeft = j % picToCrop.getWidth();
break outerLoop1;
}
}
}
for (i = pixels.length - 1; i >= 0; i--) {
if (pixels[i] != unusedSpaceColor) {
marginBottom = (pixels.length - i) / picToCrop.getWidth();
break;
}
}
outerLoop2: for (i = pixels.length - 1; i >= 0; i--) {
for (int j = i; j >= 0; j -= picToCrop.getWidth()) {
if (pixels[j] != unusedSpaceColor) {
marginRight = picToCrop.getWidth()
- (j % picToCrop.getWidth());
break outerLoop2;
}
}
}
return Bitmap.createBitmap(picToCrop, marginLeft, marginTop,
picToCrop.getWidth() - marginLeft - marginRight,
picToCrop.getHeight() - marginTop - marginBottom);
}
If all the images you want to crop are more or less in the center of the original canvas, I guess you could so something like this:
Start from each border working your way inwards the image searching for non-transparent pixels
Once you've found the top-left pixel and the right-bottom, you'll have your desired target.
Copy the image as you please
Now, the question remains is what you consider a transparent pixel. Does alpha trasparency counts? if so, how much alpha until you decide it's transparent enough to be cut from the image?
To find the non-transparent area of your bitmap, iterate across the bitmap in x and y and find the min and max of the non-transparent region. Then crop the bitmap to those co-ordinates.
Bitmap CropBitmapTransparency(Bitmap sourceBitmap)
{
int minX = sourceBitmap.getWidth();
int minY = sourceBitmap.getHeight();
int maxX = -1;
int maxY = -1;
for(int y = 0; y < sourceBitmap.getHeight(); y++)
{
for(int x = 0; x < sourceBitmap.getWidth(); x++)
{
int alpha = (sourceBitmap.getPixel(x, y) >> 24) & 255;
if(alpha > 0) // pixel is not 100% transparent
{
if(x < minX)
minX = x;
if(x > maxX)
maxX = x;
if(y < minY)
minY = y;
if(y > maxY)
maxY = y;
}
}
}
if((maxX < minX) || (maxY < minY))
return null; // Bitmap is entirely transparent
// crop bitmap to non-transparent area and return:
return Bitmap.createBitmap(sourceBitmap, minX, minY, (maxX - minX) + 1, (maxY - minY) + 1);
}