Extracting a rectangular pixel region from an image - java

I need to extract a pixel region described by (2n+1) x (2m+1) centred on leftimage (xl,yl). n and m are user input parameters and xl and yl are already defined. Thus far I have this code:
for(int xl = n; xl < picOneGreyScale.getWidth() - n; xl++) {
for(int yl = m; yl < picOneGreyScale.getHeight() - m; yl++) {
//extract (2n+1) x (2m+1) pixel region centred on leftimage (xl,yl);
for(int nArea = xl-n; nArea < xl+n+1; nArea++) {
for(int mArea = yl-m; mArea < yl+m+1; mArea++) {
*code here*
}
}
I'm uncertain as to how to continue. I have defined a BufferedImage called leftRegion:
BufferedImage leftRegion = new BufferedImage((2*n+1),(2*m+1),BufferedImage.TYPE_BYTE_GRAY);
which I intend to use to "extract" my pixel region into. My thoughts thus far are, for where it says code here to extract the pixel at the current location (using getRGB?) and then nesting another for loop to place this pixel within the correct x, y coordinates for leftRegion. I'm not sure how to do this however or if I'm thinking too complex. Alternatively it may be possible to use getRGB with extended arguments:
getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
instead of the two inner for loops but again I'm not so hot on how to implement this. Finally there is a method for BufferedImage called copyData which looks like it might be relevant but I'm not sure how to use it. What's the best way to implement this? Many thanks as always.
Additional Information:
Okay so I'm trying to use the getSubImage method of the BufferedImage class:
leftRegion = picOneGreyScale.getSubimage(xl, yl, (2*n+1), (2*m+1));
only I'm getting an error "(y + height) is outside of Raster". How does getSubImage work exactly? Will the image be centered around xl, yl with the width and height being extended equally either side, or does it work differently? Am I even following the right path?

I figured it out. I simply replaced the two inner for loops with this:
leftRegion = picOneGreyScale.getSubimage(xl-n, yl-n, (2*n+1), (2*m+1));

Related

How to scale a pixel-drawing function in Java

In Java, I have a function like this:
public void setPixel(int x, int y, boolean on);
It sets a virtual black and white pixel, given whether it is on or not.
How can I call this function so the resulting display will be four times larger?
I tried this:
int x = 3;
int y = 3;
setPixel(x, y, true);
setPixel(x+1, y+1, true);
setPixel(x+2, y+2, true);
setPixel(x+3, y+3, true);
But naturally, it overlapped when I tried to draw something. How should I call the method?
While I'm tagging this Java, the concept could apply to any language.
Answering on these assumptions: setPixel sets a single pixel to white or black (if on is true, to black, else to white). You want to use this function to get a B&W image and make it four times larger. The code you provided is wrong and just makes a diagonal instad of a 4x4 block. Is this correct? If so:
A way to draw a 4 times larger image would then be, for example, to have a "getPixel(x,y)" which gets you whether the pixel at (x,y) is on in the original image and then start painting somewhere else in 4x4 blocks. Whenever you move by one pixel in either X or Y direction when getting the values of your original image, you move by 4 in your new image to scale. So then what you intended to do maybe was something like this?
void setBlock(int x, int y, boolean on, int scale)
for(int i=0; i < scale; i++){
for(int j=0; j < scale; j++){
setPixel(scale*x + i, scale*y + j, on);
And then iterate over your original image's coordinates doing something like this?
setBlock(x, y, getPixel(x, y), 4);

How do I take out a specific card from a deck image?

I want to take out a card from my deck image. How can I do that without downloading every single card separately? I don't want to initialize all 52 cards in my class.
Right now, I randomize colour and value and then it finds the picture in my source folder. But is it possible to only take one card out from my single deck image?
bild = ImageIO.read(new File("source folder/" + colour + value + ".png"));
You should initialize them all but you don't have to do it by hands.
You should create one image that contains every single card and load it. BufferedImage class provides you a getSubImage(int x, int y, int w, int h); and is returning a piece (a card) of your BufferedImage.
You can populate an array of card while looping through the image of your deck.
for(int i = 0; i<4; i++){
for(int j = 0; j < 13; j++){
deckArray[13 * i + j] == image.getSubImage(i * cardWidth,
j * cardHeight,
cardWidth,
cardHeight);
}
}
Something like this. Note that I'm assuming 4*13 images os sheet and no space between them.
You will have to find a way to track you cards, which one is which in your array no matter how you store them, because what you definietly don't want is loading an image every time you want to use it.
It's not tested and not 100% sure I did all the math corretly, just a quick reference how could you achive something like this.
You still have to load the entire image but when you're drawing, just use
g.drawImage(Image img, int dstx1, int dsty1, int dstx2, int dsty2, int srcx1, int srcy1, int srcx2, int srcy2, ImageObserver observer);
The src (=source) values will be the upper left und lower right coordinates within your image that define the part you want to draw while the dst (=destination) values will decide where it will be drawn.

Render lots of individual pixels efficient?

I have made a map on an image which I load in the game like this:
List<Block> tempBlocks = new ArrayList<Block>();
BufferedImage level = levels.get(currentLevel);
for (int x = 0; x < level.getWidth(); x++) {
for (int y = 0; y < level.getHeight(); y++) {
tempBlocks.add(new Block(x, y, new Color(level.getRGB(x, y))));
}
}
blocks = tempBlocks;
isLoading = false;
The array blocks is an array with all 1-pixel-blocks. Every single block renders like this:
g.setColor(color);
g.drawLine(x, y, x, y);
I call them like this:
for (int i = 0; i < getCurrentScene().blocks.size(); i++)
getCurrentScene().blocks.get(i).render(g);
It's 1280x720 blocks... Is it a better way to render this insane amount of blocks? Because I want it to load from an image, which is 1280x720. I get like 3 FPS now...
For what you're doing now, if you do that for every frame, you're creating new objects all over the place for every single frame, and only using them once before discarding and allowing the garbage collector to pick them up.
Create enough objects to represent how the screen is now.
Create enough objects to represent how the screen should be next.
Don't lose those. Don't create any more.
For the Color(int int int) thing you're doing? You can just do Color(int); new color(level.getRGB(x, y)) should work just fine; the java.awt.Color class can take a single int instead of three.
That said, you'd still be initializing Color a million times. If you have a limited number of Colors, it may be beneficial to call them directly or cache them in some way, instead of continually recreating new Color objects on the heap.
Shepard solved it in the comments. What I did was to render the image as g.drawImage(image, x, y); instead of rendering all of the pixels. I still use the blocks for collision detection, but that is way more efficient.

Slick is getting very slow but only drawin rectangles

I am using slick for java since a few days and got a serious problem.
If i run a completely empty apllication (it just shows the fps) with a solution of 800x600 i get a fps count between 700 and 800.
If I now draw an array with 13300 entries as a grid of green and white rectangles, the fps drop to something around 70.
With more entries in the array it becomes really slow.
For example in a solution of 1024x768 and an array with 21760 entries the fps drop to 40.
How i draw a single entry:
public void draw(Graphics graphics){
graphics.setColor(new Color(getColor().getRed(), getColor().getGreen(), getColor().getBlue(), getColor().getAlpha()));
graphics.fillRect(getPosition().x, getPosition().y, getSize().x, getSize().y);
Color_ARGB white = new Color_ARGB(Color_ARGB.ColorNames.WHITE);
graphics.setColor(new Color(white.getRed(), white.getGreen(), white.getBlue(), white.getAlpha()));
}
And this is how I draw the complete array:
public void draw(Graphics graphics) {
for (int ix = 0; ix < getWidth(); ix++) {
for (int iy = 0; iy < getHeight(); iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
In my opinion 21760 is not that much.
Is there anything wrong with my code or is slick just too slow to draw so much rectangles?
You only want to draw rectangles that are on the screen. If your screen bounds go from 0 to 1024 in the x direction and from 0 to 768 in the y direction, then you only want to loop through rectangles that are inside those bounds and then only draw those rectangles. I can't imagine you are trying to draw 21760 rectangles inside those bounds.
If you are, then try creating one static rectangle and then just try drawing that ONE in all of the different positions you need to draw it at rather than creating a new one every time. For example, in a game I am making, I might have 1000 tiles that are "grass" tiles, but all 1000 of those share the same static texture. So I only need to reference one image rather than each tile creating its own.
Each rectangle can still have a unique state. Just make your own rectangle class and have a static final Image that holds a 5*5 image. Each rectangle will use this image when it needs to be drawn. You can still have unique properties for each rectangle. For example, private Vector2f position, private boolean isAlive, etc
You're probably not going to be able to draw individual rectangles any faster than that.
Games that render millions of polygons per second do so using vertex buffer objects (VBO). For that, you'll probably need to code against the OpenGL API (LWJGL) itself, not a wrapper.
Not sure if Slick will allow it, but if this thing looks anything like a chessboard grid... you could draw just 4 rectangles, grab them and use the resulting image as a texture for your whole image. I'm not even a java programmer just trying to come up with a solution.
Since you're only repeatedly using just a few colors creating a new Color object for every single one is bound to be slow... use new only once for each different color used and store the re-usable colors somewhere in your class, than call the functions with those, constantly allocating and freeing memory is very slow.
And while this might not be as much a benefit as not using new each time but have you considered caching the results of all those function calls and rewriting code as
public void draw(Graphics graphics) {
int ixmax = getWidth();
int iymax = getHeight();
for (int ix = 0; ix < ixmax; ix++) {
for (int iy = 0; iy < iymax; iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Or if you'd prefer not to declare new variables
public void draw(Graphics graphics) {
for (int ix = getWidth() - 1; ix >= 0; ix--) {
for (int iy = getHeight() - 1; iy >= 0; iy--) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Just noticed in another answer you have an integral size grid (5x5) ... in this case the fastest way to go about this would seem to be to draw each item a single pixel (you can do this directly in memory using a 2-dimensional array) and scale it to 500% or use it as a texture and draw a single rectangle with it the final size you desire ... should be quite fast. Sorry for all the confusion caused by previous answers, you should have said what you're doing more clearly from the start.
If scaling and textures are not available you can still draw in memory using something like this (written in c++, please translate it to java yourself)
for( int x = 0; x < grid.width(); x++ ) {
for( int y = 0; y < grid.height(); y++ ) {
image[x*5][y*5] = grid.color[x][y];
image[x*5][y*5 + 1] = grid.color[x][y];
image[x*5][y*5 + 2] = grid.color[x][y];
image[x*5][y*5 + 3] = grid.color[x][y];
image[x*5][y*5 + 4] = grid.color[x][y];
}
memcpy(image[x*5+1], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+2], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+3], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+4], image[x*5], grid.height() * sizeof(image[0][0]) );
}
I'm not sure, but perhaps for graphics the x and y might be represented in the reversed order than used here, so change the code accordingly if it that's the case (you'll figure that out as soon as a few iterations run), also your data is probably structured a bit differently but I think the idea should be clear.

Load bitmap into array (Java)

For a project I need to make a map in Java that a robot can navigate through. Preferably, I'd like to store the map in a 2D-array, but I don't know how to go from the 1 bit bitmap to an array in Java. Can you help me out?
You can use the ImageIO.read() method to load your bitmap in a BufferedImage instance. Then, call BufferedImage.getRGB(int x, int y) to get the color value of a particuliar pixel of your map.
Assuming a 10 by 10 grid, then you would create an array such as
Image[][] grid = new Image[10][10];
Then
for (int x = 0; X < grid.length; X++) {
for (int y = 0; y < grid[x].length; y++) {
grid[x][y] = theImageForThisPosition;
}
}
However, as you are storing 1 bit bitmaps, it would be much more efficient to store Color objects, rather than Image objects.

Categories