2013-03-05 53 views
2

我試圖計算輸入圖像的DCT和IDCT,並將IDCT輸出顯示爲結果圖像。但是我的IDCT值超過了300.我的輸入圖像是'.rgb'圖像。 我也在考慮輸入圖像的高度和寬度爲常數,即352 * 288Jpeg DCT和IDCT計算不正確

我將每個像素的輸入紅色,綠色和藍色整數表示爲rgb [3] [64] [1583]其中[3] - >每個塊中的像素索引的紅色/綠色/藍色和[64] - 索引,以及8×8塊的索引,即1583塊中的一個塊。

最後我保持我的量化表具有統一的值 - > 2^N,其中N作爲參數傳遞。在此代碼中,quantLevel是上面的N。

以下是我的代碼:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.Arrays; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

public class Jpeg {  
    double rgb[][][]=new double[3][64][1584]; 
    double rgbfinal[][][]=new double[3][64][1584]; 
    double R[][]=new double[64][1584]; 
    double G[][]=new double[64][1584]; 
    double B[][]=new double[64][1584]; 

    public void go(String fname, int quantLevel){  
    int numBlocks=(352*288)/64;   

    String fileName = fname; 
    int width=352,height=288; 
    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 

    try { 
      File file = new File(fname); 
     InputStream is = new FileInputStream(file); 

     long len = file.length(); 
     byte[] bytes = new byte[(int)len]; 

     int offset = 0; 
      int numRead = 0; 
      while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { 
       offset += numRead; 
     }    
     int ind = 0; 
     for(int y = 0; y < height; y++){  
      for(int x = 0; x < width; x++){      
       byte r = bytes[ind]; 
       byte g = bytes[ind+height*width]; 
       byte b = bytes[ind+height*width*2];     
       int pix = 0xff000000 | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);    
       img.setRGB(x,y,pix); 
       ind++; 
      } 
     }   
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    int indexRow=0,indexCol=0,indexBlock=0,indexBits=0,indexPixelBlock=0,indexPixel=0; 
    long count=0L; 
    String binary=""; 

     indexPixel=0; 
     indexBlock=0; 
     int i=0; 
      while(count!=(long)(numBlocks*64)){                           
       int pix = img.getRGB(indexCol, indexRow); 
       int red = (pix >> 16) & 0x000000FF; 
       int green = (pix >>8) & 0x000000FF; 
       int blue = (pix) & 0x000000FF; 

       rgb[0][indexPixel][indexBlock]=red;    
       rgb[1][indexPixel][indexBlock]=green;    
       rgb[2][indexPixel][indexBlock]=blue; 

       count++;   
       indexPixel++; 

       if(indexCol==width-1 && indexRow==height-1)    
        break;     

       if(indexCol%7==0 && indexCol!=0 && indexPixel%8==0) 
        {             
         indexPixel=indexPixelBlock; 
         indexBlock++;                         
        } 

       if(indexPixel%8==0 && indexCol%7!=0 && indexBlock!=1583) 
        { 
        indexPixel=indexPixelBlock; 
        indexBlock++; 
        } 

       if(indexCol==width-1) 
        {      
         indexCol=0;     
         indexRow++; 
        } 
       else 
        indexCol++;                             

       if((indexPixel)%8==0 && indexBlock==numBlocks-1 && indexCol%7==0)    
       {       
         indexBlock=0; 
         indexPixelBlock=indexPixel;            
       }             
      } 
    calcQuantizedDCT(quantLevel);      
    calcInverseDCT(quantLevel); 

    JFrame frame = new JFrame(); 
    frame.setLocation(0,0); 
    frame.setSize(1024, 720);     
    frame.getContentPane().setBackground(Color.WHITE); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  

    JPanel p=new JPanel(); 
    p.setLayout(new FlowLayout(FlowLayout.LEFT)); 
    p.setLocation(100,100);  

    JLabel label = new JLabel(new ImageIcon(img));  
    label.setLocation(0,0); 
    label.setSize(352,288); 

    p.add(label); 
    frame.add(p);   
    frame.setVisible(true); 

    return; 
    } 

    void calcQuantizedDCT(int quantLevel) 
    {  
     String binary=""; 
     int indexBlock=0,indexPixel=0,indexBits=0,red=0,green=0,blue=0,x=0,y=0,indexPixelTemp=0,u=0,v=0; 

     double sumRed=0,sumGreen=0,sumBlue=0; 
     String substr=""; 
     int i=0; 
     for(indexBlock=0;indexBlock<1584;indexBlock++)  
     {        
      indexPixel=0;   
      // 
      while(indexPixel!=64 && u<8) 
      {        
       while(indexPixelTemp<64 && x<8) 
       {                        
        red=(int)rgb[0][indexPixelTemp][indexBlock]; 
        green=(int)rgb[1][indexPixelTemp][indexBlock]; 
        blue=(int)rgb[2][indexPixelTemp][indexBlock]; 
        // System.out.println(red);       
        sumRed+=red*Math.cos((Math.PI*(2*y+1)*u)/(2*8))*Math.cos((Math.PI*(2*x+1)*v)/(2*8));           
        sumGreen+=green*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8));                 
        sumBlue+=blue*Math.cos((Math.PI*(2*x+1)*u)/(16))*Math.cos((Math.PI*(2*y+1)*v)/(16)); 

        indexPixelTemp++; 
        y++; 
        if(y==8) 
        { 
         x++; 
         y=0;      
        }  

       }    
       //System.out.println("SumRed :"+sumRed); 

       if(u==0 && v==0)     
       {          
        //System.out.println("U & V & Pixel & Block "+u+" "+v+" "+indexPixel+" "+indexBlock); 
        R[indexPixel][indexBlock]=(Math.sqrt(1.0/64.0)*sumRed)/Math.pow(2,quantLevel); 
        G[indexPixel][indexBlock]=(Math.sqrt(1.0/64.0)*sumGreen)/Math.pow(2,quantLevel); 
        B[indexPixel][indexBlock]=(Math.sqrt(1.0/64.0)*sumBlue)/Math.pow(2,quantLevel);     
       } 
       else 
       { 
        //System.out.println("U & V & Pixel & Block "+u+" "+v+" "+indexPixel+" "+indexBlock);     
        R[indexPixel][indexBlock]=(Math.sqrt(2.0/32.0)*sumRed)/Math.pow(2,quantLevel); 
        G[indexPixel][indexBlock]=(Math.sqrt(2.0/32.0)*sumGreen)/Math.pow(2,quantLevel); 
        B[indexPixel][indexBlock]=(Math.sqrt(2.0/32.0)*sumBlue)/Math.pow(2,quantLevel);      
       }     

       indexPixel++;  

       if(indexPixel==64) 
        break; 
       indexPixelTemp=0; 
       v++; 

       if(v==8) 
       { 
        v=0; 
        u++; 
       } 
       x=0;y=0;sumGreen=0;sumRed=0;sumBlue=0;    
      }      

      u=0;v=0;     
     }  

     /* for(int j=0;j<64;j++)  
      { 
       System.out.print(R[j][0]+" "); 
       if(j%7==0 && j!=0) 
        System.out.println(); 
      } 
      */ 
    } 

    void calcInverseDCT(int quantLevel) 
    {  
     String binary=""; 
     int indexBlock=0,indexPixel=0,indexBits=0,u=0,v=0,x=0,y=0,indexPixelTemp=0,sumRed=0,sumGreen=0,sumBlue=0,red=0,green=0,blue=0; 

     for(indexBlock=0;indexBlock<1584;indexBlock++) 
     {    
      for(indexPixel=0;indexPixel<64;indexPixel++) 
      {   
       R[indexPixel][indexBlock]=R[indexPixel][indexBlock]*Math.pow(2,quantLevel); 
       G[indexPixel][indexBlock]=G[indexPixel][indexBlock]*Math.pow(2,quantLevel); 
       B[indexPixel][indexBlock]=B[indexPixel][indexBlock]*Math.pow(2,quantLevel); 

      } 
     } 
     int i=0; 
     indexPixelTemp=0; 
     indexPixel=0; 
     for(indexBlock=0;indexBlock<1584;indexBlock++) 
     {      
      indexPixel=0;    
      while(indexPixel<64 && x<8) 
      { 
       indexPixelTemp=0; 
       while(indexPixelTemp<64 && u<8) 
       { 
        red=(int)R[indexPixelTemp][indexBlock];     
        if(u==0 && v==0)     
         sumRed+=Math.sqrt(1.0/2.0)*red*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8));     
        else 
         sumRed+=red*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8));                

        green=(int)G[indexPixelTemp][indexBlock]; 
        if(u==0 && v==0)     
         sumGreen+=Math.sqrt(1.0/2.0)*green*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8)); 
        else 
         sumGreen+=green*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8)); 

        blue=(int)B[indexPixelTemp][indexBlock]; 
        if(u==0 && v==0)     
         sumBlue+=Math.sqrt(1.0/2.0)*blue*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8)); 
        else 
         sumBlue+=blue*Math.cos((Math.PI*(2*x+1)*u)/(2*8))*Math.cos((Math.PI*(2*y+1)*v)/(2*8)); 

        indexPixelTemp++; 
        v++; 
        if(v==8) 
        { 
         u++; 
         v=0; 
        }         
       } 

       rgbfinal[0][indexPixel][indexBlock]=sumRed; 
       rgbfinal[1][indexPixel][indexBlock]=sumGreen; 
       rgbfinal[2][indexPixel][indexBlock]=sumBlue;     

       indexPixel++;         
       indexPixelTemp=0; 
       y++; 

       if(y==8) 
       { 
        y=0; 
        x++; 
       }    
       u=0;v=0;sumGreen=0;sumRed=0;sumBlue=0;    
      }    
      if(i==3) 
       break; 
      x=0;y=0;     
     } 

     System.out.println();  
     /*for(i=0;i<64;i++) 
     { 
      System.out.print(rgbfinal[0][i][0]+" "); 
      if(i%7==0 && i!=0) 
       System.out.println(); 
     }*/ 
    } 

    public static void main(String args[]){ 
     Jpeg a = new Jpeg(); 
     a.go("src/image2.rgb",0);   
    }  
} 

我不是想爲IDCT的輸出中的紅,我檢查,以顯示輸出圖像變爲上述255

請幫助。

回答

1

首先,你是否希望創建一個兼容JPEG的編解碼器?或者你只是在玩弄多媒體編碼概念?如果後者,那麼更多的權力給你。如果前者,你有很多工作要做。

要直接回答你的問題:使用2D正向DCT變換8x8塊並得到高於255的數字是正常的。正向DCT的低級實現通常需要一個8x8無符號8位樣本向量作爲輸入和輸出帶符號16位採樣的8x8向量。

如果您確實希望創建一個兼容JPEG的編解碼器,那麼您仍然有一些要研究的主題。對於初學者,JPEG不壓縮RGB。將RGB數據轉換爲YUV,然後對這些塊進行變換(然後進行量化,鋸齒形和熵編碼)。

+0

我絕對在學習,我完全同意你上面所說的,我也知道我們也需要做熵編碼。但是現在我正在使用一個.rgb圖像來消除alpha分量並應用DCT和IDCT,從而獲得最終圖像。我想執行漸進式編碼和東西也。這是我自己做的。 – Vizzard 2013-03-05 09:59:42

+0

太棒了。我曾經寫過一篇文章,建議人們如果對學習多媒體黑客感興趣,可以用他們選擇的語言從頭開始編寫JPEG解碼器:http://multimedia.cx/eggs/learn-multimedia-with-jpeg/;你會學到許多關於壓縮理論的基礎知識。爲此,您可能希望專注於先編碼解碼器,然後編碼器。如果您從解碼器開始,您可以更好地理解JPEG的各個部分。 – 2013-03-05 16:56:48

+0

非常感謝,我一定會按照鏈接。 – Vizzard 2013-03-06 00:54:46