0

For a mathematical bachelor thesis I am trying to code a simple JPG encoder in PHP. After after hard work I made it to create a script that reads out the colors of a PNG file, transforms it to YCbCr Color Format and does the Discrete Cosinus Transformation. Then the data is quantized and huffman encoded as a bitstring.

It is not my goal to create a full encoder, so the script needs long time, much RAM and only supports pictures with a width/height divisible by 16.

Now I am trying to subsample the CbCr colors with the 4:2:0 format but for some reason my picture is not correct.

For the subsampling I take 4 color values (2x2) and calculate the average of the 4 values. Later after the DCT and Quantization I huffman-encode the blocks in this order: Y1,Y2,Y3,Y4,Cb1,Cr1 as it is described as one MCU.

Here is the code for my subsampling and also the Codes for the DCT and quantization. Hope someone can give me hints, Thanks:)

original png file

no subsampled jpg file

subsampled jpg file

//$color is an twodimensional array with all values of one color
function subsampling ($color) {
    $subsampling = array();
    
    for ($y = 0; $y < count($color); $y = $y+2) {
        $y_array = array();
        
        for ($x = 0; $x < count($color[$y]); $x = $x + 2) {
            $y_array[] = ($color[$y][$x] + $color[$y][$x + 1] + $color[$y + 1][$x] + $color[$y + 1][$x + 1]) / 4;           
            
        }
        
        $subsampling[] = $y_array;
        
    }
    
    return $subsampling;
}
//function that calculate the discrete cosinus transformation
function dct($bloecke, $verschiebung){
    
    $bloecke_neu = array(); //Zeilenblöcke
    
    
    foreach ($bloecke as $blockzeile){
        $blockzeile_neu = array();
        foreach ($blockzeile as $block){
            $block_neu = array();
            
            
            for ($yy = 0; $yy < 8; $yy++) {
                $zeile = array();
                for ($xx = 0; $xx < 8; $xx++){                  
                    if ($yy == 0){
                        $ck = 1/sqrt(2);
                    } else {
                        $ck = 1;
                    }
                    if ($xx == 0){
                        $cl = 1/sqrt(2);
                    } else {
                        $cl = 1;
                    }
                    
                    
                    $summe = 0;
                    
                    for ($n = 0; $n < 8; $n++){
                        $summe2 = 0;
                        for ($m = 0; $m < 8; $m++){
                            
                            
                            $summe2 += ($block[$n][$m] + $verschiebung) * cos(((2*$n + 1) * $yy * pi())/16) * cos(((2*$m + 1) * $xx * pi())/16);
                        }
                        $summe += $summe2;
                        
                    }
                    
                    
                    $wert = ((1/4) * $ck * $cl * $summe);
                    $zeile[] = $wert;
                    
                }
                $block_neu[] = $zeile;
            }
            
            $blockzeile_neu[] = $block_neu;
        }
        
        $bloecke_neu[] = $blockzeile_neu;
        
    }
    return $bloecke_neu;
    
}
sgnd
  • 1
  • 1

0 Answers0