DCT

by wrotenodoc forked from DFT (diff: 121)
The Discrete Cosine Transform

TODO
- blockwise operation
- quantization
♥0 | Line 140 | Modified 2015-11-06 14:19:52 | MIT License
play

ActionScript3 source code

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

// forked from wrotenodoc's DFT
package {

    import flash.display.Sprite
    import flash.display.Bitmap
    import flash.display.BitmapData
    import flash.text.TextField
    
    public class DCT_Test extends Sprite {
        
        public function DCT_Test() {
            // write as3 code here..
            var bd:BitmapData = new BitmapData(64, 64, true, 0x0)
            bd.perlinNoise(32, 32, 4, 0, false, true, 7, true)
            var bmp:Bitmap = new Bitmap(bd)
            bmp.y = 20
            bmp.scaleX = bmp.scaleY = 3
            addChild(bmp)
            
            var dct:DCTResult = DCT(bd)
            
            var dctBD:BitmapData = dct2bd(dct)
            var dctBMP:Bitmap = new Bitmap(dctBD)
            with(addChild(dctBMP)){
                x = 64 * 3
                y = 20
                scaleX = scaleY = 3
            }
            var idct:BitmapData = IDCT(dct)
            var idctBMP:Bitmap = new Bitmap(idct)
            with(addChild(idctBMP)){
                scaleX = scaleY = 3
                y = bmp.y + bmp.height
            }
            
            var tf1:TextField = makeText("original", bmp.x+bmp.width/2, bmp.y-10)
            var tf2:TextField = makeText("dct", dctBMP.x+dctBMP.width/2, dctBMP.y-10)
            var tf3:TextField = makeText("idct", idctBMP.x+idctBMP.width/2, idctBMP.y+idctBMP.height+10)
            function makeText(msg:String, tx:Number, ty:Number):TextField {
                var tf:TextField = new TextField
                tf.selectable = false
                tf.autoSize = "center"
                tf.text = msg
                tf.x = tx - tf.width/2 ; tf.y = ty - tf.height/2
                addChild(tf)
                return tf
            }
        }
        
        private function bd2ary(bd:BitmapData):Array {
            var ary:Array = []
            for(var y:int=0; y<bd.height; y++){
                ary[y] = []
                for(var x:int=0; x<bd.width; x++){
                    ary[y][x] = bd.getPixel(x, y) & 0xFF
                }
            }
            return ary
        }
        
        private function dct2bd(dct:DCTResult):BitmapData {
            var bd:BitmapData = new BitmapData(dct.width, dct.height, false, 0x0)
            for(var y:int=0; y<dct.height; y++){
                for(var x:int=0; x<dct.width; x++){
                    var color:uint = uint(Math.log(1 + (dct.data[y][x] - dct.minValue)/(dct.maxValue - dct.minValue)) * 255 * 255)
                    bd.setPixel(x, y, color<<16 | color<<8 | color)
                }
            }
            return bd
        }
        
        private const pi2:Number = Number.PI * 2
        private function DCT(image:BitmapData):DCTResult {
            var N:int = image.height
            var M:int = image.width
            var PI_M:Number = Math.PI / M
            var PI_N:Number = Math.PI / N
            var result:DCTResult = new DCTResult(M, N)
            var i:int, j:int
    
            for(i=0; i<N; i++){
                for(j=0; j<N; j++){
                    result.data[i][j] = sum(i, j)
                }
            }
            
            result.minValue = Infinity
            result.maxValue = -Infinity
            var r:Number
            for(i=0; i<N; i++){
                for(j=0; j<N; j++){
                    r = result.data[i][j]
                    if(r > result.maxValue) result.maxValue = r
                    if(r < result.minValue) result.minValue = r
                }
            }
    
            return result
    
            function sum(i:int, j:int):Number {
                var real:Number = 0
                var col:uint
                for(var y:int=0; y<N; y++){
                    for(var x:int=0; x<M; x++){
                        col = image.getPixel(x, y) & 0xFF
                        real += 4 * col * Math.cos(PI_M*(x+.5)*j) * Math.cos(PI_N*(y+.5)*i)
                    }
                }
                return real
            }
        }
        
        private function IDCT(dct:DCTResult):BitmapData {
            var N:int = dct.height, M:int = dct.width
            var PI_M:Number = Math.PI / M
            var PI_N:Number = Math.PI / N
            var MN:int = M * N
            var i:int, j:int
            var bd:BitmapData = new BitmapData(M, N, false, 0x0)
            
            var col:uint
            for(i=0; i<N; i++){
                for(j=0; j<M; j++){
                    col = uint(sum(i, j))
                    bd.setPixel(j, i, col<<16 | col<<8 | col)
                }
            }
            
            return bd
            
            function sum(i:int, j:int):Number {
                var real:Number = 0
                var accum:Number
                var w1:Number, w2:Number
                for(var y:int=0; y<N; y++){
                    accum = 0
                    for(var x:int=0; x<M; x++){
                        w1 = x == 0 ? .5 : 1
                        w2 = y == 0 ? .5 : 1
                        accum += w1*w2*dct.data[y][x] * Math.cos(PI_M*(j+.5)*x) * Math.cos(PI_N*(i+.5)*y)
                    }
                    real += accum / MN
                }
                return real
            }
        }
        
    }
    
}

class DCTResult {
    public var data:Vector.<Vector.<Number>>
    public var maxValue:Number, minValue:Number
    public var width:int, height:int
    public function DCTResult(width:int, height:int) {
        data = new Vector.<Vector.<Number>>(height, true)
        for(var i:int=0; i<height; i++) data[i] = new Vector.<Number>(width, true)
        this.width = width
        this.height = height
    }
}

Forked