24bit RGB888 -> 16bit RGB565 的转换
24ibt RGB888 {R7 R6 R5 R4 R3 R2 R1 R0} {G7 G6 G5 G4 G3 G2 G1 G0} {B7 B6 B5 B4 B3 B2 B1 B0}
16bit RGB656 {R7 R6 R5 R4 R3} {G7 G6 G5 G4 G3 G2} {B7 B6 B5 B4 B3}
可以修正,比如(当然人眼无法感觉,但是RG888-RGB565-RGB888的时候更好补偿)
R:197=>197>>3=24
R:197=192+5=>24+0.625≈25
所以
R5=R[2] ? R[7:3]+1 : R[7:3];
G5=G[1] ? G[7:2]+1 : G[7:2];
B5=B[2] ? B[7:3]+1 : B[7:3];
16bit RGB565 -> 24bit RGB888 的转换
16bit RGB656 {R4 R3 R2 R1 R0} {G5 G4 G3 G2 G1 G0} {B4 B3 B2 B1 B0}
24ibt RGB888 {R4 R3 R2 R1 R0 0 0 0} {G5 G4 G3 G2 G1 G0 0 0} {B4 B3 B2 B1 B0 0 0 0}
进行精度补偿(剩余的用低位进行补偿)
24ibt RGB888 {R4 R3 R2 R1 R0 R2 R1 R0} {G5 G4 G3 G2 G1 G0 G1 G0} {B4 B3 B2 B1 B0 B2 B1 B0}
总结一下:
1、量化压缩的方法:
三个字节对应取高位
2、量化补偿的方法:
(1) 将原数据填充至高位
(2) 对于低位,用原始数据的低位进行补偿
3、RGB565互转代码
#define RGB565_MASK_RED 0xF800 #define RGB565_MASK_GREEN 0x07E0 #define RGB565_MASK_BLUE 0x001F void rgb565_2_rgb24(BYTE *rgb24, WORD rgb565) //分离出单独的RGB { rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11; rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5; rgb24[0] = (rgb565 & RGB565_MASK_BLUE); //往高位移动填满单字节的8位 rgb24[2] <<= 3; rgb24[1] <<= 2; rgb24[0] <<= 3; }
下面的代码来自这个网址:
http://bbs.csdn.net/topics/350153377
#ifndef WIDTHBYTES #define WIDTHBYTES(bits) ((DWORD)(((bits)+31) & (~31)) / 8) #endif // BITMAPINFOHEADER m_bmih; // BYTE *m_pR; // BYTE *m_pG; // BYTE *m_pB; BOOL CImageProcessor::LoadFileFromBitmap(LPCTSTR lpFileName) { if(lpFileName == NULL) { return FALSE; } HANDLE hFile = ::CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) { return FALSE; } BOOL bRet = FALSE; do { LARGE_INTEGER liSize; liSize.QuadPart = 0; ::GetFileSizeEx(hFile, &liSize); BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; DWORD dwByteRead = 0; ::ReadFile(hFile, &bmfh, sizeof(bmfh), &dwByteRead, NULL); if(dwByteRead < sizeof(bmfh)) { break; } if(bmfh.bfType != ‘MB‘ || bmfh.bfSize > liSize.QuadPart || bmfh.bfOffBits > liSize.QuadPart) { break; } dwByteRead = 0; ::ReadFile(hFile, &bmih, sizeof(bmih), &dwByteRead, NULL); if(dwByteRead < sizeof(bmih)) { break; } int nBitmapSize = abs(bmih.biHeight) * WIDTHBYTES(bmih.biWidth * bmih.biBitCount); if(bmih.biPlanes != 1) { break; } if(bmih.biBitCount != 1 && bmih.biBitCount != 4 && bmih.biBitCount != 8 && bmih.biBitCount != 16 && bmih.biBitCount != 24 && bmih.biBitCount != 32) { break; } if(bmih.biCompression != BI_RGB && bmih.biCompression != BI_BITFIELDS) { break; } if(bmih.biWidth <= 0 || bmih.biHeight == 0) { break; } if(bmfh.bfOffBits + nBitmapSize > liSize.QuadPart) { break; } m_pR = new BYTE[bmih.biWidth * abs(bmih.biHeight)]; m_pG = new BYTE[bmih.biWidth * abs(bmih.biHeight)]; m_pB = new BYTE[bmih.biWidth * abs(bmih.biHeight)]; if(bmih.biBitCount < 16) { //... } else if(bmih.biBitCount == 16) { //... } else if(bmih.biBitCount == 24) { ::SetFilePointer(hFile, bmfh.bfOffBits, NULL, SEEK_SET); BYTE *pData = new BYTE[nBitmapSize]; dwByteRead = 0; ::ReadFile(hFile, pData, nBitmapSize, &dwByteRead, NULL); BYTE *pR = m_pR; BYTE *pG = m_pG; BYTE *pB = m_pB; for(int j = 0; j < abs(bmih.biHeight); j++) { BYTE *pTemp = pData + WIDTHBYTES(bmih.biWidth * bmih.biBitCount) * j; for(int i = 0; i < bmih.biWidth; i++) { *pB++ = *pTemp++; *pG++ = *pTemp++; *pR++ = *pTemp++; } } delete[] pData; } else if(bmih.biBitCount == 32) { //... } memcpy(&m_bmih, &bmih, sizeof(m_bmih)); bRet = TRUE; } while(0); CloseHandle(hFile); return bRet; } BOOL CImageProcessor::SaveFile565(HANDLE hFile) { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; memset(&bmfh, 0, sizeof(bmfh)); memset(&bmih, 0, sizeof(bmih)); int nBitmapSize = abs(m_bmih.biHeight) * WIDTHBYTES(m_bmih.biWidth * 16); bmfh.bfType = ‘MB‘; bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih) + 12; bmfh.bfSize = bmfh.bfOffBits + nBitmapSize; bmih.biSize = sizeof(bmih); bmih.biWidth = m_bmih.biWidth; bmih.biHeight = m_bmih.biHeight; bmih.biPlanes = 1; bmih.biBitCount = 16; bmih.biCompression = BI_BITFIELDS; bmih.biSizeImage = nBitmapSize; BYTE *pData = new BYTE[nBitmapSize]; memset(pData, 0, nBitmapSize); BYTE *pR = m_pR; BYTE *pG = m_pG; BYTE *pB = m_pB; for(int j = 0; j < abs(bmih.biHeight); j++) { WORD *pTemp = (WORD *)(pData + WIDTHBYTES(bmih.biWidth * 16) * j); for(int i = 0; i < bmih.biWidth; i++) { #if 1 *pTemp++ = ((WORD)(*pR++ << 8) & 0xf800) | ((WORD)(*pG++ << 3) & 0x07e0) | ((WORD)(*pB++ >> 3) & 0x001f); #else int nR = (*pR++ + 4) >> 3; int nG = (*pG++ + 2) >> 2; int nB = (*pB++ + 4) >> 3; if(nR > 31) nR = 31; if(nG > 63) nG = 63; if(nB > 31) nB = 31; *pTemp++ = (nR << 11) | (nG << 5) | nB; #endif } } DWORD nRGBMask[3]; nRGBMask[0] = 0xf800; nRGBMask[1] = 0x07e0; nRGBMask[2] = 0x001f; DWORD dwByteWritten = 0; ::WriteFile(hFile, &bmfh, sizeof(bmfh), &dwByteWritten, NULL); ::WriteFile(hFile, &bmih, sizeof(bmih), &dwByteWritten, NULL); ::WriteFile(hFile, nRGBMask, sizeof(nRGBMask), &dwByteWritten, NULL); ::WriteFile(hFile, pData, nBitmapSize, &dwByteWritten, NULL); delete[] pData; return TRUE; }