Simple issue regarding iterating through each pixel in an image - java

Okay this is going to seem really dumb but bear with me please. A year ago I made a little program to perform various operations on images, and now I'm a bit rusty and having to do something vaguely similar. I'm looking at the old application in order to help me get started but there is one very simple thing my head doesn't want to understand the logic of just now. Basically where I loop through each pixel in an image in order to do something with that location, what exactly doesn't matter right now. Here is the basic idea:
for (int x = 0; x < inputImage.getWidth(); x++) {
for(int y = 0; y < inputImage.getHeight(); y++) {
*code in here*
}
}
Now what I don't get is this. Surely the logic of the nested for loops means that after every loop, both x AND y are incremented. So on the first pass, x = 0, y = 0. Second pass, x = 1, y = 1 and so on. This would mean that you only ever choose diagonal pixels going from the top left of the image to the bottom right, missing out a ton of pixels such as one located at x = 0, y = 1. I KNOW this is simple and surely makes sense but I'm just not getting the logic right now! Many thanks.

No, that's not what nested loops do at all. The y loop is wholly inside the body of the x loop (that's what it means to be nested), so the entire y loop runs at each iteration of the x loop.
x = 0
y = 0, y = 1, y = 2, ...
x = 1
y = 0, y = 1, y = 2, ...
The behavior you're thinking of, with only iterating over diagonal elements, could be achieved like this if you wanted it:
for (int x = 0, int y = 0;
x < inputImage.getWidth && y < inputImage.getHeight;
x++, y++) {
// stuff
}
Notice how both x and y are incremented in the same loop; there is no nested "subloop". (Disclaimer: I haven't done Java in a while, I might have messed up the syntax a bit)

No. Both x and y are not actually incremented simultaneously.
y goes from 0 to inputImage.height-1 for every x from 0 to inputImage.width-1. That means, you traverse the first column completely before moving to another column on the image and so on.

Related

Why doesn't my code flip image horizontally?

public void flipImageHorizontally(){
this.redisplayImage();
for(int x = 0; x < this.image.length; x++)
for(int y = 0; y < this.image[0].length; y++){
this.image[x][y] = this.image[x][this.image[0].length - 1 - y];
}
}
The code runs but it doesn't perform the action intended. It is supposed to flip the image horizontally, but instead it only flips half of the image.
Let's say you have an image two pixels wide and one pixel high:
1 2
After the first iteration of your loop, the end pixel will be swapped to the beginning (image[0][0] = image[0][2 - 1 - 0];):
2 2
But now you lost the original value of image[0][0]! So when you do the swap image[0][1] = image[0][2 - 1 - 1];, you are copying the second half of the image back to itself.
The right answer is to use a buffer so you don't overwrite the swap:
for(int y = 0; y < this.image[0].length / 2; y++) {
int buffer = this.image[x][y];
this.image[x][y] = this.image[x][this.image[0].length - 1 - y];
this.image[x][this.image[0].length - 1 - y] = buffer;
}
Integer truncation ensures that this.image[0].length / 2 is an efficient bound. For even numbers, you iterate exactly the first half. For odd numbers, you iterate the first half, not including the middle pixel. That's a good thing, because the middle does not need to be swapped.
You need to iterate up to the middle, and swap pixels that are on the left with pixels that are on the right. Otherwise you end up overwriting your changes.
public void flipImageHorizontally() {
this.redisplayImage();
for(int x = 0; x < this.image.length; x++) {
for(int y = 0; y < this.image[x].length / 2; y++) {
int pixel = this.image[x][y]; // assuming int
this.image[x][y] = this.image[x][this.image[x].length - 1 - y];
this.image[x][this.image[x].length - 1 - y] = pixel;
}
}
}
In this code
the pixel variable temporarily holds the value on the left;
the value on the left gets assigned the value on the right;
the value on the right gets the value that was originally on the left (i.e. whatever is in pixel).
Notes:
I maintained your naming of x and y, even though it's counter-intuitive because it makes it look like you're performing a vertical flip instead of a horizontal one.
I don't know the data type of the array; I assumed int, but it might be a float array, Pixel objects, or something else.
I don't know what this.redisplayImage(); is supposed to do, and whether it's in the right location.

Is it possible to write a conditional with the logical form "then if"?

I'm currently trying to teach myself to code in Processing 3. Having looked over the reference doc, there is no then if (*expression*) {} statement. My best guess is that I'll need to string together if (*expression*) {} and else if (*expression) statements, but I'm so far unable to get something similar to a direct then if statement. How might I go about doing something like this?
Based on comments, I'm seeing that I should have provided an example case. I don't even entirely understand the logic and so this might be messy, but here's my best attempt:
Say that I want to draw a square to the console, where I have int x = 0, int y = 0, and rect(x, y, 20, 20). I then want to draw multiple squares in sequence and keep track of the number of squares. Then, if the number of squares is equal to ten, I want to fill each square with a randomly determined color. Every tenth square is intended to serve as a trigger which tells to program to alter the color of each set of ten squares.
I should add that, although there is probably a simpler method for writing this that likely involves looping statements like for and while, I'm trying to challenge myself to write this using the stuff that I've already learned.
My current code looks like this; please bare in mind that this is by no means complete and that there are likely to be other errors because I'm just starting to learn to code and I'm not perfect at it yet:
1. //global variables:
2. int x = 0;
3. int y = 0;
4. int numberOfSquares = 0;
5.
6. void setup() {
7.
8. // note that the size of the window is
9. // currently needlessly large, but this
10. // is the intended final size for the
11. // end result of this exercise
12. size(1000, 1000);
13. frameRate(5);
14. }
15.
16. void draw() {
17. //local variables: none yet
18.
19. // if statement used to draw ten squares
20.
21. if (numberOfSquares < 10) {
22. rect(x, y, 20, 20);
23. x = x + 40;
24. y = y + 40;
25. numberOfSquares = numberOfSquares + 1;
26.
27. // then, if ten squares exist, and only then
28. // fill each square with a random color
29.
30. if (numberOfSquares == 10) {
31. fill (random(255), random(255), random(255));
32. }
33. }
34. }
35.
36. // from here, draw 10 squares again,
37. // maintaining the original fill until
38. // another 10 squares are drawn
There are probably also some formatting errors in this edit; this is my first time using a Stack page and so I'm not entirely familiar with the conventions yet. My apologies.
I'm not clear on what you mean, but here are some examples that may clear things up. May...
if (expression) {
// If expression is true, then do this.
else if (anotherExpression) {
// If expression is false, check whether anotherExpression is true.
// If it is, do this.
// There can be more than one "else if" chained one after the other.
} else {
// If all those "if" and "else if" expressions were false, then do this.
// The "else" part of an "if" is not required.
}
The official Java tutorial has a good page on the different types of if statements:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
Now if you want to chain conditions:
if (expression && anotherExpression) {
// Do this if both expressions are true.
}
if (expression) {
// Do something if expression is true.
if (anotherExpression) {
// Do this if anotherExpression is also true.
// Since this block is inside the first "if", it needs both
// expression and anotherExpression to be true.
}
}
Of course you can mix and match these.
As background for people not yet familiar with Processing: "Processing is a flexible software sketchbook and a language for learning how to code within the context of the visual arts." You can use different programming languages and this program is using Java (JavaScript and Python are also supported).
The draw function is called continuously and since you've set the frame rate to 5, it should be called about every 200 milliseconds.
The fill function sets the color used to fill shapes. This fill color will only be used to shapes that are added after you've called the fill function. In your program, calling fill doesn't change the color of the ten squares that the program has already created.
If you use the draw function below, the first ten squares are filled with white (the default fill color). After drawing the tenth square, a random fill color is selected, which will be used for the next ten squares.
By using an if statement within another if statement, you get the "then if" behavior I think you're looking for. The fill color will only be changed if both conditions are met: squareCount < maximumSquareCount and squareCount % 10 == 0:
//global variables:
int x = 0;
int y = 0;
int maximumSquareCount = 25;
int squareCount = 0;
void draw() {
if (squareCount < maximumSquareCount) {
rect(squareCount * 40, squareCount * 40, 20, 20);
x = x + 40;
y = y + 40;
squareCount++;
if (squareCount % 10 == 0) {
fill(random(255), random(255), random(255));
}
}
}
The expression used to decide when to change the fill color might be a bit cryptic: squareCount % 10 == 0. The remainder operator % calculates the remainder after dividing (see https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op1.html). In this case, the square count is divided by ten and if the remainder is equal to zero, the fill color is changed. This will happen after 10, 20, etc. squares have been added.
There is some ambiguity as to your intent but I think I understand what you are going for. Lets first look at your code unchanged
void draw()
{
// if statement used to draw ten squares
if (numberOfSquares < 10)
{
rect(x, y, 20, 20);
x = x + 40;
y = y + 40;
numberOfSquares = numberOfSquares + 1;
// then, if ten squares exist, and only then
// fill each square with a random color
if (numberOfSquares == 10) {
fill (random(255), random(255), random(255));
}
}
}
So lets consider that Draw runs when you have numberOfSquares = 0. First, it will check numberOfSquares < 10, which is true. So it will create a single square. Then, it will check if numberOfSquares == 10. This will be false since we only have 1 square now and will not run. We would have to call draw() 10 times before if (numberOfSquares == 10) will evaluate to true.
Now referring to your question in a comment you say how might I implement something akin to "do thing, then do next thing for each time that next thing needs to be done"?This is the concept of looping, more specifically it is an if statement followed by a loop. Its a little unclear what you mean to repeat by this, but just as an example lets assume you want "if I have less than 10 squares, produce squares until I have 10 of them". You could use a while loop, or for loop for this, I personally prefer for loops.
void draw()
{
// for loop used to draw 10 squares
for(int i = numberOfSquares; numberOfSquares < 10; i = i + 1)
{
rect(x, y, 20, 20);
x = x + 40;
y = y + 40;
numberOfSquares = numberOfSquares + 1;
}
if (numberOfSquares == 10)
{
fill (random(255), random(255), random(255));
}
}
Now when draw is called, it will produce squares until you have 10 every time. In this case, the inner if (numberOfSquares == 10) is redundant, because we just ensured that 10 will exist no matter what when we reach this if statement, so we can remove it.
void draw()
{
// for loop used to draw 10 squares
for(int i = numberOfSquares; numberOfSquares < 10; i = i + 1)
{
rect(x, y, 20, 20);
x = x + 40;
y = y + 40;
numberOfSquares = numberOfSquares + 1;
}
// fill
fill (random(255), random(255), random(255));
}

Converting Vertex[] to graph

I am making a Pac-Man game and I am currently working on the ghosts AI. I am planning on using Dijkstra's algorithm for the pathfinding. My problem is that when my game is loaded the vertices for the graph are stored in a matrix. I am trying to assign each vertex all of its edges like this
for(int x = 0; x<40; x++)
{
for(int y = 0; y<40; y++)
{
Vertex vertex = map[x][y];
vertex.adjacencies = new Edge[]{new Edge(map[x-1][y], 1), new Edge(map[x+1][y], 1), new Edge(map[x][y-1], 1), new Edge(map[x][y+1], 1)};
}
}
the problem is that it sometimes throws an array out of bounds exception. How would I fix this without putting in tons of if statements to check if the current vertex is on the edge of the graph?
One easy way is to include a non-traversable border around the edges.
For example, if your actual map is 40x40, you can declare a 42x42 array. Rows 0 and n would be non-traversable, as would be columns 0 and n.
You'd still need to handle cylindrical travel of the pacman between left and right sides.
You should start your loop with a "border" of 1, like this:
for(int x = 1; x < 39; x++)
because, when you create your edges with map[x-1][y] with a x started to 0, it take -1 as array index, so it throw an Array Out of Bounds exception.

Counting with booleans

I was wondering if I could add booleans up like numbers. I am making something that uses a grid, and I want it to find the surrounding squares and return a number.
EDIT:
This is how I count with booleans.
int count = 0;
for (int x = -1; x<=1;x++){
for (int y = -1; y <=1;y++){
if (grid[xPos+x][yPos+y]){
count++;
}
}
}
boolean[] bools = ...
int sum = 0;
for(boolean b : bools) {
sum += b ? 1 : 0;
}
This assumes that you want true to be 1 and false to be 0.
To add to Jeffrey's answer, don't forget:
If your at the center cell of your nested for loops, don't check the grid, and don't add to count. Else you're counting the cell itself in its neighbor count. In your situation, it's were (x == 0 && y == 0)
You will need to check if the cell is on the edge, and if so make sure you're not trying to count cells that are off the grid. I've done this using something like this: int xMin = Math.max(cellX - 1, 0); where xMin is the lower bound of one of the for loops. I do similar for y, and similar for the maximum side of the grid. In your code this will happen when xPos + x < 0 or xPos + x >= MAX_X (MAX_X is a constant for the max x value allowed for the grid), and similar for the y side of things.
What is your goal? Speed? Readability? Code terseness?
If you're seeking speed, think about minimizing the number of memory accesses. If you can force your booleans to be stored as bits, you could use >> and & to compare only the bits you care about in each row. Maybe something like this:
byte grid[m][n / 8];
int neighbor_count = 0;
for (int row = yPos - 1; row < yPos + 1; row++) {
// calculate how much to shift the bits over.
int shift = 5 - (xPos - 1 % 8);
if (shift > 0) {
// exercise for the reader - span bytes.
} else {
// map value of on-bits to count of on bits
static byte count[8] = [0, 1, 1, 2, 1, 2, 2, 3];
// ensure that only the lowest 3 bits are on.
low3 = (grid[row][xPos / 8] >> shift) & 7;
// look up value in map
neighbor_count += count[low3];
}
caveat coder: this is untested and meant for illustration only. It also contains no bounds-checking: a way around that is to iterate from 1 to max - 2 and have a border of unset cells. Also you should subtract 1 if the cell being evaluated is on.
This might end up being slower than what you have. You can further optimize it by storing the bitmap in int32s (or whatever's native). You could also use multithreading, or just implement Hashlife :)
Obviously this optimizes away from terseness and readability. I think you've got maximum readability in your code.
As Jeffrey alludes to, storing a sparse array of 'on' booleans might be preferable to an array of values, depending on what you're doing.

Creating a check that needs to loop outwards from the middle of 3 variables ( x y z )

for (int ix = x - r; ix < x + r + 1; ix++) {
for (int iz = z - r; iz < z + r + 1; iz++) {
for (int iy = y - r; iy < y + r + 1; iy++) {
// if ix,iy,iz = something blah blah (this part isn't needed)
}
}
}
Ok, now here's the issue. The current code above gets an x,y,z and r (range). It's job is to reference through the "cube" until meets a certain condition I've set. The problem lies in the fact that it starts on the outside of the cube and progresses from 1 corner to another corner basically.
I'm looking for a way (my math/java is not liking me atm) to start at a pos and loop outwards from that pos (including the pos itself) until it reaches the outermost bounds of the cube.
So if we gave everything fake values, lets use x = 5, y = 5, z = 5, r = 2
the code should check 5,5,5 - 4,5,5 6,5,5 5,6,5 5,4,5 etc etc basically iterating through every thing to outwards from the center.
The command is called FindNearest, but technically it's acting like FindFurthest atm.
I hope I gave enough detail and would love if someone could toss some snippets or working code at me as this is frustrating for the last hour or so. I don't wanna have 10 if checks in the middle of the for loops or random stuff like that, I'm looking for a clean way of doing this.
You can iterate out from the center by doing something like this:
for (ix = x, xsign = 1, xstep = 1;
(ix >= x - r) && (ix <= x + r);
ix += xsign * xstep, xsign = -xsign, xstep++)
So ix for your example will go from 5 to 6 to 4 to 7, etc. You can just nest loops like these and you'll get what you're looking for, at least if I'm understanding the question correctly.

Categories

Resources