I have written this piece of code to break an image into 9 pieces and it gives me runtime error. There is no error in LogCat and I am stuck. The error comes at line 7 line from bottom (Bitmap.createBitmap(...);).
public Bitmap[] getPieces(Bitmap bmp) {
Bitmap[] bmps = new Bitmap[9];
int width = bmp.getWidth();
int height = bmp.getHeight();
int rows = 3;
int cols = 3;
int cellHeight = height / rows;
int cellWidth = width / cols;
int piece = 0;
for (int x = 0; x <= width; x += cellWidth) {
for (int y = 0; y <= height; y += cellHeight) {
Bitmap b = Bitmap.createBitmap(bmp, x, y, cellWidth,
cellHeight, null, false);
bmps[piece] = b;
piece++;
}
}
return bmps;
}
It is a limitation of android framework which doesn't give proper error message. The ideal solution would be to wrap your code in try / catch block and log the exception to console and fix your code accordingly, but use it only for debugging purposes.
try {
// Code
}
catch (Exception e) {
Log.e("ERROR", "ERROR IN CODE:"+e.toString());
}
The above code extracted from here:
http://moazzam-khan.com/blog/?p=41
Instead of
for (int x = 0; x <= width; x += cellWidth) {
for (int y = 0; y <= height; y += cellHeight) {
use
for (int x = 0; x+cellWidth < width; x += cellWidth) {
for (int y = 0; y+cellHeight < height; y += cellHeight) {
to avoid fetching parts of the image that (at least partly) don't exist.
In your code, piece can be greater than 8, so you are getting index out of bounds on bmps. You need to rewrite it so that the right-most and bottom-most pieces just have all of the extra and aren't necessarily the same size.
Or, if you need them to be the same size, drop the extra rows/cols. To make sure, I would formulate my for loop like this
for (int cellX = 0; cellX < 3; cellX++) {
int x = cellX * cellWidth;
for (int cellY = 0; cellY < 3; cellY++) {
int y = cellY * cellHeight;
// find the cellWidth/Height that doesn't overflow the original image
Bitmap b = // get the bitmap
bmps[piece] = b;
piece++;
}
}
Related
I am new to Perlin noise and I have hit a roadblock. The perlin noise function I have translated from C++ seems to work correctly for one octave, however I have found that the lower octaves of noise aren't added to the original Perlin Noise. Here is my code:
public class Perlin {
float[][] generateWhiteNoise(int width, int height) {
Random random = new Random(0);
float[][] noise = new float[width][height];
for (int i = 0; i < noise.length; i++) {
for (int j = 0; j < noise[i].length; j++){
noise[i][j] = (float)random.nextDouble();
}
}
return noise;
}
float[][] generateSmoothNoise(float[][] baseNoise, int octave){
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][] smoothNoise = baseNoise;
int samplePeriod = (int) Math.pow(2,octave); // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++) {
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++){
//calculate the vertical sampling indices
int sample_j0 = (j / samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float interpolate(float x0, float x1, float alpha){
return (float) ((float)(x0) * (float)(1 - alpha) + (float)(alpha * x1));
}
float[][] generatePerlinNoise(float[][] baseNoise, int octaveCount) {
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = .5f;
//generate smooth noise
for (int i = 0; i<octaveCount; i++) {
System.out.println("Generating Smooth Noise: " + i);
smoothNoise[i] = generateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[width][height];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--) {
amplitude *= persistance;
totalAmplitude += amplitude;
System.out.println("Adding smooth noise for octave: " + octave + " at amplitude: " + amplitude);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalization
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
public float[][] printVals(float[][] baseNoise){
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
for(int i = 0; i<baseNoise.length; i++){
String row = "";
for(int j = 0; j<baseNoise[i].length;j++){
row+= (int)(baseNoise[i][j]*255) + " ";
}
System.out.println(row);
}
return baseNoise;
}
}
Here is the code in that I use to get values:
baseNoise = generatePerlinNoise(generateWhiteNoise(800,800),6);
Here are the outputs at octaves 1,2,3, and 4
Any help would be appreciated!
Edit:
Through trial and error, I have found that the most likely area for there to be problems is in the generatePerlinNoise() function. If I change the octaves, I get the desired noise level, which is what I want. That also means that the generateWhiteNoise() and generateSmoothNoise() works. So, somewhere within the generatePerlinNoise() blending there is a problem, but it seems like it should work.
I have found an answer. I had thought that the generateSmoothNoise() command was going to give me multi-octave perlin noise. However, I realized that I needed to build another command similar to what happens with the blending of the smooth noise to blend my different octaves of perlin noise.
public float[][] generateMultiOctavePerlinNoise(int octaves, double persistence, double dropoff, int width, int height){
float[][][]noise = new float[octaves][width][height];
for(int i = octaves - 1; i > 0;i--){
noise[i] = generatePerlinNoise(generateWhiteNoise(width,height),octaves - i);
}
float[][] multiOctave = new float[width][height];
for(int a= 0; a<noise.length; a++){
persistence*= dropoff;
for(int i = 0; i<multiOctave.length; i++){
for(int j = 0; j<multiOctave[i].length; j++){
multiOctave[i][j] += noise[a][i][j]*persistence;
}
}
}
return multiOctave;
}
I want to get number of all red pixels on bitmap image, after I painted on it and merged with back image.
How can I do that? Please give me more details, I will be very grateful, thank you!
Example: Count of red pixels
Iterate through every single pixel in the bitmap
//define your red
static final int RED = Color.RED;
//counting
int count = 0;
for (int x = 0; x <= myBitmap.getWidth(); x++) {
for (int y = 0; x <= myBitmap.getHeight(); y++) {
if(myBitmap.getPixel(x, y))
count++;
}
}
//done. use the variable count
You have a Bitmap, you can get a pixel color from it using code below:
int countX = bitmap.getWidth();
int countY = bitmap.getHeight();
int redCount = 0;
for (int x = 0; x < countX; x++) {
for (int y = 0; y < countY; y--) {
int colorXY = bitmap.getPixel(x, y);
redCount += Color.red(colorXY);
}
}
I got something like this:
int countX = bm.getWidth();
int countY = bm.getHeight();
int redCount = 0;
for (int rangeX = 0; rangeX < countX; rangeX++) {
for (int rangeY = 0; rangeY < countY; rangeY++) {
int colorXY = bm.getPixel(rangeX, rangeY);
int r = Color.red(colorXY);
int g = Color.green(colorXY);
int b = Color.blue(colorXY);
if(Color.rgb(r,g,b) == Color.RED) {
redCount++;
/*bm.setPixel(rangeX,rangeY,Color.GREEN);*/
}
}
}
i want to paint black and white stripes on the image, switching every 20th column both horizontally and vertically on top of an image while staying inside it's borders. so far i can get a black square with 1 pixel wide vertical stripes. i've tried to at least get skinny white stripes on my horizontal lines by switching things around but it's still vertical.
public void zebraStripes() {
Image img = ImageViewer.getImage();
double numPixelsWide = img.getWidth();
int numPixelsHigh = img.getHeight();
Color c = Color.WHITE;
Color b = Color.BLACK;
double i = numPixelsWide;
if (i % 20 == 0) {
for (int x = 0; x < numPixelsHigh; x++) {
for (int y = 0; y < i; y++) {
img.setPixelColor(y, x, b);
}
for (int z = 19; z < i; z = z + 20) {
img.setPixelColor(z, x, c);
}
}
}
}
// paint black and white stripes (left to right) on the image, switching
// every 20th row
public void jailBird() {
Image img = ImageViewer.getImage();
double numPixelsWide = img.getWidth();
double numPixelsHigh = img.getHeight();
Color c = Color.WHITE;
Color b = Color.BLACK;
double i = numPixelsHigh;
if (i % 20 == 0) {
for (int x = 0; x < numPixelsHigh; x++) {
for (int y = 0; y < i; y++) {
img.setPixelColor(y, x, b);
}
for (int z = 19; z < i; z = z + 20) {
img.setPixelColor(z, x, c);
}
}
}
}
}
how do i get the white stripes to be 20 pixels wide and horizontal?
Not tested! Hope it gets you going.
// paint a 20 pixels wide horizontal line for every 40 pixels
for (int y = 0; y < numPixelsHigh; y += 40) {
// paint a stripe
for (int ys = y; ys < y + 20; ys++) {
for (int x = 0; x < numPixelsWide; x++) {
img.setPixelColor(x, ys, Color.BLACK);
}
}
}
I cant seem to figure it out is it possible that someone can tell me why?
public class Display {
private int width,height;
public int [] pixels;
public int [] tiles = new int[64 * 64];
private Random random = new Random();
public Display(int width, int height) {
this.width = width;
this.height = height;
pixels = new int [width*height]; // 50400
for (int i = 0; i < 64 * 64; i++) {
tiles[i] = random.nextInt (0xffffff);
}
}
public void clear() {
for (int i = 0; i < pixels.length; i++) {
tiles[i] = random.nextInt (0xffffff);
}
}
public void render() {
for (int y = 0; y <height; y++) {
if (y < 0 || y >= height) break;
for (int x = 0; x < width; x++) {
if (x < 0 || x >=width) break;
int tileIndex = (x / 16) + (y / 16) * 64;
pixels[x+y*width] = tiles[tileIndex];
}
}
}
}
The ArrayIndexOutOfBoundsException is likely to occur at the assignment in the clear() method.
You are iterating from 0 to pixels.length. pixels.length is variable-sized (according to what is passed to the constructor). While iterating you assign values to tiles[i]. Tiles is a fixed sized array (64*64 = 4.096 entries). If width*height > 4096, the clear() method will fail if it tries to access tiles[4096] or above.
Maybe you wanted to iterate up to tiles.length only?
I have a sprite sheet which has each image centered in a 32x32 cell. The actual images are not 32x32, but slightly smaller. What I'd like to do is take a cell and crop the transparent pixels so the image is as small as it can be.
How would I do that in Java (JDK 6)?
Here is an example of how I'm currently breaking up the tile sheet into cells:
BufferedImage tilesheet = ImageIO.read(getClass().getResourceAsStream("/sheet.png");
for (int i = 0; i < 15; i++) {
Image img = tilesheet.getSubimage(i * 32, 0, 32, 32);
// crop here..
}
My current idea was to test each pixel from the center working my way out to see if it is transparent, but I was wondering if there would be a faster/cleaner way of doing this.
There's a trivial solution – to scan every pixel. The algorithm bellow has a constant performance of O(w•h).
private static BufferedImage trimImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int top = height / 2;
int bottom = top;
int left = width / 2 ;
int right = left;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (image.getRGB(x, y) != 0){
top = Math.min(top, y);
bottom = Math.max(bottom, y);
left = Math.min(left, x);
right = Math.max(right, x);
}
}
}
return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
}
But this is much more effective:
private static BufferedImage trimImage(BufferedImage image) {
WritableRaster raster = image.getAlphaRaster();
int width = raster.getWidth();
int height = raster.getHeight();
int left = 0;
int top = 0;
int right = width - 1;
int bottom = height - 1;
int minRight = width - 1;
int minBottom = height - 1;
top:
for (;top <= bottom; top++){
for (int x = 0; x < width; x++){
if (raster.getSample(x, top, 0) != 0){
minRight = x;
minBottom = top;
break top;
}
}
}
left:
for (;left < minRight; left++){
for (int y = height - 1; y > top; y--){
if (raster.getSample(left, y, 0) != 0){
minBottom = y;
break left;
}
}
}
bottom:
for (;bottom > minBottom; bottom--){
for (int x = width - 1; x >= left; x--){
if (raster.getSample(x, bottom, 0) != 0){
minRight = x;
break bottom;
}
}
}
right:
for (;right > minRight; right--){
for (int y = bottom; y >= top; y--){
if (raster.getSample(right, y, 0) != 0){
break right;
}
}
}
return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
}
This algorithm follows the idea from pepan's answer (see above) and is 2 to 4 times more effective. The difference is: it never scans any pixel twice and tries to contract search range on each stage.
The worst case of the method's performance is O(w•h–a•b)
This code works for me. The algorithm is simple, it iterates from left/top/right/bottom of the picture and finds the very first pixel in the column/row which is not transparent. It then remembers the new corner of the trimmed picture and finally it returns the sub image of the original image.
There are things which could be improved.
The algorithm expects, there is the alpha byte in the data. It will fail on an index out of array exception if there is not.
The algorithm expects, there is at least one non-transparent pixel in the picture. It will fail if the picture is completely transparent.
private static BufferedImage trimImage(BufferedImage img) {
final byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
int width = img.getWidth();
int height = img.getHeight();
int x0, y0, x1, y1; // the new corners of the trimmed image
int i, j; // i - horizontal iterator; j - vertical iterator
leftLoop:
for (i = 0; i < width; i++) {
for (j = 0; j < height; j++) {
if (pixels[(j*width+i)*4] != 0) { // alpha is the very first byte and then every fourth one
break leftLoop;
}
}
}
x0 = i;
topLoop:
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
if (pixels[(j*width+i)*4] != 0) {
break topLoop;
}
}
}
y0 = j;
rightLoop:
for (i = width-1; i >= 0; i--) {
for (j = 0; j < height; j++) {
if (pixels[(j*width+i)*4] != 0) {
break rightLoop;
}
}
}
x1 = i+1;
bottomLoop:
for (j = height-1; j >= 0; j--) {
for (i = 0; i < width; i++) {
if (pixels[(j*width+i)*4] != 0) {
break bottomLoop;
}
}
}
y1 = j+1;
return img.getSubimage(x0, y0, x1-x0, y1-y0);
}
I think this is exactly what you should do, loop through the array of pixels, check for alpha and then discard. Although when you for example would have a star shape it will not resize the image to be smaller be aware of this.
A simple fix for code above. I used the median for RGB and fixed the min() function of x and y:
private static BufferedImage trim(BufferedImage img) {
int width = img.getWidth();
int height = img.getHeight();
int top = height / 2;
int bottom = top;
int left = width / 2 ;
int right = left;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (isFg(img.getRGB(x, y))){
top = Math.min(top, y);
bottom = Math.max(bottom, y);
left = Math.min(left, x);
right = Math.max(right, x);
}
}
}
return img.getSubimage(left, top, right - left, bottom - top);
}
private static boolean isFg(int v) {
Color c = new Color(v);
return(isColor((c.getRed() + c.getGreen() + c.getBlue())/2));
}
private static boolean isColor(int c) {
return c > 0 && c < 255;
}
[Hi I tried the following. In the images file idle1.png is the image with a big transparent box while testing.png is the same image with minimum bounding box
'BufferedImage tempImg = (ImageIO.read(new File(fileNPath)));
WritableRaster tempRaster = tempImg.getAlphaRaster();
int x1 = getX1(tempRaster);
int y1 = getY1(tempRaster);
int x2 = getX2(tempRaster);
int y2 = getY2(tempRaster);
System.out.println("x1:"+x1+" y1:"+y1+" x2:"+x2+" y2:"+y2);
BufferedImage temp = tempImg.getSubimage(x1, y1, x2 - x1, y2 - y1);
//for idle1.png
String filePath = fileChooser.getCurrentDirectory() + "\\"+"testing.png";
System.out.println("filePath:"+filePath);
ImageIO.write(temp,"png",new File(filePath));
where the get functions are
public int getY1(WritableRaster raster) {
//top of character
for (int y = 0; y < raster.getHeight(); y++) {
for (int x = 0; x < raster.getWidth(); x++) {
if (raster.getSample(x, y,0) != 0) {
if(y>0) {
return y - 1;
}else{
return y;
}
}
}
}
return 0;
}
public int getY2(WritableRaster raster) {
//ground plane of character
for (int y = raster.getHeight()-1; y > 0; y--) {
for (int x = 0; x < raster.getWidth(); x++) {
if (raster.getSample(x, y,0) != 0) {
return y + 1;
}
}
}
return 0;
}
public int getX1(WritableRaster raster) {
//left side of character
for (int x = 0; x < raster.getWidth(); x++) {
for (int y = 0; y < raster.getHeight(); y++) {
if (raster.getSample(x, y,0) != 0) {
if(x > 0){
return x - 1;
}else{
return x;
}
}
}
}
return 0;
}
public int getX2(WritableRaster raster) {
//right side of character
for (int x = raster.getWidth()-1; x > 0; x--) {
for (int y = 0; y < raster.getHeight(); y++) {
if (raster.getSample(x, y,0) != 0) {
return x + 1;
}
}
}
return 0;
}'[Look at Idle1.png and the minimum bounding box idle = testing.png][1]
Thank you for your help regards Michael.Look at Idle1.png and the minimum bounding box idle = testing.png]images here
If your sheet already has transparent pixels, the BufferedImage returned by getSubimage() will, too. The default Graphics2D composite rule is AlphaComposite.SRC_OVER, which should suffice for drawImage().
If the sub-images have a distinct background color, use a LookupOp with a four-component LookupTable that sets the alpha component to zero for colors that match the background.
I'd traverse the pixel raster only as a last resort.
Addendum: Extra transparent pixels may interfere with collision detection, etc. Cropping them will require working with a WritableRaster directly. Rather than working from the center out, I'd start with the borders, using a pair of getPixels()/setPixels() methods that can modify a row or column at a time. If a whole row or column has zero alpha, mark it for elimination when you later get a sub-image.