How does one convert 16-bit RGB565 to 24-bit RGB888?

后端 未结 8 906
深忆病人
深忆病人 2020-11-27 03:22

I’ve got my hands on a 16-bit rgb565 image (specifically, an Android framebuffer dump), and I would like to convert it to 24-bit rgb888 for viewing on a normal monitor.

8条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-11-27 04:00

    iOS vImage Conversion

    The iOS Accelerate Framework documents the following algorithm for the vImageConvert_RGB565toARGB8888 function:

    Pixel8 alpha = alpha
    Pixel8 red   = (5bitRedChannel   * 255 + 15) / 31
    Pixel8 green = (6bitGreenChannel * 255 + 31) / 63
    Pixel8 blue  = (5bitBlueChannel  * 255 + 15) / 31
    

    For a one-off conversion this will be fast enough, but if you want to process many frames you want to use something like the iOS vImage conversion or implement this yourself using NEON intrinsics.

    From ARMs Community Forum Tutorial

    First, we will look at converting RGB565 to RGB888. We assume there are eight 16-bit pixels in register q0, and we would like to separate reds, greens and blues into 8-bit elements across three registers d2 to d4.

     vshr.u8      q1, q0, #3      @ shift red elements right by three bits,
                                    @  discarding the green bits at the bottom of
                                    @  the red 8-bit elements.
    vshrn.i16    d2, q1, #5      @ shift red elements right and narrow,
                                    @  discarding the blue and green bits.
    vshrn.i16    d3, q0, #5      @ shift green elements right and narrow,
                                    @  discarding the blue bits and some red bits
                                    @  due to narrowing.
    vshl.i8      d3, d3, #2      @ shift green elements left, discarding the
                                    @  remaining red bits, and placing green bits
                                    @  in the correct place.
    vshl.i16  q0, q0, #3      @ shift blue elements left to most-significant
                                    @  bits of 8-bit color channel.
    vmovn.i16    d4, q0          @ remove remaining red and green bits by
                                    @  narrowing to 8 bits.
    

    The effects of each instruction are described in the comments above, but in summary, the operation performed on each channel is: Remove color data for adjacent channels using shifts to push the bits off either end of the element. Use a second shift to position the color data in the most-significant bits of each element, and narrow to reduce element size from 16 to eight bits.

    Note the use of element sizes in this sequence to address 8 and 16 bit elements, in order to achieve some of the masking operations.

    A small problem

    You may notice that, if you use the code above to convert to RGB888 format, your whites aren't quite white. This is because, for each channel, the lowest two or three bits are zero, rather than one; a white represented in RGB565 as (0x1F, 0x3F, 0x1F) becomes (0xF8, 0xFC, 0xF8) in RGB888. This can be fixed using shift with insert to place some of the most-significant bits into the lower bits.

    For an Android specific example I found a YUV-to-RGB conversion written in intrinsics.

提交回复
热议问题