Сжатие изображения в коде длины выполнения в Java

2

Хорошо, поэтому у меня есть университетское задание, где мне нужно сжать изображение, используя кодировку Run-Length и кодировку huffman. Я сосредоточен на кодировании Run-Length atm, так как не думаю, что у меня будет время для реализации huffman.

То, что я сейчас делаю, - это передать буферное изображение, затем делать

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;
}

для получения байта изображения. Я тогда беру это и делаю фактическое сжатие, чтобы сделать это atm. Я использую 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, а не фактические байты. Но я не могу понять, как я мог бы эффективно добавлять длину выполнения в стандартный байт-массив (я думаю, что смог бы это сделать, добавив длину начала в начало, а затем переместил все после байта [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;
}
  • 1
    Не вдаваясь в алгоритмы, вы, возможно, захотите изучить байтовые буферы для всех ваших потребностей в обработке байтов.
  • 0
    Не уверен, почему вы отделяете «кодирование длины пробега» от «huffman»; построение дерева Хаффмана является примером RLE ...
Показать ещё 5 комментариев
Теги:
image-processing
image-compression
run-length-encoding

2 ответа

2
Лучший ответ

Вы должны иметь возможность использовать ByteArrayOutputStream точно так же, как вы используете StringBuffer:

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 и обратно.

Кстати, алгоритм неэффективен и, вероятно, ошибочен. Вы перебираете каждого персонажа, а затем для каждого персонажа вы ожидаете пробел символов. Вам не нужно это делать. Вы уже проходите через все персонажи, поэтому все, что вам нужно сделать, это помнить, что такое последний персонаж, и ac соответственно.

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();
}

Вы увидите, что это касается каждого байтового значения только один раз.

  • 0
    Ну, похоже, это работает, когда я вывожу runLengthEncode в текстовый файл, так что большое спасибо за это. Я получаю пустое изображение по какой-то причине на imageRle = ImageIO.read (новый ByteArrayInputStream (runLengthEncode), однако. Я предполагаю, что это неправильно с тем, как я использую ImageIO, или, возможно, формат моего byteArray. иметь тот же вывод, я получу время выполнения потока в какой-то момент, чтобы увидеть, какой из них является более эффективным по времени.
  • 0
    Если вам нравится ответ, нажмите на галочку под номером ответа, чтобы указать «принятый ответ»
Показать ещё 1 комментарий
0

вы используете flush в ByteArrayOutputStream, это даст вам неверную информацию, чтобы ваш код работал, просто удалите строку

public byte[] byteArray(BufferedImage image){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] imageInByte = null;
try{
    ImageIO.write(image, "BMP", baos);

    imageInByte = baos.toByteArray();
    baos.close();
}catch(IOException e){
    System.out.println(e.getMessage());
}

return imageInByte;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню