Search code examples
javamathimage-processingimagej

Implenting a Sobel filter in ImageJ


Hello Im trying to implement a Sobel filter in imagej by creating my own plugin. I have code that works but, its not properly highlighting the edges white. Ive been trying for a while now and I just cant figure out what im doing wrong or perhaps I do not not fully understand the implantation of the sobel filter and or do not understand the math. Any help will be greatly appreciated. Here is my code:

import ij.*;
import ij.process.*;
import ij.gui.*;
import java.util.*;
import java.awt.*;
import ij.plugin.filter.*;
import ij.process.*;
import java.lang.Math.*;

public class Filter_Plugin implements PlugInFilter {
String title = null; 

int sobel_x[][] = {{-1,0,1},
                        {-2,0,2},
                            {-1,0,1}};

        int sobel_y[][] = {{-1,-2,-1},
                            {0,0,0},
                            {1,2,1}};

int pixel_x;
int pixel_y;

public int setup(String arg, ImagePlus im) { 
    title = im.getTitle(); 
    return DOES_8G; 
} 

public void run(ImageProcessor ip) { 

    int w = ip.getWidth();
    int h = ip.getHeight();
    ImageProcessor copy = ip.duplicate(); 

     for (int x=1; x < w-2; x++) 
     {
            for (int y=1; y < h-2; y++) 
        {
            pixel_x = 1/6 * (sobel_x[0][0] * copy.getPixel(x-1,y-1)) + (sobel_x[0][1] * copy.getPixel(x,y-1)) + (sobel_x[0][2] * copy.getPixel(x+1,y-1)) +
                    (sobel_x[1][0] * copy.getPixel(x-1,y))   + (sobel_x[1][1] * copy.getPixel(x,y))   + (sobel_x[1][2] * copy.getPixel(x+1,y)) +
                            (sobel_x[2][0] * copy.getPixel(x-1,y+1)) + (sobel_x[2][1] * copy.getPixel(x,y+1)) + (sobel_x[2][2] * copy.getPixel(x+1,y+1));

            pixel_y = 1/6 * (sobel_y[0][0] * copy.getPixel(x-1,y-1)) + (sobel_y[0][1] * copy.getPixel(x,y-1)) + (sobel_y[0][2] * copy.getPixel(x+1,y-1)) +
                    (sobel_y[1][0] * copy.getPixel(x-1,y))   + (sobel_y[1][1] * copy.getPixel(x,y))   + (sobel_y[1][2] * copy.getPixel(x+1,y)) +
                            (sobel_y[2][0] * copy.getPixel(x-1,y+1)) + (sobel_y[2][1] * copy.getPixel(x,y+1)) + (sobel_x[2][2] * copy.getPixel(x+1,y+1));

            int val = (int)Math.sqrt((pixel_x * pixel_x) + (pixel_y * pixel_y));

            if(val < 0)
            {
               val = 0;
            }

            if(val > 255)
            {
                  val = 255;
            }

            ip.putPixel(x,y,val);

             }
        }
 }

}


Solution

  • There's a mistake in your calculation: you are multiplying by 1/6 only the first summand (i.e. the upper left corner of your matrix). By removing this factor, I get the following code that works for me:

    import ij.*;
    import ij.process.*;
    import ij.gui.*;
    import java.util.*;
    import java.awt.*;
    import ij.plugin.filter.*;
    import ij.process.*;
    import java.lang.Math.*;
    
    public class Filter_Plugin implements PlugInFilter {
        String title = null; 
        int sobel_x[][] = {{-1,0,1},
                           {-2,0,2},
                           {-1,0,1}};
        int sobel_y[][] = {{-1,-2,-1},
                           {0,0,0},
                           {1,2,1}};
        int pixel_x;
        int pixel_y;
    
        public int setup(String arg, ImagePlus im) { 
            title = im.getTitle(); 
            return DOES_8G; 
        } 
    
        public void run(ImageProcessor ip) { 
            int w = ip.getWidth();
            int h = ip.getHeight();
            ImageProcessor copy = ip.duplicate(); 
            for (int x=1; x < w-2; x++) {
                for (int y=1; y < h-2; y++) {
                    pixel_x = (sobel_x[0][0] * copy.getPixel(x-1,y-1)) + (sobel_x[0][1] * copy.getPixel(x,y-1)) + (sobel_x[0][2] * copy.getPixel(x+1,y-1)) +
                        (sobel_x[1][0] * copy.getPixel(x-1,y))   + (sobel_x[1][1] * copy.getPixel(x,y))   + (sobel_x[1][2] * copy.getPixel(x+1,y)) +
                        (sobel_x[2][0] * copy.getPixel(x-1,y+1)) + (sobel_x[2][1] * copy.getPixel(x,y+1)) + (sobel_x[2][2] * copy.getPixel(x+1,y+1));
                    pixel_y = (sobel_y[0][0] * copy.getPixel(x-1,y-1)) + (sobel_y[0][1] * copy.getPixel(x,y-1)) + (sobel_y[0][2] * copy.getPixel(x+1,y-1)) +
                        (sobel_y[1][0] * copy.getPixel(x-1,y))   + (sobel_y[1][1] * copy.getPixel(x,y))   + (sobel_y[1][2] * copy.getPixel(x+1,y)) +
                        (sobel_y[2][0] * copy.getPixel(x-1,y+1)) + (sobel_y[2][1] * copy.getPixel(x,y+1)) + (sobel_x[2][2] * copy.getPixel(x+1,y+1));
    
                    int val = (int)Math.sqrt((pixel_x * pixel_x) + (pixel_y * pixel_y));
    
                    if(val < 0)
                    {
                       val = 0;
                    }
    
                    if(val > 255)
                    {
                       val = 255;
                    }
    
                    ip.putPixel(x,y,val);
                }
            }
        }
    }
    

    Have you had a look at Stephan Preibisch's Sobel Filter Plugin as a reference?

    Maybe you should make your output a 32-bit float image instead of truncating the values at 0 and 255.