www.pudn.com > face.rar > 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 ;ibiWidth;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;kbiWidth*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;iPixelOffset(i,j,wBytesPerLine);
if(*(lpS+lOffset)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 ;iPixelOffset(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(tempsumx = j;
ImPoint->y = i;
}
}
if(sum 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;
}
GlobalUnlock(hDIB);
return true;
}
else AfxMessageBox("Can't find the corresponding point!");
GlobalUnlock(hDIB);
return false;
}
//比较两张图片的相似度
BOOL DIB::IsScaterPoint(int x, int y, int width, int height, LPBYTE lpData,WORD wBytesPerLine, int threshold,bool lab[m_HEIGHT][m_WIDTH])
{
long lOffset;
//得到数据的偏移
lOffset = this->PixelOffset(y,x,wBytesPerLine);
//判断该点是否为白色以及是否计算过了
if(*(lpData+lOffset) == 255 && lab[y][x] == false)
{
//链长度加一
this->lenth++;
//更改标志位
lab[y][x] = true;
//如果链长度达到临界值则返回真
if(this->lenth >= threshold)
return true;
//对右边点的边界判断以及标志位判断
if(x+1lenth>=threshold)
return true;
}
//处理左边的点
if(x-1>=0 && lab[y][x-1] == false)
{
(IsScaterPoint(x-1,y,width,height,lpData,wBytesPerLine,threshold,lab));
if(this->lenth>=threshold)
return true;
}
//处理上面的点
if(y-1>=0 && lab[y-1][x]==false)
{
(IsScaterPoint(x,y-1,width,height,lpData,wBytesPerLine,threshold,lab));
if(this->lenth>=threshold)
return true;
}
//处理下面的点
if(y+1lenth>=threshold)
return true;
}
//处理右下的点
if(y+1lenth>=threshold)
return true;
}
//处理左下的点
if(y+1=0 && lab[y+1][x-1]==false)
{ (IsScaterPoint(x-1,y+1,width,height,lpData,wBytesPerLine,threshold,lab));
if(this->lenth>=threshold)
return true;
}
//处理左上的点
if(y-1>=0 && x-1 >=0 &&lab[y-1][x-1]==false)
{ (IsScaterPoint(x-1,y-1,width,height,lpData,wBytesPerLine,threshold,lab));
if(this->lenth>=threshold)
return true;
}
//处理右上的点
if(y-1lenth>=threshold)
return true;
}
}
//如果递归结束,长度达不到临界值,返回假
return false;
}
BOOL DIB::LightingCompensate(HANDLE hDIB)
{
if(!hDIB)
return FALSE;
LPBITMAPINFOHEADER lpbi;
int width,height;
LPBYTE lpData;
WORD wBytesPerLine;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
//得到图片宽和高
width = lpbi->biWidth;
height = lpbi->biHeight;
//得到图片数据区
lpData = this->FindDIBBits(hDIB);
//得到图片每行的象素所占字节个数
wBytesPerLine = this->BytePerLine(hDIB);
//比例系数
const float thresholdco = 0.05;
//象素个数的临界常数
const int thresholdnum = 100;
//灰度级数组
int histogram[256];
for(int i =0;i<256;i++)
histogram[i] = 0;
//对于过于小的图片的判断
if(width*height*thresholdco < thresholdnum)
return false;
int colorr,colorg,colorb;
long lOffset;
//考察整个图片
for( i=0;iPixelOffset(i,j,wBytesPerLine);
//得到rgb值
colorb = *(lpData+lOffset++);
colorg = *(lpData+lOffset++);
colorr = *(lpData+lOffset++);
//计算灰度值
int gray = (colorr * 299 + colorg * 587 + colorb * 114)/1000;
histogram[gray]++;
}
int calnum =0;
int total = width*height;
int num;
//下面的循环得到满足系数thresholdco的临界灰度级
for(i =0;i<256;i++)
{
if((float)calnum/total < thresholdco)
{
calnum+= histogram[255-i];
num = i;
}
else
break;
}
int averagegray = 0;
calnum =0;
//得到满足条件的象素总的灰度值
for(i = 255;i>=255-num;i--)
{
averagegray += histogram[i]*i;
calnum += histogram[i];
}
averagegray /=calnum;
//得到光线补偿的系数
float co = 255.0/(float)averagegray;
//下面的循环对图象进行光线补偿
for(i =0;iPixelOffset(i,j,wBytesPerLine);
//得到蓝色分量
colorb = *(lpData+lOffset);
//调整
colorb *=co;
//临界判断
if(colorb >255)
colorb = 255;
//保存
*(lpData+lOffset) = colorb;
//绿色分量
colorb = *(lpData+lOffset+1);
colorb *=co;
if(colorb >255)
colorb = 255;
*(lpData+lOffset+1) = colorb;
//红色分量
colorb = *(lpData+lOffset+2);
colorb *=co;
if(colorb >255)
colorb = 255;
*(lpData+lOffset+2) = colorb;
}
return TRUE;
}
BOOL DIB::FaceModeling(int Cr,int Cb)
{
//Cb的系数常量
const float cx = 114.38;
//cr的系数常量
const float cy = 160.02;
//角度常量
const float theta = 2.53;
//x轴线和y轴线的两个常量
const float ecx = 1.60;
const float ecy = 2.41;
//长轴
const float a = 25.39;
//短轴
const float b = 14.03;
//相似度常量
const float judge = 0.5;
//计算得到x轴数值
float x = cos(theta)*(Cb-cx)+sin(theta)*(Cr-cy);
//y轴数值
float y = -sin(theta)*(Cb -cx)+cos(theta)*(Cr-cy);
//计算离心率
float temp = pow(x-ecx,2)/pow(a,2)+pow(y-ecy,2)/pow(b,2);
//如果满足要求返回真,否则假
if(fabs(temp-1.0)Kh)
Cb = 108 + ((Y-Kh)*10)/(Ymax - Kh);
else
Cb = -1;
return Cb;
}
int DIB::_Cr(int Y)
{
int Cr;
//亮度很小的情况
if(YKh)
Cr = 154 - ((Y-Kh)*22)/(Ymax - Kh);
else
Cr = -1;
return Cr;
}
int DIB::_WCr(int Y)
{
int WCr;
if(YKh)
//亮度很大的情况
WCr = WHcr + ((Ymax-Y)*(Wcr-WHcr))/(Ymax-Kh);
else WCr = -1;
return WCr;
}
int DIB:: _WCb(int Y)
{
int WCb;
if(YKh)
//亮度很大的情况
WCb = WHcb + ((Ymax-Y)*(Wcb-WHcb))/(Ymax-Kh);
else WCb = -1;
return WCb;
}
void DIB::YccTransform(LPBYTE lpYcc,WORD wBytesPerLine,int height,int width)
{
int Y,Cr,Cb;
long lOffset;
//下面的循环实现ycc色彩空间的非线性转换
for(int i=0;i=Kl && Y<=Kh)
continue;
//调用非线性转换函数调整Cr,Cb的数值
Cr = (Cr-_Cr(Y))*(Wcr/_WCr(Y))+_Cr(Kh);
Cb = (Cb-_Cb(Y))*(Wcb/_WCb(Y))+_Cb(Kh);
*(lpYcc+lOffset+1) = Cr;
*(lpYcc+lOffset+2) = Cb;
}
}
void DIB::faceear(LPBYTE lpYcc, WORD wBytesPerLine, int height,int width, bool flag[ImgRange][ImgRange])
{
//初始化标志位
for (int i=0; iCopyHandle(hDIB);
LPBITMAPINFOHEADER lpbi;
LPBYTE lpData;
WORD wBytesPerLine;
int height;
int width;
long lOffset;
//得到图象的基本信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
lpData = FindDIBBits(hDIB);
wBytesPerLine = BytePerLine(hDIB);
//人脸数目初始化为0
faceNum =0;
for(int k=0; k<10; k++)
{
//初始化区域
faceLocation[k].bottom = -1;
faceLocation[k].top = height;
faceLocation[k].right = -1;
faceLocation[k].left = width;
}
for(int i=0; iCopyHandle(hDIBTemp);
lpData = FindDIBBits(hDIB);
wBytesPerLine = BytePerLine(hDIB);
for (i=0; iPixelOffset(j, faceLocation[i].left, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
lOffset = this->PixelOffset(j, faceLocation[i].right, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
}
for (i=0; iPixelOffset(faceLocation[i].top, j, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
lOffset = this->PixelOffset(faceLocation[i].bottom, j, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
}
GlobalFree(hDIBTemp);
GlobalUnlock(hDIB);
}
void DIB::RecursiveLocateRect(LPBYTE lpData,WORD wBytesPerLine, int y, int x, int num, CRect &faceRect)
{
long lOffset;
//得到偏移
lOffset = PixelOffset(y,x,wBytesPerLine);
//数值判断
if(*(lpData + lOffset) == num)
{
//更改颜色为黑色
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
//修改矩形的上下左右四个点位置
if(faceRect.bottom < y)
{
faceRect.bottom = y;
}
if(faceRect.top > y)
{
faceRect.top = y;
}
if(faceRect.right < x)
{
faceRect.right = x;
}
if(faceRect.left > x)
{
faceRect.left = x;
}
//上下左右调用本函数进行区域判定
RecursiveLocateRect(lpData, wBytesPerLine, y-1, x, num,faceRect);
RecursiveLocateRect(lpData, wBytesPerLine, y+1, x, num, faceRect);
RecursiveLocateRect(lpData, wBytesPerLine, y, x-1, num, faceRect);
RecursiveLocateRect(lpData, wBytesPerLine, y, x+1, num, faceRect);
}
}
void DIB::EyeMapC(LPBYTE lpRgb, const LPBYTE lpYcc, WORD wBytesPerLine, CRect faceLocation)
{
long lOffset;
int cr;
int cb;
//根据传进来的矩形区域进行眼睛的色度匹配
for(int i=faceLocation.top; i<=faceLocation.bottom; i++)
for (int j=faceLocation.left; j<=faceLocation.right; j++)
{
//得到Cr,Cb数值
lOffset = PixelOffset(i, j, wBytesPerLine);
cr = *(lpYcc + lOffset +1);
cb = *(lpYcc + lOffset +2);
//标志
bool lab;
//判断Cb分量的数值,并修改标志
int cmap = cb -116 ;
if(cmap >-1 && cmap <4)
lab = true;
else
lab = false;
//判断Cr分量的数值,并修改标志
cmap = cr- 144 ;
if(cmap <=-2 || cmap>= 2)
{
lab = false;
}
//根据标志设定图像颜色
if(lab)
cmap = 255;
else
cmap = 0;
//保存图象颜色
*(lpRgb + lOffset++) = cmap;
*(lpRgb + lOffset++) = cmap;
*(lpRgb + lOffset++) = cmap;
}
}
void DIB::EyeMapb(LPBYTE lpRgb, const LPBYTE lpYcc, WORD wBytesPerLine, CRect faceLocation)
{
long lOffset;
int cr;
int cb;
for(int i=faceLocation.top; i<=faceLocation.bottom; i++)
for (int j=faceLocation.left; j<=faceLocation.right; j++)
{
lOffset = PixelOffset(i, j, wBytesPerLine);
cb = *(lpYcc + lOffset +2);
*(lpRgb + lOffset++) = cb;
*(lpRgb + lOffset++) = cb;
*(lpRgb + lOffset++) = cb;
}
}
void DIB::EyeMapR(LPBYTE lpRgb, const LPBYTE lpYcc, WORD wBytesPerLine, CRect faceLocation)
{
long lOffset;
int cr;
int cb;
for(int i=faceLocation.top; i<=faceLocation.bottom; i++)
for (int j=faceLocation.left; j<=faceLocation.right; j++)
{
lOffset = PixelOffset(i, j, wBytesPerLine);
cr = *(lpYcc + lOffset +1);
cb = *(lpYcc + lOffset +2);
*(lpRgb + lOffset++) = cr;
*(lpRgb + lOffset++) = cr;
*(lpRgb + lOffset++) = cr;
}
}
void DIB::ErasionFalseArea(HANDLE hDIB)
{
int PixelNum[255];
LPBITMAPINFOHEADER lpbi;
int width;
int height;
LPBYTE lpData;
WORD wBytesPerLine;
long lOffset;
//得到长宽信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
//得到数据区指针和每行字节数
lpData = FindDIBBits(hDIB);
wBytesPerLine = BytePerLine(hDIB);
//初始化象素累计数组
for (int i=0; i<255; i++)
{
PixelNum[i] = 0;
}
int calNum =1;
for (i=0; igray)
gray =255;
else
gray = 0;
*(lpRgb + lOffset++) = gray;
*(lpRgb + lOffset++) = gray;
*(lpRgb + lOffset++) = gray;
}
}
void DIB::RgbtoYcb(HANDLE hDIB, LPBYTE lpYcb)
{
LPBITMAPINFOHEADER lpbi;
int width,height;
WORD wBytesPerLine;
LPBYTE lpData;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
//得到图象的基本信息
width = lpbi->biWidth;
height = lpbi->biHeight;
lpData = FindDIBBits(hDIB);
wBytesPerLine = BytePerLine(hDIB);
long lOffset;
//下面的循环实现从rgb到ycc的转化
for(int i=0;ibiHeight;
width = lpbi->biWidth;
wBytesPerLine = BytePerLine(hDIB);
lpData = FindDIBBits(hDIB);
HANDLE hTempDIB;
LPBYTE lpTemp;
//申请同样大小的内存
hTempDIB = GlobalAlloc(GMEM_MOVEABLE,(DWORD)(sizeof(BITMAPINFOHEADER) + wBytesPerLine*height));
//判断内存情况
if(!hTempDIB)
{
GlobalFree(hTempDIB);
GlobalFree(hDIB);
return;
}
lpTemp = (LPBYTE)GlobalLock(hTempDIB);
lpTemp+= sizeof(BITMAPINFOHEADER);
//下面的循环实现腐蚀功能
for (int i=1; iPixelOffset(i, j, wBytesPerLine);
*(lpTemp + lOffset) = 255;
*(lpTemp + lOffset+1) = 255;
*(lpTemp + lOffset+2) = 255;
}
//如果当前点为黑色,则在暂时的目标区域中设置为黑色
else
{
*(lpTemp + lOffset) = 0;
*(lpTemp + lOffset+1) = 0;
*(lpTemp + lOffset+2) = 0;
}
}
//把图象周边的点全部设置为黑色
for(i=0; ibiHeight;
width = lpbi->biWidth;
wBytesPerLine = BytePerLine(hDIB);
lpData = FindDIBBits(hDIB);
HANDLE hTempDIB;
LPBYTE lpTemp;
//申请相同大小的内存
hTempDIB = GlobalAlloc(GMEM_MOVEABLE,(DWORD)(sizeof(BITMAPINFOHEADER) + wBytesPerLine*height));
if(!hTempDIB)
{
GlobalFree(hTempDIB);
GlobalFree(hDIB);
return;
}
lpTemp = (LPBYTE)GlobalLock(hTempDIB);
lpTemp+= sizeof(BITMAPINFOHEADER);
//下面的代码实现腐蚀功能
for (int i=1; iPixelOffset(i, j, wBytesPerLine);
*(lpTemp + lOffset) = 255;
*(lpTemp + lOffset+1) = 255;
*(lpTemp + lOffset+2) = 255;
}
//如果当前点为黑色,则把暂时区域中对应点设置为黑色
else
{
*(lpTemp + lOffset) = 0;
*(lpTemp + lOffset+1) = 0;
*(lpTemp + lOffset+2) = 0;
}
}
//把图象四周的点设置为黑色
for(i=0; ibiHeight;
width = lpbi->biWidth;
wBytesPerLine = this->BytePerLine(hDIB);
lpData = this->FindDIBBits(hDIB);
//申请一块和数据区大小相同的内存
lpTemp = (LPBYTE) new BYTE[wBytesPerLine * height];
long lOffsetJudge;
for (int i=1; iPixelOffset(i, j, wBytesPerLine);
//如果当前点为白色,接着循环
if(*(lpData + lOffset) == 255)
{
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
continue;
}
//否则考察上下左右四个点
else
{
lOffsetJudge = this->PixelOffset(i-1, j, wBytesPerLine);
//如果上面的点为白色
if(*(lpData + lOffsetJudge) == 255)
{ //设置为白色,并继续循环
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
continue;
}
//考察下面的点
lOffsetJudge = this->PixelOffset(i+1,j, wBytesPerLine);
if(*(lpData + lOffsetJudge) == 255)
{
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
continue;
}
//考察左边的点
lOffsetJudge = this->PixelOffset(i,j-1, wBytesPerLine);
if(*(lpData + lOffsetJudge) == 255)
{
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
continue;
}
//考察右边的点
lOffsetJudge = this->PixelOffset(i,j+1, wBytesPerLine);
if(*(lpData + lOffsetJudge) == 255)
{
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
*(lpTemp + lOffset++) = 255;
continue;
}
//如果上下左右都是黑色点,则把暂时区域的点设置为黑色
lOffset = this->PixelOffset(i,j,wBytesPerLine);
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
}
}
//处理图象四周的点,设置为黑色
for(i=0; iPixelOffset(i, 0, wBytesPerLine);
{
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
}
}
for(i=0; iPixelOffset(i, width-1, wBytesPerLine);
{
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
}
}
for(i=0; iPixelOffset(0, i, wBytesPerLine);
{
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
}
}
for(i=0; iPixelOffset(height-1, i, wBytesPerLine);
{
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
*(lpTemp + lOffset++) = 0;
}
}
//把暂时区域的点拷贝到原句柄区域下面
memcpy(lpData, lpTemp, wBytesPerLine*height);
delete [] lpTemp;
GlobalUnlock(hDIB);
}
void DIB::DeleteFasleEye(HANDLE hDIB, CRect facelocation)
{
LPBYTE lpData;
LPBITMAPINFOHEADER lpbi;
int height;
int width;
long lOffset;
WORD wBytesPerLine;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
lpData = this->FindDIBBits(hDIB);
wBytesPerLine = this->BytePerLine(hDIB);
for (int i=0; iPixelOffset(i, j, wBytesPerLine);
if(*(lpData + lOffset) == 255)
{
if(i<(facelocation.bottom+facelocation.top)/2)
{
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
}
}
}
GlobalUnlock(hDIB);
}
void DIB::DeleteScatePoint(HANDLE hDIB)
{
LPBITMAPINFOHEADER lpbi;
int height;
int width;
LPBYTE lpData;
WORD wBytesPerLine;
long lOffset;
//得到图象的基本信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
wBytesPerLine = this->BytePerLine(hDIB);
lpData = this->FindDIBBits(hDIB);
for (int i=0; iPixelOffset(i, j, wBytesPerLine);
//如果当前点为白色点
if(*(lpData + lOffset) == 255)
{
//设定判断数组
for(int ii = 0;iilab[ii][jj] = false;
//设定判断长度
this->lenth=0;
//判断是否为离散点
bool judge = this->IsScaterPoint(j, i, width,height,lpData,wBytesPerLine,3,this->lab);
if(!judge)
{
//是离散点则把该点设置为黑色
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 0;
}
}
}
GlobalUnlock(hDIB);
}
void DIB:: MouseMap(LPBYTE lpRgb, const LPBYTE lpYcc, WORD wBytesPerLine, CRect faceLocation)
{
//下面的循环在人脸的区域内实现嘴巴的匹配
for (int i=faceLocation.top; iPixelOffset(i, j, wBytesPerLine);
//得到cr,cb的数值
int cr = *(lpYcc+lOffset+1);
int cb = *(lpYcc+lOffset+2);
//标志
bool lab;
int mapm;
//根据cr的数值设定标志
cr = cr-143;
if(cr <-5 || cr>5)
{
cr = 0;
}
cr *=cr;
if(cr>16)
lab = true;
else
lab = false;
//根据cb的时值设定标志
cb= cb-120;
if(cb<-5 || cb >5)
{
cb = 0;
if(lab = true)
lab = false;
}
//如果cr,cb两项数值都在设定的范围之内,则设定颜色位白色,否则黑色
if(lab)
mapm = 255;
else
mapm = 0;
*(lpRgb + lOffset++) = mapm;
*(lpRgb + lOffset++) = mapm;
*(lpRgb + lOffset++) = mapm;
}
}
void DIB::MouthCenter(HANDLE hDIB, CRect faceLocation, CPoint &mouthLocation)
{
LPBITMAPINFOHEADER lpbi;
int height;
int width;
long lOffset;
WORD wBytesPerLine;
LPBYTE lpData;
//得到图象的基本信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
wBytesPerLine = this->BytePerLine(hDIB);
lpData = this->FindDIBBits(hDIB);
//下面的三个变量用来累计嘴巴区域的象素的x,y和象素点数
int xnum = 0 ;
int ynum = 0 ;
int count = 0;
for (int i=faceLocation.top; iPixelOffset(i, j, wBytesPerLine);
//白色点
if(*(lpData + lOffset) == 255)
{
//x值加
xnum +=j;
//y值加
ynum +=i;
//点数加
count++;
}
}
//得到中心点位置
mouthLocation.x = xnum/count;
mouthLocation.y = ynum/count;
//把中心点设置位绿色
lOffset = this->PixelOffset(mouthLocation.y, mouthLocation.x, wBytesPerLine);
*(lpData + lOffset++) =0;
*(lpData + lOffset++) =255;
*(lpData + lOffset++) =0;
GlobalUnlock(hDIB);
}
void DIB::EyeCenter(HANDLE hDIB, CRect faceLocation, CPoint &eye1, CPoint &eye2)
{
LPBITMAPINFOHEADER lpbi;
LPBYTE lpData;
long lOffset;
WORD wBytesPerLine;
int height;
int width;
int pixelnum =0;
int num =0;
//得到图象基本信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
lpData = this->FindDIBBits(hDIB);
wBytesPerLine = this->BytePerLine(hDIB);
//考察人脸区域
for(int i=faceLocation.top; iPixelOffset(i, j, wBytesPerLine);
//白色点
if(*(lpData + lOffset) == 255)
//递归统计象素并修改象素值
this->RecursiveCal(lpData,i,j,wBytesPerLine,pixelnum,++num);
}
//初始化眼睛的坐标
eye1.x =0;
eye1.y =0;
eye2.x =0;
eye2.y =0;
//初始化象素点个数
int eye1count=0;
int eye2count =0;
for (i=faceLocation.top; iPixelOffset(i, j, wBytesPerLine);
//如果象素点的数值为1
if(*(lpData + lOffset) == 1)
{
//眼睛1的横坐标和纵坐标加上当前点的坐标值
eye1.x +=j;
eye1.y +=i;
eye1count++;
//把当前点改成白色
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 255;
}
//如果当前象素的数值为2
else if(*(lpData + lOffset) == 2)
{
//眼睛2的横坐标和纵坐标加上当前点的坐标值
eye2.x +=j;
eye2.y +=i;
//象素点个数加一
eye2count++;
//把当前点设置为白色
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 255;
}
}
//计算眼睛的中心点坐标
eye1.x /=eye1count;
eye1.y /=eye1count;
eye2.x /=eye2count;
eye2.y /=eye2count;
//把中心点设置为绿色
lOffset = this->PixelOffset(eye1.y, eye1.x ,wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
lOffset = this->PixelOffset(eye2.y, eye2.x ,wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
GlobalUnlock(hDIB);
}
void DIB::EllipseFace(HANDLE hDIB, CPoint mouth, CPoint eye1, CPoint eye2)
{
LPBYTE lpData;
LPBITMAPINFOHEADER lpbi;
int width;
int height;
WORD wBytesPerLine;
long lOffset;
//得到图象的基本信息
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
height = lpbi->biHeight;
width = lpbi->biWidth;
lpData = this->FindDIBBits(hDIB);
wBytesPerLine = this->BytePerLine(hDIB);
//用dda算法画三角形
this->DdaLine(mouth,eye1,lpData,wBytesPerLine);
this->DdaLine(mouth,eye2,lpData,wBytesPerLine);
this->DdaLine(eye1,eye2,lpData,wBytesPerLine);
//椭圆的中心点和两个焦点坐标
int ellipsecenter_x;
int ellipsecenter_y;
int ellipseFocusTop_x;
int ellipseFocusTop_y;
int ellipseFocusBottom_x;
int ellipseFocusBottom_y;
//根据眼睛和嘴巴的坐标计算椭圆的中心点坐标
ellipsecenter_x = (eye1.x + eye2.x + mouth.x )/3;
ellipsecenter_y = (eye1.y + eye2.y)/2 -abs(eye2.x - eye1.x)/2;
//上面的焦点
ellipseFocusTop_x = ellipsecenter_x;
ellipseFocusBottom_x = ellipsecenter_x;
//下面的焦点
ellipseFocusTop_y = ellipsecenter_y + (eye1.y +eye2.y)/2 -mouth.y;
ellipseFocusBottom_y = ellipsecenter_y - ((eye1.y +eye2.y)/2 -mouth.y)+2;
//长轴
int a = (eye1.x-eye2.x)*2-2;
for (int i=0; i2*a-2)
{
//把点设置为绿色
lOffset = this->PixelOffset(i, j, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
}
}
GlobalUnlock(hDIB);
}
void DIB::DdaLine(CPoint from, CPoint end, LPBYTE lpData, WORD wBytesPerLine)
{
//x,y的增量
float delta_x;
float delta_y;
//x,y的坐标
float x;
float y;
//x,y上的差值
int dx;
int dy;
//总的步长
int steps;
int k;
//得到x,y的差值
dx = end.x - from.x;
dy = end.y - from.y;
//判断x,y上的差值大小,确定步长
if(abs(dx) > abs(dy))
{
steps = abs(dx);
}
else
{
steps = abs(dy);
}
//得到每次增量的大小
delta_x = (float)dx / (float)steps;
delta_y = (float)dy / (float)steps;
//设定x,y的起点
x = (float)from.x;
y = (float)from.y;
//设定初始点的颜色为绿色
long lOffset = this->PixelOffset(y, x, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
//根据计算得到的步长,把直线上的点填充成绿色
for (k=1;k<=steps; k++)
{
//x,y分别加上各自的增量
x+=delta_x;
y+=delta_y;
//设置点的颜色
lOffset = this->PixelOffset(y, x, wBytesPerLine);
*(lpData + lOffset++) = 0;
*(lpData + lOffset++) = 255;
*(lpData + lOffset++) = 0;
}
}