最近在做OCR识别,在本机上做好的程序在服务器上的VM虚拟机上出现了问题,进行调试,发现原来服务器的VM虚拟机里面的颜色是16位色彩的,截的图也默认是16位,而tesseract是不识别16位的,因此我就想把16位改成32位。本来我以为16位就是两种颜色共用1个字节,以为也是rgba的格式,结果在改写的过程发现转换的结果一直不对,经过4!变换对应,我意识到我的思路出现问题,通过查找,发现16位是565或者0555的模式(这个要注意高字节低字节的问题),于是在尝试了一番,果然可用,下面贴上我的转换代码,代码比较粗糙,但是希望给困惑中的人带来帮助。注意:这个代码适用于VM虚拟机中的xp16位颜色模式,其他的16位需要具体分析。
//后面用到的数据,我在构造函数有初始化
BITMAPFILEHEADER *pBmpFileHeader;
BITMAPINFOHEADER *pBmpInfoHeader;
BYTE *pBmpData;
bool OCR::Convert16Bit232Bit(char *source, char *savefile)
{
//读文件
//前面这里的有些函数是我自己用来校验文件存在和后缀的,去掉不影响使用,直接从读文件开始就可以了
int len = helper->GetStringLength(source);
char *fullpath = new char[len + 10];
memset(fullpath, 0 ,sizeof(char) * (len + 10));
helper->GetExtensionFilePath(source, fullpath);
if (!helper->FileIsExist(fullpath))
{
#ifdef _CONSOLE_SHOW_
std::cout << "ERROR 1. The file can\'t open." << std::endl;
#endif
delete[] fullpath;
return false;
}
FILE *fp = fopen(fullpath, "rb");
if (NULL != fullpath)
{
delete[] fullpath;
fullpath = NULL;
}
if (!fp)
{
#ifdef _CONSOLE_SHOW_
std::cout << "ERROR 2. The file can\'t open." << std::endl;
#endif
return false;
}
pBmpFileHeader = new BITMAPFILEHEADER();
pBmpInfoHeader = new BITMAPINFOHEADER();
fread(pBmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fread(pBmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
pBmpData = new BYTE[pBmpInfoHeader->biSizeImage];
if (!pBmpData)
{
#ifdef _CONSOLE_SHOW_
std::cout << "ERROR 3. The memory assigned fail." << std::endl;
#endif
return false;
}
memset(pBmpData, 0, sizeof(BYTE) * (pBmpInfoHeader->biSizeImage));
fread(pBmpData, sizeof(BYTE), pBmpInfoHeader->biSizeImage, fp);
fclose(fp);
fp = NULL;
//转换成32位
int lineBytes = (pBmpInfoHeader->biWidth * 32 + 31) / 32 * 4;
int oldLineBytes = (pBmpInfoHeader->biWidth * 16 + 31) / 32 *4;
int oldSize = pBmpInfoHeader->biSizeImage;
pBmpInfoHeader->biBitCount = 32;
pBmpInfoHeader->biSizeImage = lineBytes * pBmpInfoHeader->biHeight;
BYTE *pData = new BYTE[pBmpInfoHeader->biSizeImage];
memset(pData, 255, sizeof(BYTE) * pBmpInfoHeader->biSizeImage);
WORD *temp = (WORD*)pBmpData;
for (int i = 0; i < pBmpInfoHeader->biHeight; ++i)
{
for (int j = 0; j < pBmpInfoHeader->biWidth; ++j)
{
//变量声明应该写在循环外,可以提高速度,尤其是图比较大时
int color1 = (float)(((*(temp + i * oldLineBytes/2 + j)) & 0x1f)) / 31.0f * 255;
int color2 = (float)(((*(temp + i * oldLineBytes/2 + j)) & 0x3e0) >> 5) / 31.0f * 255;
int color3 = (float)(((*(temp + i * oldLineBytes/2 + j)) & 0x7c00) >> 10) / 31.0f * 255;
//红色
*(pData + i * lineBytes + 4 * j + 2) = color3;
//绿色 //e0 7
*(pData + i * lineBytes + 4 * j + 1) = color2;
//蓝色
*(pData + i * lineBytes + 4 * j + 0) = color1;
//aphla
*(pData + i * lineBytes + 4 * j + 3) = 255;
}
}
//写
if (savefile != NULL)
{
fp = fopen(savefile, "wb");
if (!fp)
{
#ifdef _CONSOLE_SHOW_
std::cout << "ERROR 6. The file can\'t write." << std::endl;
#endif
//这里应该释放new出的内存,在网页上编写比较费劲,就不改了
return false;
}
fwrite(pBmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(pBmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
fwrite(pData, sizeof(BYTE), pBmpInfoHeader->biSizeImage, fp);
fclose(fp);
fp = NULL;
}
if (NULL != pBmpData)
{
delete[] pBmpData;
pBmpData = NULL;
}
if (NULL != pBmpFileHeader)
{
delete pBmpFileHeader;
pBmpFileHeader = NULL;
}
if (NULL != pBmpInfoHeader)
{
delete pBmpInfoHeader;
pBmpInfoHeader = NULL;
}
if (NULL != pData)
{
delete[] pData;
pData = NULL;
}
return true;
}