📄 dib.cpp
字号:
// DIB.cpp: implementation of the DIB class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DIB.h"
#include"math.h"
#define WIDTHBYTES(bits) ((bits+31)/32*4)
#define RECTWIDTH(x) (x->right-x->left)
#define RECTHEIGHT(x) (x->bottom-x->top)
#define THRESHOLDCONTRAST 40
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define PI 3.1415926
extern int locax,locay;
#define m_WIDTH 600
#define m_HEIGHT 600
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
/////////////////////////////////////////////////////////////////////
HDIB DIB::ReadDIBFile(HANDLE hFile)
{
BITMAPFILEHEADER bmfHeader;
DWORD dwBitsSize;
HANDLE hDIB;
HANDLE hDIBtmp;
LPBITMAPINFOHEADER lpbi;
DWORD dwRead;
//得到文件大小
dwBitsSize = GetFileSize(hFile,NULL);
hDIB = GlobalAlloc(GMEM_MOVEABLE,(DWORD)(sizeof(BITMAPINFOHEADER)));
if(!hDIB)
return NULL;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
if(!lpbi)
{
GlobalFree(hDIB);
return NULL;
}
if(!ReadFile(hFile,(LPBYTE)&bmfHeader,sizeof(BITMAPFILEHEADER),&dwRead,NULL))
goto ErrExit;
if(sizeof(BITMAPFILEHEADER)!=dwRead)//读取文件出错
goto ErrExit;
if(bmfHeader.bfType != 0x4d42)//文件类型不匹配
goto ErrExit;
if(!ReadFile(hFile,(LPBYTE)lpbi,sizeof(BITMAPINFOHEADER),&dwRead,NULL))
goto ErrExit;
if(sizeof(BITMAPINFOHEADER)!= dwRead)//读取数据出错
goto ErrExit;
GlobalUnlock(hDIB);
if(lpbi->biSizeImage==0)
lpbi->biSizeImage = (this->BytePerLine(hDIB))*lpbi->biHeight;
hDIBtmp = GlobalReAlloc(hDIB,lpbi->biSize+lpbi->biSizeImage,0);
if(!hDIBtmp)
goto ErrExitNoUnlock;
else
hDIB = hDIBtmp;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
//根据情况设定文件指针
if(bmfHeader.bfOffBits != 0L)
SetFilePointer(hFile,bmfHeader.bfOffBits,NULL,FILE_BEGIN);
//读取文件的象素颜色数据
if(ReadFile(hFile,(LPBYTE)lpbi+lpbi->biSize,lpbi->biSizeImage,&dwRead,NULL))
goto OKExit;
ErrExit:
GlobalUnlock(hDIB);
ErrExitNoUnlock:
GlobalFree(hDIB); //释放内存
return NULL;
OKExit:
GlobalUnlock(hDIB);
return hDIB;
}
HDIB DIB::LoadDIB(LPCTSTR lpFileName)
{
HANDLE hDIB;
HANDLE hFile;
//创建文件句柄
if((hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL))!= INVALID_HANDLE_VALUE)
{
//读取数据
hDIB = ReadDIBFile(hFile);
//关闭文件句柄
CloseHandle(hFile);
return hDIB;
}
return NULL;
}
BOOL DIB::PaintDIBTrue(HDC hDC,LPRECT lpDCRect,HANDLE hDIB,LPRECT lpDIBRect ,DWORD dwRop)
{
LPBYTE lpDIBHdr;
LPBYTE lpDIBBits;
BOOL bSuccess = FALSE;
if(!hDIB)
return FALSE;
lpDIBHdr = (LPBYTE)GlobalLock(hDIB);
lpDIBBits = lpDIBHdr + sizeof(BITMAPINFOHEADER);
bSuccess = StretchDIBits(hDC,lpDCRect->left,
lpDCRect->top,
RECTWIDTH(lpDCRect),
RECTHEIGHT(lpDCRect),
lpDIBRect->left,
((LPBITMAPINFOHEADER)lpDIBHdr)->biHeight-lpDIBRect->top-RECTHEIGHT(lpDIBRect),
RECTWIDTH(lpDIBRect),
RECTHEIGHT(lpDIBRect),
lpDIBBits,
(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY);
GlobalUnlock(hDIB);
return bSuccess;
}
WORD DIB::BytePerLine(HANDLE hDIB)
{
WORD i;
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
i = WIDTHBYTES((lpbi->biWidth)*24);
GlobalUnlock(hDIB);
return i;
}
//函数实现图片从彩色到黑白的转换
HDIB DIB::ToGray(HANDLE hDIB)
{
HDIB hNewDIB = NULL;
LPBITMAPINFOHEADER lpSrc,lpDest;
LPBYTE lpS,lpD;
DWORD dwBytesPerLine;
DWORD dwImgSize;
WORD wBytesPerLine;
unsigned i ,j,height,width;
if(!hDIB)
return NULL;
lpSrc = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
dwBytesPerLine = WIDTHBYTES(24*(lpSrc->biWidth));
dwImgSize = lpSrc->biHeight * dwBytesPerLine;
//申请新的内存,大小等于原来图象的大小
hNewDIB = GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER)+dwImgSize);
lpDest = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
//保存图片的长宽、颜色深度等信息
memcpy((void*)lpDest,(void*)lpSrc,sizeof(BITMAPINFOHEADER));
DWORD dwSBytesPerLine;
dwSBytesPerLine = (24*(lpSrc->biWidth)+31)/32*4;
height = lpDest->biHeight;
width = lpDest->biWidth;
lpS = (LPBYTE)lpSrc;
wBytesPerLine = this->BytePerLine(hDIB);
lpD = (LPBYTE)lpDest;
lpS = lpS + sizeof(BITMAPINFOHEADER);
lpD = lpD + sizeof(BITMAPINFOHEADER);
unsigned r , g ,b,gray ;
//扫描整个图片,实现灰度化
for(i = 0 ;i<height; i++)
{
for(j = 0 ;j<(unsigned )lpDest->biWidth;j++)
{
//获得原来图片的颜色值
r = *(lpS++);
g = *(lpS++);
b = *(lpS++);
//计算灰度值
gray = (g*50+r*39+b*11)/100;
//保存灰度值到目标图片
*(lpD++)=gray;
*(lpD++) = gray;
*(lpD++) = gray;
}
//处理四字节对齐问题
unsigned k ;
for(k=0;k<dwSBytesPerLine-lpSrc->biWidth*3;k++)
{
lpS++;
lpD++;
}
}
GlobalUnlock(hDIB);
GlobalUnlock(hNewDIB);
return hNewDIB;
}
LPBYTE DIB::FindDIBBits(HANDLE hDIB)
{
LPBYTE lpDIB,lpDIBtmp;
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
lpDIBtmp = (LPBYTE)lpbi;
lpDIB = lpDIBtmp + sizeof(BITMAPINFOHEADER);
GlobalUnlock(hDIB);
return lpDIB;
}
long DIB::PixelOffset(int i,int j,WORD wBytePerLine)
{
long Offset;
Offset = i*wBytePerLine + j*3;
return Offset;
}
int DIB::BOUND(int a ,int b ,int rgb)
{
if(rgb<0)
return BOUND(a,b,abs(rgb));
if(rgb>b)
return b;
return rgb;
}
//实现图片的黑白二值化
void DIB::WhiteBlack(HANDLE hDIB,unsigned n)
{
LPBITMAPINFOHEADER lpbi;
LPBYTE lpS;
int width,height;
long lOffset;
WORD wBytesPerLine;
if(!hDIB)
return ;
wBytesPerLine = this->BytePerLine(hDIB);
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
//得到图片的长宽信息
width = lpbi->biWidth;
height = lpbi->biHeight;
lpS = (LPBYTE)lpbi;
//lps指向数据区
lpS = lpS + sizeof(BITMAPINFOHEADER);
//扫描整个图片,实现二值化
for(int i = 0;i<height;i++)
for(int j = 0 ;j<width;j++)
{ //得到象素数据在数据区中的偏移
lOffset = this->PixelOffset(i,j,wBytesPerLine);
if(*(lpS+lOffset)<n)//象素值小于临界值
{ //把象素填充为黑色
*(lpS+lOffset++) = 0;
*(lpS+lOffset++) = 0;
*(lpS+lOffset) = 0;
}
else //象素值大于临界值
{
//把象素填充为白色
*(lpS+lOffset++) = 255;
*(lpS+lOffset++) = 255;
*(lpS+lOffset) = 255;
}
}
GlobalUnlock(hDIB);
}
DIB::DIB()
{
for(int i=0;i<ImgRange; i++)
for (int j=0; j<ImgRange; j++)
this->lab[i][j] = false;
}
DIB::~DIB()
{
}
BOOL DIB:: SaveDIB(HANDLE hDib, CFile& file)
{
// Bitmap文件头
BITMAPFILEHEADER bmfHdr;
// 指向BITMAPINFOHEADER的指针
LPBITMAPINFOHEADER lpBI;
// DIB大小
DWORD dwDIBSize =0;
if (hDib == NULL)
{
// 如果DIB为空,返回FALSE
return FALSE;
}
// 读取BITMAPINFO结构,并锁定
lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
if (lpBI == NULL)
{
// 为空,返回FALSE
return FALSE;
}
// 判断是否是WIN3.0 DIB
// if (!IS_WIN30_DIB(lpBI))
// {
// 不支持其它类型的DIB保存
// 解除锁定
// ::GlobalUnlock((HGLOBAL) hDib);
// 返回FALSE
// return FALSE;
// }
// 填充文件头
// 文件类型"BM"
bmfHdr.bfType = 0x4d42; //DIB_HEADER_MARKER;
// 计算DIB大小时,最简单的方法是调用GlobalSize()函数。但是全局内存大小并
// 不是DIB真正的大小,它总是多几个字节。这样就需要计算一下DIB的真实大小。
// 文件头大小+颜色表大小
// (BITMAPINFOHEADER和BITMAPCOREHEADER结构的第一个DWORD都是该结构的大小)
// dwDIBSize = *(LPDWORD)lpBI; //+ ::PaletteSize((LPSTR)lpBI);
dwDIBSize = sizeof(BITMAPINFOHEADER);//+lpBI->biSizeImage;
// 计算图像大小
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
{
// 对于RLE位图,没法计算大小,只能信任biSizeImage内的值
dwDIBSize += lpBI->biSizeImage;
}
else
{
// 象素的大小
DWORD dwBmBitsSize;
// 大小为Width * Height
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*24) * lpBI->biHeight;
// 计算出DIB真正的大小
dwDIBSize += dwBmBitsSize;
// 更新biSizeImage(很多BMP文件头中biSizeImage的值是错误的)
lpBI->biSizeImage = dwBmBitsSize;
}
// 计算文件大小:DIB大小+BITMAPFILEHEADER结构大小
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
// 两个保留字
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
// 计算偏移量bfOffBits,它的大小为Bitmap文件头大小+DIB头大小+颜色表大小
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize;
// + PaletteSize((LPSTR)lpBI);
// 尝试写文件
// TRY
{
// 写文件头
file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
// 写DIB头和象素
file.WriteHuge(lpBI, dwDIBSize);
}
// CATCH (CFileException, e)
// {
// 解除锁定
// ::GlobalUnlock((HGLOBAL) hDib);
// 抛出异常
/// THROW_LAST();
// }
// END_CATCH
// 解除锁定
::GlobalUnlock((HGLOBAL) hDib);
// 返回TRUE
return TRUE;
}
HANDLE DIB::CopyHandle( HANDLE hSrc)
{
HANDLE hDst;
LPBITMAPINFOHEADER lpbi;
int width,height;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hSrc);
width = lpbi->biWidth;
height = lpbi->biHeight;
hDst = GlobalAlloc(GMEM_MOVEABLE,lpbi->biSize+lpbi->biSizeImage);
if(!hDst)
return NULL;
LPBYTE lpDest;
lpDest = (LPBYTE)GlobalLock(hDst);
memcpy(lpDest,(LPBYTE)lpbi,lpbi->biSize+lpbi->biSizeImage);
GlobalUnlock(hSrc);
GlobalUnlock(hDst);
return hDst;
}
//函数寻找图片中的特征区域的中心点
#define THRESHOLD (RADIUS*2+1)*(RADIUS*2+1)*15
//函数在一幅图片中寻找匹配的中心点
BOOL DIB::MatchImportantPoint(HANDLE hDIB,int CharaterInfo[RADIUS*2+1][RADIUS*2+1][3],CPoint *ImPoint)
{
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
int width = lpbi->biWidth;
int height = lpbi->biHeight;
LPBYTE lpData = this->FindDIBBits(hDIB);
WORD wBytesPerLine = this->BytePerLine(hDIB);
long lOffset;
long sum =100000,tempsum;
//扫描整个图片(边缘点)除外
for(int i=RADIUS ;i<height-RADIUS;i++)
for(int j=RADIUS;j<width-RADIUS;j++)
{
tempsum =0;
//扫描以RADIUS*2+1为边长的正方形区域
for(int k=-RADIUS;k<=RADIUS;k++)
for(int kk=-RADIUS;kk<=RADIUS;kk++)
{
//计算当前正方形和已知特征区域的颜色差值
lOffset = this->PixelOffset(i+k,j+kk,wBytesPerLine);
int colorblue = abs(*(lpData+lOffset++)-CharaterInfo[k+RADIUS][kk+RADIUS][0]);
int colorgreen = abs(*(lpData+lOffset++)-CharaterInfo[k+RADIUS][kk+RADIUS][1]);
int colorred = abs(*(lpData+lOffset++)-CharaterInfo[k+RADIUS][kk+RADIUS][2]);
tempsum +=colorgreen+colorblue+colorred;
}
if(tempsum<sum)
{ //更新差值
sum = tempsum;
//更改特征坐标点
ImPoint->x = j;
ImPoint->y = i;
}
}
if(sum <THRESHOLD){//找到满足条件的区域
//下面的代码把找到的区域的边框设置成为白色
for(i =-RADIUS;i<=RADIUS;i++)
{
lOffset = this->PixelOffset(ImPoint->y-RADIUS,ImPoint->x+i,wBytesPerLine);
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
}
for(i =-RADIUS;i<=RADIUS;i++)
{
lOffset = this->PixelOffset(ImPoint->y+RADIUS,ImPoint->x+i,wBytesPerLine);
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
}
for(i =-RADIUS;i<=RADIUS;i++)
{
lOffset = this->PixelOffset(ImPoint->y+i,ImPoint->x+RADIUS,wBytesPerLine);
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
}
for(i =-RADIUS;i<=RADIUS;i++)
{
lOffset = this->PixelOffset(ImPoint->y+i,ImPoint->x-RADIUS,wBytesPerLine);
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
*(lpData+lOffset++) = 255;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -