0
votes

I am trying to write a sobel edge detecting program in java. But i am getting werid outputs. HELP. Here is my program.

import java.io.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.util.Scanner;
import java.lang.Math;

public class sobeltest
{
  public static void main(String args[]) throws IOException{

    System.out.println("Enter the file name :");
    Scanner ne1=new Scanner(System.in);
    String filename=ne1.nextLine();


   File file= new File(filename);
   BufferedImage image = ImageIO.read(file);

   int x=image.getWidth();
   int y=image.getHeight();

   for(int i=1;i<x-1;i++)
    {
     for(int j=1;j<y-1;j++)
      {

     int val00=image.getRGB(i-1,j-1);
     int val01=image.getRGB(i-1,j);
     int val02=image.getRGB(i-1,j+1);

     int val10=image.getRGB(i,j-1);
     int val11=image.getRGB(i,j);
     int val12=image.getRGB(i,j+1);

     int val20=image.getRGB(i+1,j-1);
     int val21=image.getRGB(i+1,j);
     int val22=image.getRGB(i+1,j+1);

     int gx=(((-1*val00)+(0*val01)+(1*val02))+((-2*val10)+(0*val11)+(2*val12))+((-1*val20)+(0*val21)+(1*val22)));
     int gy=(((-1*val00)+(-2*val01)+(-1*val02))+((0*val10)+(0*val11)+(0*val12))+((1*val20)+(2*val21)+(1*val22)));

     double gval=Math.sqrt((gx*gx)+(gy*gy));
     int g=(int)gval;

     image.setRGB(i,j,g);

      }
      }
    File outputfile = new File("sobel.png");
    ImageIO.write(image, "png", outputfile);
  }
  }

INPUT IMAGE: This is input image i given

and here is the output i get when i run the code. OUTPUT IMAGE

......................................

1
Just for the record: you dont come here and order/ask to "provide a working solution". You try to ask a good question; and then we see what we do. But rarely that means that somebody will drop a working solution on you! In that sense: simply avoid such statements; they could come over a bit ... rude ...GhostCat
Hint: you can still edit your question ;-)GhostCat
Got the message and it's done.Project-A

1 Answers

5
votes

There are two issues with your code. First is that code is supposed to use color components (R,G,B) in calculation instead of the color integer itself.

int val00=image.getRGB(i-1,j-1);
//Should be
int val00 = getGrayScale(image.getRGB(i - 1, j - 1));

Where getGrayScale() gives the luminance of the color in gray scale, otherwise you can use all three components individually.

Second issue is that you're directly setting gcal or g gradient value to the color. This again should be a component only and should be converted to the color using g<<16 | g<<8 | g.

However g is not necessarily in range 0-255, so we have to take care of that by finding the max g and then normalizing all the gradients using 255/max(g).

Following is working code.

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class SobelTest {
    public static void main(String args[]) throws IOException {

        System.out.println("Started");
        /*System.out.println("Enter the file name :");
        Scanner ne1 = new Scanner(System.in);
        String filename = ne1.nextLine();*/

        String filename = "engine.png";

        File file = new File(filename);
        BufferedImage image = ImageIO.read(file);

        int x = image.getWidth();
        int y = image.getHeight();

        int maxGval = 0;
        int[][] edgeColors = new int[x][y];
        int maxGradient = -1;

        for (int i = 1; i < x - 1; i++) {
            for (int j = 1; j < y - 1; j++) {

                int val00 = getGrayScale(image.getRGB(i - 1, j - 1));
                int val01 = getGrayScale(image.getRGB(i - 1, j));
                int val02 = getGrayScale(image.getRGB(i - 1, j + 1));

                int val10 = getGrayScale(image.getRGB(i, j - 1));
                int val11 = getGrayScale(image.getRGB(i, j));
                int val12 = getGrayScale(image.getRGB(i, j + 1));

                int val20 = getGrayScale(image.getRGB(i + 1, j - 1));
                int val21 = getGrayScale(image.getRGB(i + 1, j));
                int val22 = getGrayScale(image.getRGB(i + 1, j + 1));

                int gx =  ((-1 * val00) + (0 * val01) + (1 * val02)) 
                        + ((-2 * val10) + (0 * val11) + (2 * val12))
                        + ((-1 * val20) + (0 * val21) + (1 * val22));

                int gy =  ((-1 * val00) + (-2 * val01) + (-1 * val02))
                        + ((0 * val10) + (0 * val11) + (0 * val12))
                        + ((1 * val20) + (2 * val21) + (1 * val22));

                double gval = Math.sqrt((gx * gx) + (gy * gy));
                int g = (int) gval;

                if(maxGradient < g) {
                    maxGradient = g;
                }

                edgeColors[i][j] = g;
            }
        }

        double scale = 255.0 / maxGradient;

        for (int i = 1; i < x - 1; i++) {
            for (int j = 1; j < y - 1; j++) {
                int edgeColor = edgeColors[i][j];
                edgeColor = (int)(edgeColor * scale);
                edgeColor = 0xff000000 | (edgeColor << 16) | (edgeColor << 8) | edgeColor;

                image.setRGB(i, j, edgeColor);
            }
        }

        File outputfile = new File("sobel.png");
        ImageIO.write(image, "png", outputfile);

        System.out.println("max : " + maxGradient);
        System.out.println("Finished");
    }

    public static int  getGrayScale(int rgb) {
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = (rgb) & 0xff;

        //from https://en.wikipedia.org/wiki/Grayscale, calculating luminance
        int gray = (int)(0.2126 * r + 0.7152 * g + 0.0722 * b);
        //int gray = (r + g + b) / 3;

        return gray;
    }
}

Output

enter image description here

Edit

Second image contains an alpha channel opposed to the first one, please see the details of both below.

#Engine
type = 5 ColorModel: #pixelBits = 24 numComponents = 3 has alpha = false
#Type 5 is BufferedImage.TYPE_3BYTE_BGR
#Girl
type = 6 ColorModel: #pixelBits = 32 numComponents = 4 has alpha = true
#type 6 is BufferedImagef.TYPE_4BYTE_ABGR

Since second image contains alpha component and we are not setting alpha it becomes completely transparent.

Following part of the code needs to be changed to set alpha to opaque.

edgeColor = (edgeColor << 16) | (edgeColor << 8) | edgeColor;
//Should be
edgeColor = 0xff000000 | (edgeColor << 16) | (edgeColor << 8) | edgeColor;

I have changed the original code above with the same.

Here's Output with the change.

enter image description here

To get the edges like in the image in your comment, you will have to group edge based on the direction of the gradient and use a suitable threshold to ignore the weak edges.