Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Sobel Operator Edge Detection

by t-k (Novice)
on Jul 08, 2012 at 10:35 UTC ( [id://980568]=CUFP: print w/replies, xml ) Need Help??

Haven't found any perl implementations of Sobel Operator so I was forced to rewrite processing.org one to perl. It uses binary colour values (black and white).
Grab the code:
#!/usr/local/bin/perl use strict; use warnings; use Image::Magick; sub sobelEdgeDetection($); my $inputImage = 'input.jpg'; my $outputImage = 'output.jpg'; my $Img = new Image::Magick; my $warn = $Img->Read($inputImage); print "$warn"; my $foo = sobelEdgeDetection($Img); $warn = $foo->Write($outputImage); print "$warn"; sub sobelEdgeDetection($) { my $imSrcImg = shift; my $buf = $imSrcImg->Clone(); my @GX = ( [ -1, 0, 1 ], [ -2, 0, 2 ], [ -1, 0, 1 ] ); my @GY = ( [ 1, 2, 1 ], [ 0, 0, 0 ], [ -1, -2, -1 ] ); my $tolerance = 90; my $sumRx = 0; my $sumGx = 0; my $sumBx = 0; my $sumRy = 0; my $sumGy = 0; my $sumBy = 0; my $finalSumR = 0; my $finalSumG = 0; my $finalSumB = 0; my $gray = 0; my ( $width, $height ) = $imSrcImg->Get( 'width', 'height' ); # Iterate over every pixel in the image and change for my $y ( 1 .. ( $height - 2 ) ) { for my $x ( 1 .. ( $width - 2 ) ) { for ( my $i = -1 ; $i <= 1 ; $i++ ) { for ( my $j = -1 ; $j <= 1 ; $j++ ) { my @pixel = $imSrcImg->GetPixel( x => $x + $i, y => $y + $j +); #GetPixel method returns normalized floated colors + 0..1 so they need to be converted my $r = int( $pixel[0] * 255 ); my $g = int( $pixel[1] * 255 ); my $b = int( $pixel[2] * 255 ); $sumRx += $r * $GX[ $i + 1 ][ $j + 1 ]; $sumGx += $g * $GX[ $i + 1 ][ $j + 1 ]; $sumBx += $b * $GX[ $i + 1 ][ $j + 1 ]; $sumRy += $r * $GY[ $i + 1 ][ $j + 1 ]; $sumGy += $g * $GY[ $i + 1 ][ $j + 1 ]; $sumBy += $b * $GY[ $i + 1 ][ $j + 1 ]; } } $finalSumR = abs($sumRx) + abs($sumRy); $finalSumG = abs($sumGx) + abs($sumGy); $finalSumB = abs($sumBx) + abs($sumBy); $gray = ( $finalSumR + $finalSumG + $finalSumB ) / 3; if ( $gray > $tolerance ) { $buf->Set( "pixel[$x,$y]" => "white" ); } else { $buf->Set( "pixel[$x,$y]" => "black" ); } $sumRx = 0; $sumGx = 0; $sumBx = 0; $sumRy = 0; $sumGy = 0; $sumBy = 0; $gray = 0; } } return $buf; }

Replies are listed 'Best First'.
Re: Sobel Operator Edge Detection
by zentara (Archbishop) on Jul 08, 2012 at 11:44 UTC
    It works great, but do you really need the sub prototype? Removing the prototype works just as well.
    #sub sobelEdgeDetection($); sub sobelEdgeDetection { }

    Also, I don't know the exact differences, but the IM charcoal method produces similar output, but quicker. :-)

    #!/usr/bin/perl use warnings; use strict; use Image::Magick; my $file = shift or die "need a file\n";; my $p = new Image::Magick; $p->Read($file); $p->Charcoal('0x1'); $p->Write($0.'.jpg'); exit;

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      Hi zentara,
      There are multiple edge detection alghoritms, and since they return different outputs they are often implemented to compare and determine the most desired result. Image::Magick has it's own edge detection implementation but AFAIK it's not Sobel.
      Cheers
Re: Sobel Operator Edge Detection
by dwalton76 (Initiate) on Mar 08, 2013 at 21:49 UTC
    Thank you for posting this. I was able to speed it up some by storing the RGB pixel values in 2D arrays. The image that I am testing originally took 28 seconds to process and I have it down to 12 seconds. I'll cut-n-paste the parts that I changed:
    my $gray = 0; my ( $width, $height ) = $imSrcImg->Get( 'width', 'height' ); my @pixels_red; my @pixels_green; my @pixels_blue; for (my $x = 0; $x < $width; $x++) { for (my $y = 0; $y < $height; $y++) { (my $red, my $green, my $blue) = split(',', $imSrcImg->Get(" +pixel[$x,$y]")); $pixels_red[$x][$y] = $red; $pixels_green[$x][$y] = $green; $pixels_blue[$x][$y] = $blue; } } # Iterate over every pixel in the image and change for my $y ( 1 .. ( $height - 2 ) ) { for my $x ( 1 .. ( $width - 2 ) ) { for ( my $i = -1 ; $i <= 1 ; $i++ ) { for ( my $j = -1 ; $j <= 1 ; $j++ ) { my $r = $pixels_red[$x + $i][$y + $j]; my $g = $pixels_green[$x + $i][$y + $j]; my $b = $pixels_blue[$x + $i][$y + $j]; my $tmp_GX = $GX[ $i + 1 ][ $j + 1 ]; my $tmp_GY = $GY[ $i + 1 ][ $j + 1 ]; if ($tmp_GX) { $sumRx += $r * $tmp_GX; $sumGx += $g * $tmp_GX; $sumBx += $b * $tmp_GX; } if ($tmp_GY) { $sumRy += $r * $tmp_GY; $sumGy += $g * $tmp_GY; $sumBy += $b * $tmp_GY; } } }
    The rest of the code is the same.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://980568]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-24 06:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found