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 R00 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;
}
下面的代码来自这个网址:
#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)
{returnFALSE;
}
HANDLE hFile= ::CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);if(hFile ==INVALID_HANDLE_VALUE)
{returnFALSE;
}
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 = newBYTE[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);returnbRet;
}
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 = newBYTE[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;returnTRUE;
}