Edge detection with sobel operator/mask

Apprentice
Posts: 8
Joined: 2010.07
Post: #1
Hi. I'm trying to write little program that is able to detect edges. But it's not working correctly. I want to detect edges and get orientation (angle) of this egdes. So I'm using Sobel Mask/Operator to do this.

The Sobel operator performs a 2-D spatial gradient measurement on an image. Typically it is used to find the approximate absolute gradient magnitude at each point in an input grayscale image. The Sobel edge detector uses a pair of 3x3 convolution masks, one estimating the gradient in the x-direction (columns) and the other estimating the gradient in the y-direction (rows).

Masks are:
Gx:
-1 0 1
-2 0 2
-1 0 1

Gy:
1 2 1
0 0 0
-1 -2 -1

My code looks like this:
Code:
NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithData:[loadedImage TIFFRepresentation]];
    NSInteger width = [bitmapImageRep pixelsWide];
    NSInteger height = [bitmapImageRep pixelsHigh];
    
    int Gx[3][3];
    int Gy[3][3];
    int col = 0;
    int row = 0;
    
    int sumX, sumY;
    int SUM;
    int I, J;
    
    // Sobel Mask, Gx
    Gx[0][0]=-1;    Gx[0][1]=0;     Gx[0][2]=1;
    Gx[1][0]=-2;    Gx[1][1]=0;     Gx[1][2]=2;
    Gx[2][0]=-1;    Gx[2][1]=0;     Gx[2][2]=1;
    
    // Sobel Mask, Gy
    Gy[0][0]=1;     Gy[0][1]=2;     Gy[0][2]=1;
    Gy[1][0]=0;     Gy[1][1]=0;     Gy[1][2]=0;
    Gy[2][0]=-1;    Gy[2][1]=-2;    Gy[2][2]=-1;
    
    //
    unsigned char *pixels;
    NSBitmapImageRep *bitmap2;
    NSGraphicsContext *context;
    
    pixels = malloc(width * height);
    
    bitmap2 = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &pixels
                                                      pixelsWide: width
                                                      pixelsHigh: height
                                                   bitsPerSample: 8
                                                 samplesPerPixel: 1
                                                        hasAlpha: NO
                                                        isPlanar: NO
                                                  colorSpaceName: NSCalibratedWhiteColorSpace
                                                    bitmapFormat: 0
                                                     bytesPerRow: width
                                                    bitsPerPixel: 8];
    
    context = [NSGraphicsContext graphicsContextWithBitmapImageRep: bitmap2];
    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext: context];
    [bitmapImageRep drawInRect: NSMakeRect(0, 0, width, height)];
    [NSGraphicsContext restoreGraphicsState];
    //
    
    /*-----------------------------------
            Sobel Mask Algorithm
    -----------------------------------*/
    for(col=0; col<width-1; col++) {
        for(row=0; row<height-1; row++) {
            sumX = 0;
            sumY = 0;
            
            // Image boundaries
            /*if (height==0)
                SUM=0;
            else if (width==0)
                SUM=0;
            else {*/
            // Gradient X
            /*for(I=-1; I<=1; I++) {
                for(J=-1; J<=1; J++) {
                    sumX += pixels[(row+I)*width + (col+J)]*Gx[I+1][J+1];
                    //sumX += pixels[row][col]*Gx[I+1][J+1];
                    //pixels[(row*width + col)] = pixels[(row*width + col)]*Gx[I+1][J+1];
                }
            }*/
            /*
            // Gradient Y
            for(I=-1; I<=1; I++) {
                for(J=-1; J<=1; J++) {
                    sumY += pixels[row*width + col]*Gy[I+1][J+1];
                }
            }*/
                
            // Gradient
            //SUM = sqrt(pow((double)sumX, 2.0) + pow((double)sumY, 2.0));
            
            //pixels[(row*width + col)] = 255 - SUM;
            pixels[(row*width + col)] = abs( (pixels[((row+1)*width + (col-1))] + 2*pixels[((row+1)*width + col)] + pixels[((row+1)*width + (col+1))]) - (pixels[((row-1)*width + (col-1))] + 2*pixels[((row-1)*width + col)] + pixels[((row+1)*width + (col+1))] ));
        }
    }
    
    producedImage = [[NSImage alloc] init];
    [producedImage addRepresentation:bitmap2];
    
    [bitmap2 release];
    
    [processedImage setImage: producedImage];

In above code there are two methods to apply this mask. One is commented:
Code:
// Gradient X
            /*for(I=-1; I<=1; I++) {
                for(J=-1; J<=1; J++) {
                    sumX += pixels[(row+I)*width + (col+J)]*Gx[I+1][J+1];
                    //sumX += pixels[row][col]*Gx[I+1][J+1];
                    //pixels[(row*width + col)] = pixels[(row*width + col)]*Gx[I+1][J+1];
                }
            }*/
            /*
            // Gradient Y
            for(I=-1; I<=1; I++) {
                for(J=-1; J<=1; J++) {
                    sumY += pixels[row*width + col]*Gy[I+1][J+1];
                }
            }*/
                
            // Gradient
            //SUM = sqrt(pow((double)sumX, 2.0) + pow((double)sumY, 2.0));

Second one:
Code:
pixels[(row*width + col)] = abs( (pixels[((row+1)*width + (col-1))] + 2*pixels[((row+1)*width + col)] + pixels[((row+1)*width + (col+1))]) - (pixels[((row-1)*width + (col-1))] + 2*pixels[((row-1)*width + col)] + pixels[((row+1)*width + (col+1))] ));

is commonly used approximation. But when using first or second way i receive this:

[Image: processedlena.th.png]

Can someone help me with this problem?
Quote this message in a reply
Apprentice
Posts: 8
Joined: 2010.07
Post: #2
Slowly forward. I added some simple code
Code:
if (SUM>255)
                SUM=255;
            else if (SUM<0)
                SUM=0;

after

Code:
SUM = abs(sumX) + abs(sumY);

and I receive something closer to what I'm looking for

[Image: zrzutekranu20110517godz.th.png]

But still it's not properly done edge detection.
Quote this message in a reply
⌘-R in Chief
Posts: 1,260
Joined: 2002.05
Post: #3
Wrote this up quickly... (first time I've done it as well)


[Image: upshot_RoJ9vM2R.jpg]


Code:
uint8_t Convolute(const char * src, int x, int y);
int Convolute2(const char * src, int x, int y, int G[]);
int Gx[] = { -1, 0, 1,  -2, 0, 2,  -1, 0, 1 };
int Gy[] = { -1, -2, -1,  0, 0, 0,  1, 2, 1 };


#define SRC(__x, __y)           (*(src + (__y) * 256 + (__x)))



uint8_t Convolute(const char * src, int x, int y)
{
        int xx = Convolute2(src, x, y, Gx);
        int yy = Convolute2(src, x, y, Gy);
        int r = sqrt(xx * xx + yy * yy);
        return (uint8_t)MAX(0, MIN(255, r));
}


int Convolute2(const char * src, int x, int y, int G[])
{
        int center = SRC(x, y);
        int v[9];
        int r = 0;
        
        v[0] = (x >   0 && y >   0) ? SRC(x - 1, y - 1) : center;
        v[1] = (           y >   0) ? SRC(x    , y - 1) : center;
        v[2] = (x < 255 && y >   0) ? SRC(x + 1, y - 1) : center;

        v[3] = (x >   0           ) ? SRC(x - 1, y    ) : center;
        v[4] = center;
        v[5] = (x < 255           ) ? SRC(x + 1, y    ) : center;

        v[6] = (x >   0 && y < 255) ? SRC(x - 1, y + 1) : center;
        v[7] = (           y < 255) ? SRC(x    , y + 1) : center;
        v[8] = (x < 255 && y < 255) ? SRC(x + 1, y + 1) : center;

        
        r += (G[0] * v[0]) + (G[1] * v[1]) + (G[2] * v[2]) +
                 (G[3] * v[3]) + (G[4] * v[4]) + (G[5] * v[5]) +
                 (G[6] * v[6]) + (G[7] * v[7]) + (G[8] * v[8]);
                
        return r;
}



- (PNMImage *)findEdges:(PNMImage *)image;
{
        NSMutableData * data = [NSMutableData dataWithLength:256*256];
        const char * src = [image.originalData bytes];
        char * dst = [data mutableBytes];
        
        
        for (int y = 0; y < 256; y++) {
                for (int x = 0; x < 256; x++) {
                        *(dst + y * 256 + x) = Convolute(src, x, y);
                }
        }
                
        return [[[PNMImage alloc] initWithData:data type:PNMGrayscaleImageType pixelsWide:256 pixelsHigh:256 maximumValue:255] autorelease];
}



- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
        PNMImage * image = [PNMImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"lena" ofType:@"pgm"]];
        PNMImage * edges = [self findEdges:image];
        
        [imageView1 setImage:image.image];
        [imageView2 setImage:edges.image];
}
Quote this message in a reply
Apprentice
Posts: 8
Joined: 2010.07
Post: #4
Ok, mine also is working now. Some novice mistake - calculated value I should store in new matrix, not write it directly to image matrix.
Quote this message in a reply
⌘-R in Chief
Posts: 1,260
Joined: 2002.05
Post: #5
So what are you doing with this filtered image, now?
Quote this message in a reply
Apprentice
Posts: 8
Joined: 2010.07
Post: #6
This little program was to test sobel mask. I will use it in program to fingerprint recognition. Grad_x and grad_y will be used to get orientation diagram.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Pasting an image with alpha mask on a texture Najdorf 10 5,908 Jun 24, 2008 03:23 PM
Last Post: Najdorf
  Changing the Mask in OpenGL kodex 2 3,835 Jan 18, 2006 09:21 PM
Last Post: kodex
  Smoothing edges with alpha mask McSebi 18 9,752 Nov 3, 2005 11:39 AM
Last Post: McSebi