2

さて、ランレングス エンコーディングとハフマン エンコーディングの両方を使用して画像を圧縮する必要がある大学の課題があります。ハフマンを実装する時間がないと思うので、Run-Length エンコーディング atm に焦点を当てています。

私が現在行っているのは、バッファリングされた画像を渡すことです。

public byte[] byteArray(BufferedImage image){
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] imageInByte = null;
    try{
        ImageIO.write(image, "BMP", baos);
        baos.flush();
        imageInByte = baos.toByteArray();
        baos.close();
    }catch(IOException e){
        System.out.println(e.getMessage());
    }

    return imageInByte;
}

画像のバイトを取得します。次に、それを取得して実際の圧縮を行います。これを行うには、stringBuffer を使用していますが、これは間違っていると確信していますが、別の方法は考えられません。そのためのコードは

public String getRunLength(){
    StringBuffer dest = new StringBuffer();        
    for(int i =0; i < imageByteArray.length; i++){
        int runlength = 1;
        while(i+1 < imageByteArray.length && imageByteArray[i] == imageByteArray[i+1]){
            runlength++;
            i++;

        }     


        dest.append(runlength);  

        dest.append(imageByteArray[i]);

    }
    return dest.toString();
}

バイトに戻ると、実際のバイトではなくASCII値を取得するため、文字列に変換するべきではないと確信しています。しかし、ランレングスを標準のバイト配列に効率的に追加する方法がわかりません(ランレングスを先頭に追加し、byte[i+runLength] の後のすべてを下に移動すると、それができると思います配列内の runLength 量..しかし、それは非常に非効率的でエラーが発生しやすいでしょう...おそらく)

次に、それを画像として保存する必要があります。これは明らかに現時点では機能していませんが、現在そのために取得しているコードは

 try{
        File newImage = new File("Saved.png");
        ImageIO.write(rleImage, "BMP", newImage);
    }catch(Exception e){
        System.out.println("something fucked up");
    }

あなたが提供できるかもしれない助けをありがとう:)

次のように行われるrleImageを設定する部分を見逃していることに気づきました

 public BufferedImage stringToImage(String runLengthEncode){
    ByteArrayInputStream bais = new ByteArrayInputStream(runLengthEncode.getBytes());
    try{
        imageRLE = ImageIO.read(new ByteArrayInputStream(runLengthEncode.getBytes()));
    }catch(IOException e){

    }
    //decode(runLengthEncode);
    if(imageRLE == null)
        System.out.println("imageRLE is null");
    return imageRLE;
}
4

2 に答える 2

3

StringBuffer を使用するのとまったく同じ方法で ByteArrayOutputStream を使用できるはずです。

public byte[] getRunLength(){
    ByteArrayOutputStream dest = new ByteArrayOutputStream();        
    for(int i =0; i < imageByteArray.length; i++){
        int runlength = 1;
        while(i+1 < imageByteArray.length && imageByteArray[i] == imageByteArray[i+1]){
            runlength++;
            i++;

        }     

        dest.write((byte)runlength);  
        dest.write((byte)imageByteArray[i]);
    }
    return dest.toByteArray();
}

これにより、char への変換とその逆の変換全体が回避されます。

ところで、アルゴリズムは非効率的で、おそらく間違っています。各文字を反復処理し、各文字について、文字のスパンを楽しみにしています。その必要はありません。あなたはすでにすべてのキャラクターを歩いているので、最後のキャラクターが何であったかを覚えておいて、それに応じて行動するだけです.

public byte[] getRunLength(){
    ByteArrayOutputStream dest = new ByteArrayOutputStream();  
    byte lastByte = imageByteArray[0];
    int matchCount = 1;
    for(int i=1; i < imageByteArray.length; i++){
        byte thisByte = imageByteArray[i];
        if (lastByte == thisByte) {
            matchCount++;
        }
        else {
            dest.write((byte)matchCount);  
            dest.write((byte)lastByte);
            matchCount=1;
            lastByte = thisByte;
        }                
    }
    dest.write((byte)matchCount);  
    dest.write((byte)lastByte);
    return dest.toByteArray();
}

これが各バイト値に一度だけ接触することがわかります。

于 2014-11-26T21:28:08.047 に答える