I'm running into a problem converting raw rgb565 into rgb888. I'm getting psychedelic looking images:
I followed the advice from this forum post, but I have not been able to fix the problem. Has anyone else delt with this before?
void convertRGB565To888(const uint8_t* rgbData, File outFile) { // need to abrastc height and width
//Write the BMP header
for(int i = 0; i < 54; i++) {
char ch = pgm_read_byte(&bmp_header[i]);
outFile.write((uint8_t*)&ch,1);
}
for(int i = 0; i < 240; i++) {
for(int j = 0; j < 320; j++) {
int bytePosition = (i * 320 + j) * 2; // each pixel is 2 bytes in RGB565
char VH = rgbData[bytePosition];
char VL = rgbData[bytePosition + 1]; //low byte
// RGB565 to RGB888 Conversion
byte b = (((VH & 0x1F) * 527) + 23) >> 6;
//b = 0;
byte r = ((((VL >> 3) & 0x1F) * 527) + 23) >> 6;
//r = 0;
byte g = ((((((VH & 0xF0) >> 5) | ((VL & 0x0F) << 3)) & 0x3F) * 259) + 33) >> 6;
//g = 0;
//Write image data to file
outFile.write(b);
outFile.write(g);
outFile.write(r);
}
outFile.flush();
outFile.close();
Serial.println("Image converted to RGB888 and written to file.");
}
}
...
// WHERE THE FUNC IS CALLED;
uint8_t* frameData = fb.getBuffer();
// convert 565 to 888
File rgb888File = SD.open("rgb888.bmp", FILE_WRITE);
if (rgb888File) {
convertRGB565To888(frameData, rgb888File);
rgb888File.flush();
} else {
Serial.println("Failed to open rgb888_image.bmp for writing.");
return;
}
There are a lot of magic numbers in the conversion code..
try
byte r = (VH >> 3) << 3;
byte b = (((VH & 0x07) << 3) | (VL >> 5)) << 2;
byte g = (VL & 0x1F) << 3;
That didn't work, thanks though. If you check out the final post of the forum I linked it shows exactly why those magic numbers are needed
Got it working, swapped the low and high bytes for the nicla and it cleaned everything up. Here is the code if anyone is wondering:
void convertRGB565To888(const uint8_t* rgbData, File outFile) { // need to abrastc height and width
//Write the BMP header
for(int i = 0; i < 54; i++) {
char ch = pgm_read_byte(&bmp_header[i]);
outFile.write((uint8_t*)&ch,1);
}
for(int i = 0; i < 240; i++)
for(int j = 0; j < 320; j++) {
int bytePosition = (i * 320 + j) * 2; // each pixel is 2 bytes in RGB565
char VL = rgbData[bytePosition]; // low byte
char VH = rgbData[bytePosition + 1]; // high byte
// RGB565 to RGB888 Conversion
byte b = (((VH & 0x1F) * 527) + 23) >> 6;
//b = 0;
byte r = ((((VL >> 3) & 0x1F) * 527) + 23) >> 6;
//r = 0;
byte g = ((((((VH & 0xF0) >> 5) | ((VL & 0x0F) << 3)) & 0x3F) * 259) + 33) >> 6;
//g = 0;
//byte r = (VH >> 3) << 3;
//byte b = (((VH & 0x07) << 3) | (VL >> 5)) << 2;
//byte g = (VL & 0x1F) << 3;
//Write image data to file
outFile.write(b);
outFile.write(g);
outFile.write(r);
}
outFile.flush();
outFile.close();
Serial.println("Image converted to RGB888 and written to file.");
}
Can you explain the *527 and the +23?
My assumption is that you scale it (527) and then rounding (+23) it to get the range 0..255?
Good to hear you solved it, and thanks for posting the working code.
RGB565 = [rrrrrggg][gggbbbbb]; // so VH = [rrrrrggg]
Swapped G and B channel in my code above,
this should work could you verify? or does it need the VH-VL swap?
byte r = (VH >> 3) << 3;
byte g = (((VH & 0x07) << 3) | (VL >> 5)) << 2;
byte b = (VL & 0x1F) << 3;
I can, this forum post explains it better than I could though. Essentially you are correct as there is a whole host of things going on when you try to bit shift something. E.g. with R5 = B11111, you expect R8 to be B11111111 (which is the result of the magic calculation), not B11111000 (which is the result of left shift by 3).
And yes, your method does appear to work however there exists some corruption and the file size increases massively - not sure exactly why.
Thanks again for your help!