I'm trying to calculate the edges of a black object within a .png file. And by that I mean find the column and row values that makeup a box that encapsulates an object. I attached a link to the photo I created which draws the box according to the values I find. As you can see the top, bottom, and right lines seem to line up correctly, but if you zoom in to the left line, part of the image is outside of the box. Why is that? I have an algorithm which I'll post below that searches every pixel in the array and finds the last occurrence of pixel values != 0 for the top, bottom, left and right sides. For some reason that extra image on the left side is registering pixels that are == 0... Are the values being rounded down to zero? If somebody could explain what is happening that would be great.
Here is a link to the image: http://i.imgur.com/UG8Cghe.png. You really have to zoom into the left side to see what I am talking about. Downloading the image and viewing is probably a necessity. It is a VERY small detail.
Here is the method that converts the BufferedImage(.png) to a 2D Array:
private static int[][] loadImageTo2D(String file_path)
{
img = null;
try { img = ImageIO.read(new File(file_path)); }
catch (IOException e) { System.out.println(e); }
int width = img.getWidth();
int height = img.getHeight();
int[][] pix = new int[height][width];
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
pix[row][col] = img.getRGB(col, row);
}//for
}//for
return pix;
}//loadImageTo2D
Here is how I am searching for the sides:
private static int[] getPerim(int[][] pix)
{
//Array holds object boundary edges.
int[] lines = new int[4];
lines[BOTTOM] = 0;
lines[TOP] = pix.length;
lines[LEFT] = pix[0].length;
lines[RIGHT] = 0;
//Top down iteration, find the first and last row and column of the
//actual graphic.
for (int row = 0; row < pix.length; row++)
{
for(int col = 0; col < pix[0].length; col++)
{
if (pix[row][col] != 0)
{
if (row < lines[TOP]) { lines[TOP] = row; }
else if (row > lines[BOTTOM]) { lines[BOTTOM] = row; }
else if (col < lines[LEFT]) { lines[LEFT] = col; }
else if (col > lines[RIGHT]) { lines[RIGHT] = col; }
}//if
}//for
}//for
return lines;
}//getPerim
I'm then using lines[] to draw the blue box you see in image. Help!
Drop the else part of if else and make all of them ifs . Only one of those if elses can be executed. What happens if pixel is the most down and most left pixel? It will be only used as the most bottom one, as the if-else statement won't get to the col part. I suggest you change it to
if (row < lines[TOP]) { lines[TOP] = row; }
if (row > lines[BOTTOM]) { lines[BOTTOM] = row; }
if (col < lines[LEFT]) { lines[LEFT] = col; }
if (col > lines[RIGHT]) { lines[RIGHT] = col; }
And no, you can't group left border with right border, as they can be on the same pixel.
Related
I am trying to export my sketch to pdf. The issue that I have is that for some reason only a portion of my sketch is exported to pdf, as if the original sketch was cropped! When I run my sketch, 64 lines show up (as intended) and indeed when I save it to png all the 64 lines are there and sketch looks just the same as when I run it.
When I export the sketch to pdf though, only 16 line show up, as if the pdf was cropping my sketch and only the cropped portion was being exported.
This is the png showing what the sketch is supposed to look like:
This is what the pdf has exported:
And this is my code:
import processing.pdf.*;
import java.util.Random;
int cols, rows;
int videoScale = 100;
boolean recordPDF = false;
void setup() {
size(800,800);
pixelDensity(2);
frameRate(0.5);
cols = width/videoScale;
rows = height/videoScale;
}
void draw() {
if (recordPDF) {
beginRecord(PDF, "pdfs/" + str(random(1000)) + ".pdf");
}
background(255);
strokeWeight(1.5);
drawLines();
if (recordPDF) {
endRecord();
recordPDF = false;
println("Printed pdf.");
}
}
void keyPressed() {
if (key == 'p') {
recordPDF = true;
}
if (key == 's') {
saveFrame("img.png");
}
}
void drawLines() {
// Begin loop for columns
for (int i = 0; i < cols; i++) {
// Begin loop for rows
for (int j = 0; j < rows; j++) {
int x = i*videoScale;
int y = j*videoScale;
line(x,y,x+30,y+30);
}
}
}
I have looked into the relevant documentation on PDF exports but could not find a solution to this. Any help would be greatly appreciated!
Remove pixelDensity(2) from the setup() to fix. PixelDensity of 2 was designed to allow retina monitors to use all of the pixels. If you must use it, then you would need to write a separate drawLines() for the pdf file (example follows). Note that for the pdf drawLines() the videoScale is cut in half and the second set of x,y coordinates for each line is +15 instead of +30. You will also have to change the path for each file saved to be correct for your system. I used a different method for creating a pdf from pGraphics, which should be irrelevant.
/*
If pixelDensity(2) is used, need to modify second drawLines() for pdf.
Change file paths to suit your system.
*/
import processing.pdf.*;
import java.util.Random;
int cols, rows;
int videoScale = 100;
void drawLines() {
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
int x = i*videoScale;
int y = j*videoScale;
strokeWeight(1.5);
line(x, y, x+30, y+30);
}
}
}
void setup() {
size(800, 800);
background(255);
pixelDensity(2);
// frameRate(0.5);
cols = width/videoScale;
rows = height/videoScale;
drawLines();
}
void draw() {
}
void keyPressed() {
if (key == 'p') {
PGraphics pdf = createGraphics(width, height, PDF, "/Users/me/Desktop/output.pdf"); // change this
videoScale = 50; // cut in half
pdf.beginDraw();
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
int x = i*videoScale;
int y = j*videoScale;
pdf.line(x, y, x+15, y+15); // +15 instead of +30 for second x,y coordinates
}
}
pdf.dispose();
pdf.endDraw();
println("Printed pdf.");
}
if (key == 's') {
saveFrame("/Users/me/Desktop/img.png"); // change this
println("Image saved.");
}
}
I am trying to store all of the values in the matrix from the top right to the bottom left and store them in an array.
int matrixSample [][] = {
{6,4,1,4},
{7,5,4,4},
{4,4,8,3},
{4,4,8,3}
};
The output should be
[4,1,4,4,4,3,6,5,8,3,7,4,8,4,4,4]
I can get the bottom right diagonal
static int[] getAllDiagonalsInMatrix(int matrix[][]){
// Sum of arithmetic progression
int diagonal[] = new int[matrix.length * (matrix.length + 1)*2];
int index = 0;
for(int row = 0; row < matrix.length; row++) {
for(int col = 0; col < matrix[row].length - row; col++) {
diagonal[index++] = matrix[row + col][col];
}
}
return diagonal;
}
Is this even possible to do using the same two loops by adjustments made in the loops above?
Okay, here is my thought process on your problem. However, I'm going to print values instead of collecting them to make it a little easier on me and keep the solution easy to read.
First, how do you get a diagonal? We need to do this frequently so lets start by making a function for that. Maybe we could pass in the top left corner of the diagonal and go from there.
public void getDiagonal(int[][] array, int row, int col) {
// While row and col are within the bounds of the array
while (row < array.length && col < array[row].length) {
// Print element in diagonal
System.out.println(array[row][col]);
// Diagonal moves from top-left to bottom-right
row++;
col++;
}
}
Now that we have a function to get a diagonal, we just need a way to call it. Essentially, we just need to follow an L shape going from the top-right to the top-left to the bottom-left.
// Get diagonals starting in the first row with a column > 0
for (int col = array.length - 1; col > 0; col--) {
getDiagonal(array, 0, col);
}
// Get all diagonals starting from the left most column
for (int row = 0; row < array.length; row++) {
getDiagonal(array, row, 0);
}
Now that we have a working way to iterate through the values, we can rewrite it to save the values into an array instead. You could also choose to remove the function entirely now that you have a process.
Edit: I almost forgot, but the mathematical solution you were looking for is as follows.
for (int row = 0; row < array.length; row++) {
for (int col = 0; col < array.length; col++) {
// Index along diagonal
int diagonal = Math.min(row, col);
// Which part of L contains value
if (col >= row) {
int start = array.length - 1 - (col - row);
int passed = start * (start + 1) / 2;
solution[passed + diagonal] = array[row][col];
} else {
int start = array.length - 1 - (row - col);
int passed = array.length * array.length - 1 - start * (start + 1) / 2; solution[passed - array.length + 1 + row] = array[row][col];
}
}
}
One solution is to iterate through a matrix where you consider positions outside of the matrix, but exclude every index out of bounds.
static int[] getDiagonals(int[][] mat) {
int diagonal[] = new int[mat.length * (mat[0].length)];
int index = 0;
int yStart = -mat[0].length;
for (int y = yStart; y < mat.length; y++) {
for (int x = 0; x < mat[0].length; x++) {
if (y + x >= 0 && y + x < mat.length) {
diagonal[index++] = mat[y+x][x];
}
}
}
return diagonal;
}
Might not be optimal as you are effectively traversing a matrix nearly twice the size, but it is pretty intuitive.
I have a picture and I am trying to remove all the green pixels. How do I do this using simple java and a 2D array?
So far, my code looks like this:
public void removeGreen() {
Picture pic = new Picture("IMG_7320.JPG");
Pixel pixel = null;
for (int row = 0; row < pic.getHeight(); row++) {
for (int col = 0; col < pic.getWidth(); col++) {
pixel = getPixel(row,col);
pixel.getColor();
if(pixel.getRed() < 40 & pixel.getBlue() < 160 & pixel.getGreen() > 220) {
Color white = new Color(255,255,255);
pixel.setColor(white);
}
}
}
}
(Right now I am trying only replacing the green pixel with a white pixel because I'm not sure how to remove the pixel altogether.)
And the code in my main method that I am using to test the removeGreen() method,looks like this:
//method to test removeGreen
public static void testRemoveGreen() {
Picture me = new Picture("IMG_7320.JPG");
me.explore();
me.removeGreen();
me.explore();
}
So, my code now looks like this:
public void removeGreen(Picture pic) {
for (int row = 0; row < pic.getHeight(); row++) {
for (int col = 0; col < pic.getWidth(); col++) {
Pixel pixel = pic.getPixel(row,col);
if((pixel.getRed() < 40) && (pixel.getBlue() < 160) && (pixel.getGreen() > 220)) {
Color white = new Color(255,255,255);
pixel.setColor(white);
}
}
}
}
and my main method is still the same. I still do not understand why the method is not working properly.
The following makes clear that the passed pic parameter is altered.
public static void removeGreen(Picture pic) {
for (int row = 0; row < pic.getHeight(); row++) {
for (int col = 0; col < pic.getWidth(); col++) {
Pixel pixel = pic.getPixel(row,col);
if (pixel.getRed() < 40 && pixel.getBlue() < 160
&& pixel.getGreen() > 220) {
pixel.setColor(Color.white);
}
}
}
}
The && is a short-cut AND: x && y() will not call y is x is false.
Mind the pic.getPixel. If removeGreen is intended as method of Picture, remove the parameter and the static keyword, and pic..
public static void testRemoveGreen() {
Picture me = new Picture("IMG_7320.JPG");
me.explore();
removeGreen(me);
me.explore();
}
As the .jpg, JPEG, format does not have transparency, some colour like white is needed to be shown as "background."
I have 2 images and each is partial of a complete image, and the 2 combined could create the complete image.
However there is overlap on the 2 images, and I am trying to create a program that will find where the top row of image2 meets whichever row of pixels in image 1.
I created a for loop to gather each row of pixels per image in an array.
this is my code:
int row = 0;
for (int i = 0; i < imageArray1.length; i++) {
for (int j = 0; j < imageArray1[i].length; j++) {
if (imageArray1[i][j] == (imageArray2[0][0])) {
row = imageArray1[i][j];
}
}
}
the problem is I am pretty sure I am only gathering a with the individual pixel that is top left of the second image, rather than the whole row.
Any ideas how to get around this?
new to java
You need to cross check each rows in image1 against each rows in image2. Therefore, 3 levels of looping: 1) loop through the rows in image1 2) loop through the rows in image2 3) loop through the columns in the current row in image1 and image2 to decide if they are overlapping
int overlappingRowInImage1 = 0;
int overlappingRowInImage2 = 0;
int[][] imageArray1 = null;
int[][] imageArray2 = null;
// loop through the rows in the first image
for (int row1 = 0; row1 < imageArray1.length; row1++) {
boolean foundIdenticalRow = false;
// loop through the rows in the second image
for (int row2 = 0; row2 < imageArray2.length; row2++) {
foundIdenticalRow = true;
// two rows are identical if each column in both rows are the same
for (int col = 0; col < imageArray1[row1].length; col++) {
if (imageArray1[row1][col] != (imageArray2[row2][col])) {
foundIdenticalRow = false;
break;
}
}
if (foundIdenticalRow) {
overlappingRowInImage1 = row1;
overlappingRowInImage2 = row2;
break;
}
}
if (foundIdenticalRow) {
System.out.println("Row " + overlappingRowInImage1 + " in image 1 is overlapping with Row " +
overlappingRowInImage2 + " in image 2");
break;
}
}
You need to fix the imageArray2[0][0] so it's always comparing with the first index of imageArray2 only. You need to iterate your imageArray2 along with imageArray1 for full comparison. For this I would suggest you to use a nested for loop for imageArray2.
I've been lurking and found heaps of great information form here, however the last few days I have been stuck and haven't been able to find help with my issue so I thought id post.
I have some homework and I have to make the contents of my array drop down to the bottom row. If i rotate the grid the items should still drop down to the bottom row and if i eat an object from the bottom row, everything above it in that column should drop down too.
Any help is greatly appreciated.
Here is a demo video of what should happen:
http://youtu.be/CB07vN-C_-Y
This is what i have so far:
`public class Assignment
{
// This method should return a *new copy* of
// the 2D cell matrix, with entries rotated clockwise
// The original matrix should not be changed
public static int[][] rotateClockwise(int[][] cells)
{
int w = cells.length;
int h = cells[0].length;
int[][] matrix = new int[h][w];
for (int i = 0; i < h; ++i)
{
for (int j = 0; j < w; ++j)
{
matrix[i][j] = cells[j][h - i - 1];
}
}
return matrix;
}
// This method should return a *new copy* of
// the 2D cell matrix, with entries rotated anti-clockwise
// The original matrix should not be changed
public static int[][] rotateAnticlockwise(int[][] cells)
{
int w = cells.length;
int h = cells[0].length;
int[][] matrix = new int[h][w];
for (int i = 0; i < h; ++i)
{
for (int j = 0; j < w; ++j)
{
matrix[i][j] = cells[w - j - 1][i];
}
}
return matrix;
}
// This method should return a *new copy* of the array, except
// that if there is a 0 that has a non-zero in the preceding
// slot in the array, then those two entries should be swapped
// See ProgrammingProject.pdf for an example
// The original array should not be changed
public static int[] dropOne(int[] column)
{
return column; // this will compile but gives the wrong result
}
}`
I'd model a column as a Queue<Icon> col = new LinkedList<Icon>(); there's an outline here for Queue<Segment> and a complete example here for Queue<Bauble>. You can peek() at the head (bottom) of the queue; if it's empty, you remove() a block from the column and add() it to the tail (top).
Addendum: You might start with this example, drop the getGray(), change the layout to new GridLayout(0, 1). Then, instead of shuffle(list), you'd cycle the queue.
for(int i = 0; i < arrayWidth; i++) {
boolean reachedZero = false;
for( int j = 0; j < arrayHeight; j++) {
if(array[i][j] == 1 && reachedZero == true) {
while( j >=0 && array[i][j - 1] == 0) {
array[i][j-1] = array[i][j];
array[i][j] = 0;
j--;
reachedZero = false;
}
j--; // Maybe an error here, it's late
if( array[i][j] == 0) {
reachedZero = true;
}
}
}
This was posted by a lovely redditor (RankWeis) from the /learnprogramming sub-reddit.
http://www.reddit.com/r/learnprogramming/comments/126597/java_help_needed_on_adding_a_gravity_effect_to/