Bitmap Edge and Orientation Transform Best

by j2e forked from Bitmap Edge and Orientation Transform (diff: 340)
♥0 | Line 307 | Modified 2011-01-10 22:52:06 | MIT License
play

ActionScript3 source code

/**
 * Copyright j2e ( http://wonderfl.net/user/j2e )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/afdj
 */

// forked from j2e's Bitmap Edge and Orientation Transform
package {
    
    /// written by j2e japanese2english@gmail.com
    /// The function itself takes bitmapData and overwrites it with edge data.
    /// The edge data is color-coded and can be used to determine
    /// the orientation of the edge at any point when read or further manipulated.
    /// Vertical edges are more red. Horizontal edges are more cyan/green.
    /// Edges which go from upper right to lower left are more yellow, and 
    /// edges which go from upper left to lower right are more blue.
    /// I think this is similar to the edge filter in Photoshop, but may be less efficient.
    /// At any rate, this is the fixed version that I wrote from scratch. Use at your own risk (-_^)
    /// This demo version takes a snapshot from a webcam when you click the mouse over
    /// flash stage, and it shows the effects of the function.
    
    import flash.display.AVM1Movie;
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.geom.Rectangle;
    import flash.geom.Point;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.events.MouseEvent;
    import flash.filters.ConvolutionFilter;
    
    
    public class FlashTest extends Sprite {
        //private var bmd:BitmapData = new BitmapData(0, 0, 200, 200);
        private var cam:Camera;
        private var vid:Video;
        private var myBmd:BitmapData;
        
        private const SMOOTHING:uint = 1; 
        // SMOOTHING defines how far away sampled pixels will be for comparison, 
        //higher numbers help to eliminate graininess
        
        
        public function FlashTest() {
            // write as3 code here..
            cam = Camera.getCamera();
            cam.setMode(320, 240, 15, false);
            vid = new Video();
            vid.attachCamera(cam);
            stage.addEventListener(MouseEvent.CLICK, onClick);
        }
        
        private function onClick(event:MouseEvent):void {
            myBmd = new BitmapData(cam.width, cam.height, false, 0);
            myBmd.draw(vid);
            //EdgeDetect(myBmd);
            
            //EdgeTransform(myBmd);
            
            FindFacePartsMidline(myBmd);
            
            //HorEdges(myBmd);
            //EnhanceEdges(myBmd, 1, 3);
            BlurEdges(myBmd);
            //SharpenEdges(myBmd);
            //EdgeTransform(myBmd);
            //FindEndpoints(myBmd);
            
            //var rect:Rectangle = new Rectangle(0, 0, myBmd.width, myBmd.height);
            //var pt:Point = new Point(0, 0);
            //myBmd.copyChannel(myBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.RED);
            //myBmd.copyChannel(myBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.GREEN);
            this.addChild(new Bitmap(myBmd));
        }
        
        
        private function HorEdges(bmd:BitmapData):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            var horFilter:ConvolutionFilter = new ConvolutionFilter(1, 3, [-1, 2, -1]);
            bmd.applyFilter(bmd, rect, pt, horFilter);
            
        }

        /// Applies EdgeTransform to find edges and then enhances the edges
        /// by enhancing those that are continuous or slightly disconnected 
        /// but which are implied by the orientation of surrounding edges
        private function EnhanceEdges(bmd:BitmapData, factor:uint, times:uint):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            var rFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, factor, factor, 0, 1, 0, factor, factor, 0]);
            var gFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, factor, factor, 1, factor, factor, 0, 0]);
            var bFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [factor, 0, 0, factor, 1, factor, 0, 0, factor]);
            
            
            var redBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            
            redBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            greenBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            blueBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            while (times > 0) {
            redBmd.applyFilter(bmd, rect, pt, rFilter);
            greenBmd.applyFilter(bmd, rect, pt, gFilter);
            blueBmd.applyFilter(bmd, rect, pt, bFilter);
          
            times--;
            }
       
            bmd.copyChannel(redBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            bmd.copyChannel(greenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            bmd.copyChannel(blueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            redBmd.dispose();
            greenBmd.dispose();
            blueBmd.dispose();
            
        }
        
        private function EdgeDetect(bmd:BitmapData):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            var edgeFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, -1, -1, -1, 8, -1, -1, -1, -1]);
            bmd.applyFilter(bmd, rect, pt, edgeFilter);
        }
        
        private function BlurEdges(bmd:BitmapData):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            var edgeFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [1,1,1,1,1,1,1,1,1]);
            
            bmd.applyFilter(bmd, rect, pt, edgeFilter);
        }


        private function SharpenEdges(bmd:BitmapData):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            
            var redBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            var rSharpen:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, 0, 0, -1, 4, -1, 0, 0, -1]);
            var gSharpen:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, -1, 0, 0, 4, 0, 0, -1, -1]);
            var bSharpen:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, -1, -1, 0, 4, 0, -1, -1, 0]);
            
            
            redBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            greenBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            blueBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            redBmd.applyFilter(bmd, rect, pt, rSharpen);
            greenBmd.applyFilter(bmd, rect, pt, gSharpen);
            blueBmd.applyFilter(bmd, rect, pt, bSharpen);
            
            bmd.copyChannel(redBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            bmd.copyChannel(greenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            bmd.copyChannel(blueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            redBmd.dispose();
            greenBmd.dispose();
            blueBmd.dispose();
            
        }
        
        private function FindEndpoints(bmd:BitmapData):void {
            /// Cancels out continuous line segments which are in the expected (smooth) orientation
            
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            
            var rThreshold:uint = 0x00800000;
            var gThreshold:uint = 0x00008000;
            var bThreshold:uint = 0x00000080;
            
            //var rFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, 2, -1, -1, 2, -1, -1, 2, -1]);
            //var gFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 0, 2, 2, -4, 0, 0, 0]);
            //var bFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 0, -2, 0, 2, 0, 0, 0]);
            
            var rFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, -1, -1, 0, 2, 0, -1, -1, 0]);
            var gFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, -1, -1, 2, -1, -1, 0, 0]);
            var bFilter:ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, 0, 0, -1, 2, -1, 0, 0, -1]);
            
            var rFilter2:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 2, 0, 0, 2, 0, 0, -4, 0]);
            var gFilter2:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 0, -4, 2, 2, 0, 0, 0]);
            var bFilter2:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 0, 2, 2, -4, 0, 0, 0]);
            
            var rFilter3:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, -4, 0, 2, 0, 2, 0, 0]);
            var gFilter3:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, -4, 0, 2, 0, 2, 0, 0]);
            var bFilter3:ConvolutionFilter = new ConvolutionFilter(3, 3, [-4, 0, 0, 0, 2, 0, 0, 0, 2]);
            
            var rFilter4:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 2, 0, 2, 0, -4, 0, 0]);
            var gFilter4:ConvolutionFilter = new ConvolutionFilter(3, 3, [0, 0, 2, 0, 2, 0, -4, 0, 0]);
            var bFilter4:ConvolutionFilter = new ConvolutionFilter(3, 3, [2, 0, 0, 0, 2, 0, 0, 0, -4]);
            
            
            var redBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            var redBmd2:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd2:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd2:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            var redBmd3:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd3:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd3:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            var redBmd4:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd4:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd4:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            redBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            greenBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            blueBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            redBmd.threshold(redBmd, rect, pt, "<", rThreshold); // erase weak edges
            greenBmd.threshold(greenBmd, rect, pt, "<", gThreshold);
            blueBmd.threshold(blueBmd, rect, pt, "<", bThreshold);
            
            
            
            /*redBmd2 = redBmd.clone(); 
            greenBmd2 = greenBmd.clone();
            blueBmd2 = blueBmd.clone();
            
            redBmd3 = redBmd.clone(); 
            greenBmd3 = greenBmd.clone();
            blueBmd3 = blueBmd.clone();
            
            redBmd4 = redBmd.clone(); 
            greenBmd4 = greenBmd.clone();
            blueBmd4 = blueBmd.clone();
            
            
            redBmd.applyFilter(redBmd, rect, pt, rFilter);
            greenBmd.applyFilter(greenBmd, rect, pt, gFilter);
            blueBmd.applyFilter(blueBmd, rect, pt, bFilter);
            
            
            redBmd2.applyFilter(bmd, rect, pt, rFilter2);
            greenBmd2.applyFilter(bmd, rect, pt, gFilter2);
            blueBmd2.applyFilter(bmd, rect, pt, bFilter2);
            
            redBmd3.applyFilter(bmd, rect, pt, rFilter3);
            greenBmd3.applyFilter(bmd, rect, pt, gFilter3);
            blueBmd3.applyFilter(bmd, rect, pt, bFilter3);
            
            redBmd4.applyFilter(bmd, rect, pt, rFilter4);
            greenBmd4.applyFilter(bmd, rect, pt, gFilter4);
            blueBmd4.applyFilter(bmd, rect, pt, bFilter4);
            
            redBmd.draw(redBmd2, null, null, BlendMode.ADD);
            greenBmd.draw(greenBmd2, null, null, BlendMode.ADD);
            blueBmd.draw(blueBmd2, null, null, BlendMode.ADD);
            
            redBmd.draw(redBmd3, null, null, BlendMode.ADD);
            greenBmd.draw(greenBmd3, null, null, BlendMode.ADD);
            blueBmd.draw(blueBmd3, null, null, BlendMode.ADD);
            
            redBmd.draw(redBmd4, null, null, BlendMode.ADD);
            greenBmd.draw(greenBmd4, null, null, BlendMode.ADD);
            blueBmd.draw(blueBmd4, null, null, BlendMode.ADD);*/
            
            bmd.copyChannel(redBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            bmd.copyChannel(greenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            bmd.copyChannel(blueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
           
            redBmd.dispose();
            greenBmd.dispose();
            blueBmd.dispose();
            
            /*redBmd2.dispose();
            greenBmd2.dispose();
            blueBmd2.dispose();
            
            redBmd3.dispose();
            greenBmd3.dispose();
            blueBmd3.dispose();
            
            redBmd4.dispose();
            greenBmd4.dispose();
            blueBmd4.dispose();*/
        }
        
        private function FindFacePartsMidline(bmd:BitmapData):void {
            // first find midline of symmetric objects on screen (looking primarily for lips/mouth and eyes)
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            var originalBmd:BitmapData = bmd.clone();
            
            EdgeTransform(bmd);
            var c:uint;
            
            var f1Threshold:uint = 0x0000FFFF;
            //bmd.threshold(bmd, rect, pt, "<", f1Threshold);  
            //bmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.RED);
            // Look for horizontal edges in cyan range
           
           
        }







        /// EdgeTransform takes bitmapData and overwrites it with its edge info
        private function EdgeTransform(bmd:BitmapData):void {
            var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);
            var pt:Point = new Point(0, 0);
            
            /// Split input bitmap into different color channels to preserve color contrast effect
            
            var redBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var greenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var blueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            redBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            greenBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            blueBmd.copyChannel(bmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            // Create bitmaps for writing edge info to
            var nRedBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var nGreenBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            var nBlueBmd:BitmapData = new BitmapData(bmd.width, bmd.height, false, 0x000000);
            
            var rgbR:uint;
            var rgbG:uint;
            var rgbB:uint;
            
            var oldRgbR:uint;
            var oldRgbG:uint;
            var oldRgbB:uint;
            
            var newRgbR:uint;
            var newRgbG:uint;
            var newRgbB:uint;
            
            var vertOrientation:uint;
            var horOrientation:uint;
            var verthorOrientation:uint;
            var horvertOrientation:uint;
            
            var ul:uint;
            var ll:uint;
            var dl:uint;
            var uu:uint;
            var ur:uint;
            var rr:uint;
            var dr:uint;
            var c:uint;
            var dd:uint;
            
            var y:uint;
            var x:uint;
            
            //// Go through each channel bitmap separately to preserve color contrast effect
            //// First red channel
                        //// Go through each channel bitmap separately to preserve color contrast effect
            //// First red channel
            for (y = SMOOTHING; y < bmd.height; y++)
            {
                // Get pixel colors from a 2x3 box of bitmap
                c = redBmd.getPixel(SMOOTHING, y);
                ul = redBmd.getPixel(0, y-SMOOTHING);
                ll = redBmd.getPixel(0, y);
                dl = redBmd.getPixel(0, y+SMOOTHING);
                uu = redBmd.getPixel(SMOOTHING, y-SMOOTHING);
                dd = redBmd.getPixel(SMOOTHING, y+SMOOTHING);
                
                for (x = SMOOTHING; x < bmd.width; x++)
                {
                    // Get pixel colors from right-hand column of 3x3 box
                    ur = redBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
                    rr = redBmd.getPixel(x+SMOOTHING, y);
                    dr = redBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
                    
                    //calculate the angle of the edge for the center point c
                    // depending upon surrounding edge pattern in 3x3 box
                    vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
                    horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
                    verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
                    horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
                   
                    // Give each instantaneous edge orientation angle a color code
                    rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
                    rgbG = uint((horOrientation + horvertOrientation)/0x010101);
                    rgbB = uint((horOrientation + verthorOrientation)/0x010101);
                    
                    rgbR *= 0x010000;
                    rgbG *= 0x000100;
                    rgbB *= 0x000001;
                    
                    oldRgbR = nRedBmd.getPixel(x, y);
                    oldRgbG = nGreenBmd.getPixel(x, y);
                    oldRgbB = nBlueBmd.getPixel(x, y);
                    
                    nRedBmd.setPixel(x, y, rgbR + oldRgbR);
                    nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
                    nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
                    
                    //shift values for next pass when checking next 3x3 box
                    ll = c;
                    c = rr;
                    ul = uu;
                    uu = ur;
                    dl = dd;
                    dd = dr;
                }

            }
            
            // Next blue channel 
            for (y = SMOOTHING; y < bmd.height; y++)
            {
                // Get pixel colors from a 2x3 box of bitmap
                c = blueBmd.getPixel(SMOOTHING, y);
                ul = blueBmd.getPixel(0, y-SMOOTHING);
                ll = blueBmd.getPixel(0, y);
                dl = blueBmd.getPixel(0, y+SMOOTHING);
                uu = blueBmd.getPixel(SMOOTHING, y-SMOOTHING);
                dd = blueBmd.getPixel(SMOOTHING, y+SMOOTHING);
                
                for (x = SMOOTHING; x < bmd.width; x++)
                {
                    // Get pixel colors from right-hand column of 3x3 box
                    ur = blueBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
                    rr = blueBmd.getPixel(x+SMOOTHING, y);
                    dr = blueBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
                    
                    //calculate the angle of the edge for the center point c
                    // depending upon surrounding edge pattern in 3x3 box
                    vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
                    horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
                    verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
                    horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
                   
                    // Give each instantaneous edge orientation angle a color code
                    rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
                    rgbG = uint((horOrientation + horvertOrientation)/0x010101);
                    rgbB = uint((horOrientation + verthorOrientation)/0x010101);
                    
                    rgbR *= 0x010000;
                    rgbG *= 0x000100;
                    rgbB *= 0x000001;
                    
                    oldRgbR = nRedBmd.getPixel(x, y);
                    oldRgbG = nGreenBmd.getPixel(x, y);
                    oldRgbB = nBlueBmd.getPixel(x, y);
                    
                    nRedBmd.setPixel(x, y, rgbR + oldRgbR);
                    nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
                    nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
                    
                    //shift values for next pass when checking next 3x3 box
                    ll = c;
                    c = rr;
                    ul = uu;
                    uu = ur;
                    dl = dd;
                    dd = dr;
                }

            }
            
            /// Next green channel
            for (y = SMOOTHING; y < bmd.height; y++)
            {
                // Get pixel colors from a 2x3 box of bitmap
                c = greenBmd.getPixel(SMOOTHING, y);
                ul = greenBmd.getPixel(0, y-SMOOTHING);
                ll = greenBmd.getPixel(0, y);
                dl = greenBmd.getPixel(0, y+SMOOTHING);
                uu = greenBmd.getPixel(SMOOTHING, y-SMOOTHING);
                dd = greenBmd.getPixel(SMOOTHING, y+SMOOTHING);
                
                for (x = SMOOTHING; x < bmd.width; x++)
                {
                    // Get pixel colors from right-hand column of 3x3 box
                    ur = greenBmd.getPixel(x+SMOOTHING, y-SMOOTHING);
                    rr = greenBmd.getPixel(x+SMOOTHING, y);
                    dr = greenBmd.getPixel(x+SMOOTHING, y+SMOOTHING);
                    
                    //calculate the angle of the edge for the center point c
                    // depending upon surrounding edge pattern in 3x3 box
                    vertOrientation = uint((Math.abs(ll - c) + Math.abs(rr - c)) / 2);
                    horOrientation = uint((Math.abs(uu - c) + Math.abs(dd - c)) / 2);
                    verthorOrientation = uint((Math.abs(ur - c) + Math.abs(dl - c)) / 2);
                    horvertOrientation = uint((Math.abs(dr - c) + Math.abs(ul - c)) / 2);
                   
                    // Give each instantaneous edge orientation angle a color code
                    rgbR = uint((vertOrientation + horvertOrientation)/0x010101);
                    rgbG = uint((horOrientation + horvertOrientation)/0x010101);
                    rgbB = uint((horOrientation + verthorOrientation)/0x010101);
                    
                    rgbR *= 0x010000;
                    rgbG *= 0x000100;
                    rgbB *= 0x000001;
                    
                    oldRgbR = nRedBmd.getPixel(x, y);
                    oldRgbG = nGreenBmd.getPixel(x, y);
                    oldRgbB = nBlueBmd.getPixel(x, y);
                    
                    nRedBmd.setPixel(x, y, rgbR + oldRgbR);
                    nGreenBmd.setPixel(x, y, rgbG + oldRgbG);
                    nBlueBmd.setPixel(x, y, rgbB + oldRgbB);
                    
                    
                    //shift values for next pass when checking next 3x3 box
                    ll = c;
                    c = rr;
                    ul = uu;
                    uu = ur;
                    dl = dd;
                    dd = dr;
                }

            }
            // Copy edge information from each respective channel over to original bitmap
            bmd.copyChannel(nRedBmd, rect, pt, BitmapDataChannel.RED, BitmapDataChannel.RED);
            bmd.copyChannel(nGreenBmd, rect, pt, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            bmd.copyChannel(nBlueBmd, rect, pt, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            redBmd.dispose();
            greenBmd.dispose();
            blueBmd.dispose();
            
            nRedBmd.dispose();
            nGreenBmd.dispose();
            nBlueBmd.dispose();

        }

    }
}

Forked