I am implementing the matlab 'bwmorph(img, 'thin')' algorithm in Java ImageJ. I've searched all over the net pretty much and found some similar implementations that work better, but I can't find the issue in my code. Any ideas?
My code:
public void run(ImageProcessor ip) {
MakeBinary(ip);
int sum2 = processThin(ip);
int sum = -1;
while (sum2 != sum) {
sum = sum2;
sum2 = processThin(ip);
}
}
public int processThin(ImageProcessor ipOriginal) {
int sum = 0;
// first iteration
ImageProcessor ip = ipOriginal.duplicate();
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight() -1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3(neighbors) == 0)
ip.putPixel(i,j, 0);
}
// second iteration
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight()-1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3prime(neighbors) == 0)
ip.putPixel(i,j, 0);
}
for(int i = 0; i < ip.getWidth(); i++)
for(int j = 0; j < ip.getHeight(); j++) {
if (ip.getPixel(i,j) != 0) sum++;
ipOriginal.putPixel(i, j, ip.getPixel(i, j));
}
return sum;
}
private int G1(int[] input) {
int xh = 0;
for (int i = 1; i <= 4; i++) {
if (input[2 * i - 1] == 0 && (input[2 * i] == 1 || (2 * i + 1 <= 8 ? input[2 * i + 1] == 1 : input[1] == 1)))
xh += 1;
}
return xh;
}
private int G2(int[] input) {
int n1 = 0, n2 = 0;
n1 = toInt(toBool(input[4]) || toBool(input[3])) + toInt(toBool(input[1]) || toBool(input[2])) +
toInt(toBool(input[8]) || toBool(input[7])) + toInt(toBool(input[6]) || toBool(input[5]));
n2 = toInt(toBool(input[2]) || toBool(input[3])) + toInt(toBool(input[1]) || toBool(input[8])) +
toInt(toBool(input[6]) || toBool(input[7])) + toInt(toBool(input[4]) || toBool(input[5]));
return Math.min(n1,n2);
}
private int G3 (int[] input){
return toInt((toBool(input[2]) || toBool(input[3]) || !toBool(input[8])) && toBool(input[1]));
}
private int G3prime (int[] input){
return toInt((toBool(input[6]) || toBool(input[7]) || !toBool(input[4])) && toBool(input[5]));
}
private boolean toBool(int i ){
return i == 1;
}
private int toInt(boolean i) {
return i ? 1 : 0;
}
private int[] selectNeighbors(ImageProcessor ip, int i, int j) {
int[] result = new int[9];
result[1] = ip.getPixel(i+1,j);
result[2] = ip.getPixel(i+1,j+1);
result[3] = ip.getPixel(i,j+1);
result[4] = ip.getPixel(i-1,j+1);
result[5] = ip.getPixel(i-1,j);
result[6] = ip.getPixel(i-1,j-1);
result[7] = ip.getPixel(i,j-1);
result[8] = ip.getPixel(i+1,j-1);
for (int x = 0; x < result.length; x++)
if (result[x] != 0) result[x] = 1;
return result;
}
The main issue appears to be with the horizontal lines, but not only that.
Note: I've added the toBool and toInt methods to deal with convenient data types, the code was binary before and the result is the same apparently.
EDIT:
After editing the code and omitting doing modifications between two iterations, I ended up with this result now.
The code looks like this now.
public int processThin(ImageProcessor ip) {
int sum = 0;
// first iteration
int[][] mask = new int[ip.getWidth()][ip.getHeight()];
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight() -1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3(neighbors) == 0)
mask[i][j]++;
}
// second iteration
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight()-1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3prime(neighbors) == 0)
mask[i][j]++;
}
for(int i = 0; i < ip.getWidth(); i++)
for(int j = 0; j < ip.getHeight(); j++) {
if (mask[i][j] != 0) sum++;
ip.putPixel(i, j, mask[i][j] > 0 ? 0 : ip.getPixel(i,j));
}
return sum;
}
The problem in your original code is that you write into your input image. In the very first iteration, moving left to right, you remove successive pixels because each has, after modifying the previous pixel, a background pixel as neighbor.
There are different ways to implement the thinning operation, but the simplest one that works in-place like your code does requires two passes through the image for each iteration of the thinning:
Go through the image and mark all candidate pixels. These are the pixels that have a background neighbor. Marking a pixel can be as simple as setting the pixel value to a given constant, for example 42 (assuming background is 0 and foreground is 1 or 255 or whatever you decided on).
Go through the image again and for each marked pixel, determine if removing it would change the geometry of the foreground. If not, remove it. In this test, take the marked pixels that haven't been removed yet as foreground.
Related
Hello so am trying to create a 2D array of int with random number of rows and columns and a random starting and ending points using java to apply the A* algorithm on it.
When i add {S} and {E} to define the tow points and print it there are numbers outside of the 2D array printed.
`Random rand = new Random();
int min = 2, max = 10;
// a random number of rows and columns
int a = (int)(Math.random() * (max - min + 1)) + min;
// the location of the starting point.
int row_start = rand.nextInt(a);
int col_start = rand.nextInt(a);
// the location of the ending point.
int row_end = rand.nextInt(a);
int col_end = rand.nextInt(a);
int [][] M = new int [a][a];
public void create() {
//empty: 0; grass: 1; sand: 2; water: 3; wall: 4.
for (int i = 0; i < a; i++) {
for (int j = 0; j < a; j++) {
M[i][j] = rand.nextInt(5);
}
}
for (int i = 0; i < a; i++) {
for (int j = 0; j < a; j++) {
System.out.print(" " +M[i][j] + "\t");
if(row_start == i && col_start == j) {
System.out.print("{S}" + "\t");
}
if(row_end == i && col_end == j) {
System.out.print("{E}" + "\t");
}
}
System.out.print("\n");
}
}`
the output looks like this:
1 0 4 0
2 {S} 1 2 2
4 4 {E} 0 3
2 0 3 3
the 2 and 3 shouldn't appear there.
The problem is that you always print m[i][j].
What you need is to only print m[i][j] when i and j are not S and E positions. When i and j are S and E positions, print S or E. Otherwise, print m[i][j].
if(row_start == i && col_start == j) {
System.out.print("{S}" + "\t");
} else if(row_end == i && col_end == j) {
System.out.print("{E}" + "\t");
} else {
System.out.print(" " +M[i][j] + "\t");
}
I'm currently try to print below pattern in java,please help me in solving it.
Input: 3, abcdefghijklm
output:
c
bjd
aimke
hlf
g
I build diamond pattern with star, stuck in print values from array in spirally in diamond shape show above.
public static void rhombus() {
int n = 3;
int size = 2 * n - 1;
char[][] sol = new char[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
sol[i][j] = ' ';
}
}
int i = size / 2;
int j = 0;
String s = "abcdefghijklmnop";
int len = s.length();
int in = 0;
int left = 0, top = 0, right = size - 1;
int bottom = size - 1;
boolean flag = false;
while (i != j) {
while (i >= top && !flag) {
sol[i][j] = s.charAt((in++) % len);
if (i == size / 2 && j == size / 2)
flag = true;
i--;
j++;
}
if (flag == true)
break;
i += 2;
top++;
left++;
while (j <= right && !flag) {
sol[i][j] = s.charAt((in++) % len);
i++;
j++;
}
j -= 2;
right--;
while (i <= bottom && !flag) {
sol[i][j] = s.charAt((in++) % len);
i++;
j--;
}
bottom--;
i -= 2;
while (j >= left && !flag) {
sol[i][j] = s.charAt((in++) % len);
i--;
j--;
}
j++;
}
sol[i][j] = s.charAt((in++) % len);
for (int a = 0; a < size; a++) {
for (int b = 0; b < size; b++) {
System.out.print(sol[a][b]);
}
System.out.println();
}
}
Can somebody help me a bit? I have trouble understanding why Boolean here doesn't work the way I want to. The idea is when i(firstnum) is odd, l(lastnum) to be equal and vice verse. Some help with how to use Boolean also will be a help, I can't understand it.
Input 3 and 5.
Expected output : 4333 4353 4443 4533 4553 5334 5354 5444 5534 5554
Actual output: 4333 4353 4443 4533 4553 5333 5334 5353 5354 5443 5444 5533 5534 5553 5554
int startNum = Integer.parseInt(scan.nextLine());
int endNum = Integer.parseInt(scan.nextLine());
boolean isItEqual = false;
boolean isItOdd= false;
int countDebugOperations = 0;
for (int i = startNum; i <=endNum ; i++) {
if (i % 2==0){
isItEqual =true;
}
for (int j = startNum; j <=endNum ; j++) {
for (int k = startNum; k <=endNum ; k++) {
for (int l = startNum; l <=endNum ; l++) {
if (l % 2 == 1){
isItOdd = true;
}
boolean flag =(i > l) && (j+k) % 2 ==0;
if(!isItEqual && (!isItOdd) && flag){
countDebugOperations+=1;
System.out.printf("%d%d%d%d ",i,j,k,l);
}
if (isItEqual && isItOdd && flag) {
countDebugOperations += 1;
System.out.printf("%d%d%d%d ", i, j, k, l);
}
You are trying to print numbers i, j, k and l in exactly two cases:
When i is even AND l is odd
When l is even AND i is odd
If we translate those cases to code (boolean expressions), we get:
i % 2 == 0 && l % 2 == 1
l % 2 == 0 && i % 2 == 1
Now, when we iterate through for loops, we can ask if our "number state" matches one of those 2 cases (first case OR second case).
int startNum = Integer.parseInt(scan.nextLine());
int endNum = Integer.parseInt(scan.nextLine());
for (int i = startNum; i <= endNum; i++) {
for (int j = startNum; j <= endNum; j++) {
for (int k = startNum; k <= endNum; k++) {
for (int l = startNum; l <= endNum; l++) {
boolean firstCase = i % 2 == 0 && l % 2 == 1;
boolean secondCase = l % 2 == 0 && i % 2 == 1;
// now when we print, we can ask if we are in the first OR the second case
if (firstCase || secondCase) {
System.out.printf("%d%d%d%d ",i,j,k,l);
}
}
}
}
}
I have been given the task of writing a script to "erode" a binary image i.e. black and white photo.
This means that I must distinguish the parts that are white from black, where on an RGB scale, black is 0 and 1 is white.
Pixels are iterated over on a horizontal (i index) and vertical (j index). In order for a pixel to be considered a particular colour, it's immediate neighbours must be of that colour i.e. i+1 and i-1 and j+1 and j-1.
My attempt to code this is as follows:
public static BufferedImage getErodedImage(BufferedImage image) {
BufferedImage target = copyImage(image);
for (int i = 0; i < image.getRaster().getWidth(); i++) {
for (int j = 0; j < image.getRaster().getHeight(); j++) {
if (i + 1)||(i - 1) == 0 {
i = 0
}
else{
i = 1
}
}
if (j + 1)||(j - 1) == 0 {
j = 0
}
else{
j = 1
}
}
}
My attempt is very pythonic and returns lots of Errors and I'm guessing that I might need another for loop to iterate the -1, 0 and +1 values. and then set the value of the i-th pixel.
In your code a lot of syntax error, try to use this code:
public static BufferedImage getErodedImage(BufferedImage image) {
BufferedImage target = copyImage(image);
for (int i = 0; i < image.getRaster().getWidth(); i++) {
for (int j = 0; j < image.getRaster().getHeight(); j++) {
if (i + 1 == 0 || i - 1 == 0) { // not if (i + 1)||(i - 1) == 0
i = 0; // ;
}
else{
i = 1; // ;
}
if (j + 1 == 0 ||j - 1 == 0) { // not if (j + 1)||(j - 1) == 0 and this "if" should be in "for (int j..."
j = 0; // ;
}
else{
j = 1; // ;
}
}
}
}
I have to find the maximum sum path in a 2d Array(n,m) given which has a value from 0 to 99999. 0 means wall. We have t start from the left bottom side of the array and must reach the right top cell(0,m-1). You can go up/down/right and can visit each cell once. Below is the code without any blocks .My problem is that i cant move from left bottom to right top cell . I also created left array(lest side of the main array) so that i can start from the best value possible .Sorry am not good programmer :).
Code
public static int maxvalue(int [][]field,int[] left)
{
for(int i=field.length-1;i>0 && left[i]!=-1;i--)
{
System.out.println( "Startpos "+i+" 0");
int distance =max(i,0,field,0,field.length-1);
if(distance>maxvalue)
maxvalue=distance;
}
return maxvalue;
}
public static int max(int r, int c,int [][]field ,int destR, int destC)
{
if(r>destR|| c>destC)
return 0;
if(r==0 && c==field[0].length)
return field[r][c];
int sum1=max(r-1,c,field,destR,destC); // up
System.out.println(sum1);
int sum2= max(r+1,c,field,destR,destC); //down
int sum3= max(r,c+1,field,destR,destC); //right
return field[r][c]+Math.max(sum1, Math.max(sum2, sum3));
}
Sample
Input
0 1 2 3
2 0 2 4
3 3 0 3
4 2 1 2
Output
25
How to do solve this question? if all the path is blocked then print No Solution.
Have you first tried to solve it by yourself?
It looks like a bit of work but it is not impossible.
What I would use is 3 int variables : xPosition, yPosition and Sum;
Go on and test the values of xPosition+1, yPosition-1 in priority and then the rest (because you want to reach xPosition == array.length - 1 && yPosition == 0.) and if you find a 0, test the other possibilities and exclude the ones you already passed by.
Each time you find a good path, add the value of the cell to your sum.
Reset it to 0 once you're blocked.
For every element in the array, you have to find the maximum of the adjacent elements and also check the boundary conditions. I hope this code will help you.
public class StackOverFlow {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
Integer [][] array = new Integer[n][m];
boolean [][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
array[i][j] = in.nextInt();
}
}
int i = n-1, j =0;
visited[i][j] = true;
int sum = array[i][j];
while(true)
{
int max = -1;
int maxi = 0, maxj = 0;
if(i-1 >= 0 && i-1<= n-1 && j>=0 && j<= m-1 && array[i-1][j] != null && array[i-1][j]>max && !visited[i-1][j])
{
max = array[i-1][j];
maxi = i-1;
maxj=j;
}
if(i+1 >= 0 && i+1<= n-1 && j>=0 && j<= m-1 &&array[i+1][j] != null && array[i+1][j]>max && !visited[i+1][j])
{
max = array[i+1][j];
maxi = i+1;
maxj=j;
}
if(i >= 0 && i<= n-1 && j-1>=0 && j-1<= m-1 && array[i][j-1] != null && array[i][j-1]>max && !visited[i][j-1])
{
max = array[i][j-1];
maxi = i;
maxj=j-1;
}
if(i >= 0 && i<= n-1 && j+1>=0 && j+1<= m-1 && array[i][j+1] != null && array[i][j+1]>max && !visited[i][j+1])
{
max = array[i][j+1];
maxi = i;
maxj=j+1;
}
i = maxi;
j = maxj;
visited[i][j] = true;
sum += max;
if(i == 0 && j == m-1)
break;
}
System.out.println(sum);
}
}