简体   繁体   中英

Sobel Edge Detecting program in java

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: 这是我给的输入图像

and here is the output i get when i run the code. 输出图像

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

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 g<<16 | g<<8 | g 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

在此处输入图片说明

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.

在此处输入图片说明

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM