Преобразование изображения Java в RGB565 - PullRequest
1 голос
/ 30 ноября 2011

Я пытаюсь преобразовать изображение в формат RGB565.Я читаю это изображение:

BufferedImage bufImg = ImageIO.read(imagePathFile);
sendImg = new BufferedImage(CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, BufferedImage.TYPE_USHORT_565_RGB);
sendImg.getGraphics().drawImage(bufImg, 0, 0, CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, null);

Вот оно:

picture before convertation

Затем я конвертирую его в RGB565:

int numByte=0;
byte[] OutputImageArray = new byte[CONTROLLER_LCD_WIDTH*CONTROLLER_LCD_HEIGHT*2];

int i=0;
int j=0;
int len = OutputImageArray.length;

for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
    for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {

        Color c = new Color(sendImg.getRGB(i, j));
        int aRGBpix = sendImg.getRGB(i, j);
        int alpha;
        int red = c.getRed();
        int green = c.getGreen();
        int blue = c.getBlue();

        //RGB888
        red = (aRGBpix >> 16) & 0x0FF;
        green = (aRGBpix >> 8) & 0x0FF;
        blue = (aRGBpix >> 0) & 0x0FF; 
        alpha = (aRGBpix >> 24) & 0x0FF;

        //RGB565
        red = red >> 3;
        green = green >> 2;
        blue = blue >> 3;

        //A pixel is represented by a 4-byte (32 bit) integer, like so:
        //00000000 00000000 00000000 11111111
        //^ Alpha  ^Red     ^Green   ^Blue
        //Converting to RGB565

        short pixel_to_send = 0;
        int pixel_to_send_int = 0;
        pixel_to_send_int = (red << 11) | (green << 5) | (blue);
        pixel_to_send = (short) pixel_to_send_int;


        //dividing into bytes
        byte byteH=(byte)((pixel_to_send >> 8) & 0x0FF);
        byte byteL=(byte)(pixel_to_send & 0x0FF);

        //Writing it to array - High-byte is second
        OutputImageArray[numByte]=byteH;
        OutputImageArray[numByte+1]=byteL;

        numByte+=2;
    }
}

ЗатемЯ пытаюсь восстановить это из результирующего массива OutputImageArray:

i=0;
j=0;                        
numByte=0;
BufferedImage NewImg = new BufferedImage(CONTROLLER_LCD_WIDTH, CONTROLLER_LCD_HEIGHT, BufferedImage.TYPE_USHORT_565_RGB);
for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
    for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {

        int curPixel=0;
        int alpha=0x0FF;
        int red;
        int green;
        int blue; 

        byte byteL=0;
        byte byteH=0;

        byteH = OutputImageArray[numByte];
        byteL = OutputImageArray[numByte+1];

        curPixel= (byteH << 8) | (byteL);

        //RGB565
        red = (curPixel >> (6+5)) & 0x01F;
        green = (curPixel >> 5) & 0x03F;
        blue = (curPixel) & 0x01F;

        //RGB888
        red = red << 3;
        green = green << 2;
        blue = blue << 3;                                

        //aRGB
        curPixel = 0;
        curPixel = (alpha << 24) | (red << 16) | (green << 8) | (blue);

        NewImg.setRGB(i, j, curPixel);
        numByte+=2;

    }
}

Я вывожу это восстановленное изображение.Но я вижу, что это выглядит очень плохо.

enter image description here

Я ожидал потери качества изображения.Но, как я думал, эта картинка должна иметь почти такое же качество, как и предыдущая.Это правильно?Мой код правильный?

1 Ответ

1 голос
/ 22 мая 2016

Причина, по которой вы видите эти желтые артефакты, заключается просто в отрицательных значениях byteL перезаписывающих битов из byteH, содержащих правильные значения для красный и (часть) зеленый каналы.Позвольте мне объяснить.

Помните, если старший бит в байте установлен в 1, значение считается отрицательным (от -128 до -1 вместо 128 до 255), и путем преобразования его в int все дополнительные старшие биты установлены в 1 для сохранения одинаковых значений (от -128 до -1).

В вашей программе эти дополнительные биты, установленные в 1, находятся в прямом конфликте со значением в byteH при применении битового оператора ИЛИ |, перезаписывая (насыщая) значения красного и (часть) зеленого, которые вы пытаетесь извлечь и отобразить.

curPixel = (byteH << 8) | (byteL); // BUG: issue with negative byteL values

Решение состоит в том, чтобы применить AND-маска, чтобы быть уверенным, чтобы избавиться от любых нежелательных битов, прежде чем применять битовый оператор ИЛИ.

curPixel = byteL & 0xFF; // Convert byte to int to be within [0 , 255]
curPixel = (byteH << 8) | curPixel; // Apply OR bit-operator
...