蓝文青近照:转化为灰度图

来源:百度文库 编辑:九乡新闻网 时间:2024/07/07 12:12:50

//////////////////////////////////////////////////////////////

class CBmp
{
public:
    PBITMAPINFO  pBmi;    //位图信息头+调色板指针
    PBYTE   pBits;    //图像数据指针

public:
CBmp();
    //CBMp(const CBmp &bmpObj);
CBmp& operator=( const CBmp &bmpObj );
virtual ~CBmp();

public:
BOOL Read( const CString &Filename );        //读入一幅bmp图像
BOOL Write( const CString &Filename );        //保存一幅bmp图像

int  GetWidth( ) const;            //获得图像的宽度(像素)
int  GetHeight( ) const;            //获得图像的高度(像素)
int  GetPaletteSize( ) const;          //获得调色板长度
int  GetBytesPerLine( ) const;          //获得存储每行的字节数
BOOL IsValid( ) const;            //判断图像是否存在该类对象中
BOOL IsGrayScaleImage( ) const;          //判断是否灰度图

BOOL ToGrayScaleImage( );           //转化为灰度图

void Binarize( int threshold );          //对图像进行二值化处理

private:
BOOL ToGrayScaleImage_2Color( );          //单色图像转化为灰度图
BOOL ToGrayScaleImage_16Color( );         //4位位图转化为灰度图
BOOL ToGrayScaleImage_256Color( );         //8位位图转化为灰度图
BOOL ToGrayScaleImage_TrueColor( );         //真彩色位图转化为灰度图
};
////////////////////////////////////////////////////////////////
CBmp::CBmp()
{
pBmi = NULL;
pBits = NULL;
}
/*////////////////////////////////////////////////////////////////
CBmp::CBMp(const CBmp &bmpObj)
{
int nInfoSize = sizeof(BITMAPINFOHEADER) + bmpObj.GetPaletteSize() * sizeof(RGBQUAD);
pBmi = (PBITMAPINFO)new BYTE[nInfoSize];
memcpy( (PVOID)pBmi, (PVOID)bmpObj.pBmi,nInfoSize);

int nImageSize = pBmi->bmiHeader.biSizeImage;
pBits = new BYTE[nImageSize];
memcpy((PVOID)pBits,(PVOID)bmpObj.pBits,nImageSize);
}
*////////////////////////////////////////////////////////////////////

CBmp& CBmp::operator=( const CBmp &bmpObj )
{
if ( this == &bmpObj )     //等号两边的对象若是同一个,则不必再做后续操作
  return *this;

//销毁原数据
if ( pBmi )  delete pBmi;
if ( pBits ) delete pBits;

//生成新的位图信息头+调色板
int nInfoSize = sizeof( BITMAPINFO ) + bmpObj.GetPaletteSize( ) * sizeof( RGBQUAD );
pBmi = (PBITMAPINFO)new BYTE[ nInfoSize ];
memcpy( (PVOID)pBmi, (PVOID)bmpObj.pBmi, nInfoSize );

//生成新的位图数据
int nImageSize = pBmi->bmiHeader.biSizeImage;
pBits = new BYTE[ nImageSize ];
memcpy( (PVOID)pBits, (PVOID)bmpObj.pBits, nImageSize );

return *this;
}
////////////////////////////////////////////////////////////////////
CBmp::~CBmp()
{
if ( pBmi )
{
  delete pBmi;
  pBmi = NULL;
}
if ( pBits )
{
  delete pBits;
  pBits = NULL;
}

}
////////////////////////////////////////////////////////////////////////////
BOOL CBmp::Read( const CString &FileName )
{
CFile file;
BITMAPFILEHEADER bmfh;

//打开文件
if ( !file.Open(FileName,CFile::modeRead) )
{
  AfxMessageBox( "文件打开错误!" );
  return FALSE;
}

//读文件信息头
file.Read( (PVOID)&bmfh, sizeof(BITMAPFILEHEADER) );
if ( bmfh.bfType != 0x4d42 )
{
  AfxMessageBox( "不是位图文件!");
  return FALSE;
}

//销毁原数据
if ( pBmi )
{
  delete pBmi;
  pBmi = NULL;
}
if ( pBits )
{
  delete pBits;
  pBits = NULL;
}

//读位图信息头和调色板
int nInfoSize = bmfh.bfOffBits - sizeof( BITMAPFILEHEADER );
pBmi = (PBITMAPINFO)new BYTE[ nInfoSize ];
file.Read( (PVOID)pBmi, nInfoSize );
if ( pBmi->bmiHeader.biBitCount!=1 && pBmi->bmiHeader.biBitCount!=4 && \
  pBmi->bmiHeader.biBitCount!=8 && pBmi->bmiHeader.biBitCount!=24 )
{
  CString s;
  s.Format( "%d", pBmi->bmiHeader.biBitCount );
  AfxMessageBox( (CString)"颜色位数为"+s+(CString)"位,不满足处理要求!" );

  delete pBmi;
  pBmi = NULL;

  return FALSE;
}

//读像素数据
int nImageSize = pBmi->bmiHeader.biSizeImage;
pBits = new BYTE[ nImageSize ];
file.Read( (PVOID)pBits, nImageSize );

file.Close( );

return TRUE;
}
//////////////////////////////////////////////////////////////////////
BOOL CBmp::Write( const CString &Filename )
{
CFile file;
BITMAPFILEHEADER bmfh;

if ( !(pBmi && pBits ) )
{
  AfxMessageBox( "数据无效!" );
  return FALSE;
}

//创建文件
if ( !file.Open(Filename,CFile::modeWrite|CFile::modeCreate) )
{
  AfxMessageBox( "创建文件错误!" );
  return FALSE;
}

//计算长度数据
int nBitsSize = pBmi->bmiHeader.biSizeImage;         //像素数据部分
int nInfoSize = sizeof(BITMAPINFOHEADER) + GetPaletteSize() * sizeof(RGBQUAD); //位图信息头+调色板
int nHeaderSize = sizeof(bmfh) + nInfoSize;          //文件信息头+位图信息头+调色板
int nFileSize = nHeaderSize + nBitsSize;          //文件信息头+位图信息头+调色板+像素数据部分

//填写文件信息头
bmfh.bfType = 0x4d42;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits = nHeaderSize;
bmfh.bfSize = nFileSize;

//文件信息头写入文件
file.Write( (PVOID)&bmfh, sizeof(bmfh) );
file.Write( (PVOID)pBmi, nInfoSize );
file.Write( (PVOID)pBits, nBitsSize );

file.Close( );
return TRUE;
}
////////////////////////////////////////////////////////////////////
//获得图像宽度(像素)
int CBmp::GetWidth( ) const
{
if ( pBmi )
  return pBmi->bmiHeader.biWidth;
else
  return 0;
}
///////////////////////////////////////////////////////////////////////
//获得图像高度(像素)
int CBmp::GetHeight( ) const
{
if ( pBmi )
  return pBmi->bmiHeader.biHeight;
else
  return 0;
}
///////////////////////////////////////////////////////////////////////////
//获得调色板长度
int CBmp::GetPaletteSize( ) const
{
if ( !pBmi )
  return -1;
switch ( pBmi->bmiHeader.biBitCount )
{
case 1:  return 2;
case 4:  return 16;
case 8:  return 256;
case 24: return 0;
default: return -1;
}
}
/////////////////////////////////////////////////////////////////////
//获得存储每行的字节数
int CBmp::GetBytesPerLine( ) const
{
if ( !pBmi )
  return -1;
return
  pBmi->bmiHeader.biSizeImage / pBmi->bmiHeader.biHeight;
}
////////////////////////////////////////////////////////////////////
//判断图像是否存在该类对象中
BOOL CBmp::IsValid( ) const
{
return ( pBmi && pBits );
}
////////////////////////////////////////////////////////////////////
//判断是否灰度图
BOOL CBmp::IsGrayScaleImage( ) const
{
if ( !pBmi || pBmi->bmiHeader.biBitCount!=8 )
  return FALSE;

LPRGBQUAD pPalette = pBmi->bmiColors;
for ( int i = 0; i < 256; i++ )
  if ( pPalette[i].rgbBlue!=pPalette[i].rgbGreen || pPalette[i].rgbGreen!=pPalette[i].rgbRed )
   return FALSE;

return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//转化为灰度图
BOOL CBmp::ToGrayScaleImage( )
{
switch ( pBmi->bmiHeader.biBitCount )
{
case 1:  return ToGrayScaleImage_2Color( );
case 4:  return ToGrayScaleImage_16Color( );
case 8:  return ToGrayScaleImage_256Color( );
case 24: return ToGrayScaleImage_TrueColor( );
default: return FALSE;
}
}
//////////////////////////////////////////////////////////////////////
//单色位图转为灰度图
BOOL CBmp::ToGrayScaleImage_2Color( )
{
//计算几组数据
int nBytesPerLine1 = GetBytesPerLine( );        //原 图像每行字节数
int nBytesPerLine2 = ( (GetWidth()+3)/4 ) * 4;       //新 图像每行字节数
int nImageSize2 = nBytesPerLine2 * GetHeight( );      //新 像素数据长度
int nInfoSize2 = sizeof( BITMAPINFOHEADER ) + 256 * sizeof( RGBQUAD ); //新 位图信息头+调色板 长度

//定义新图像结构
PBITMAPINFO pBmi2 = (PBITMAPINFO)new BYTE[ nInfoSize2 ];
PBYTE pBits2 = new BYTE[ nImageSize2 ];

//为新位图信息头赋值
memcpy( (PVOID)&(pBmi2->bmiHeader), (PVOID)&(pBmi->bmiHeader), sizeof(BITMAPINFOHEADER) );
pBmi2->bmiHeader.biBitCount = 8;
pBmi2->bmiHeader.biSizeImage = nImageSize2;

//初始化新调色板
LPRGBQUAD pRGB2 = pBmi2->bmiColors;
for ( int i = 0; i < 256; i++ )
  pRGB2[i].rgbRed = pRGB2[i].rgbGreen = pRGB2[i].rgbBlue = i;

//填写新图像的各像素
int nLineStart1;             //原 图像每行的起始位置
int nLineStart2;             //新 图像每行的起始位置
for ( int h = 0; h < GetHeight(); h++ )
{
  nLineStart1 = nBytesPerLine1 * h;
  nLineStart2 = nBytesPerLine2 * h;
  BYTE tag;
  for ( int w = 0; w < GetWidth(); w++ )
  {
   tag = BYTE( 0x80 ) >> ( w%8 );
   if ( pBits[nLineStart1+w/8] & tag )
    pBits2[ nLineStart2+w ] = 255;
   else
    pBits2[ nLineStart2+w ] = 0;
  }
}

//删除原图像信息并赋新值
delete pBmi;
pBmi = pBmi2;
delete pBits;
pBits = pBits2;

return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//4位位图转为灰度图
BOOL CBmp::ToGrayScaleImage_16Color( )
{
//计算几组数据
int nBytesPerLine1 = GetBytesPerLine( );        //原 图像每行字节数
int nBytesPerLine2 = ( (GetWidth()+3)/4 ) * 4;       //新 图像每行字节数
int nImageSize2 = nBytesPerLine2 * GetHeight( );      //新 像素数据长度
int nInfoSize2 = sizeof( BITMAPINFOHEADER ) + 256 * sizeof( RGBQUAD ); //新 位图信息头+调色板 长度

//定义新图像结构
PBITMAPINFO pBmi2 = (PBITMAPINFO)new BYTE[ nInfoSize2 ];
PBYTE pBits2 = new BYTE[ nImageSize2 ];

//为新位图信息头赋值
memcpy( (PVOID)&(pBmi2->bmiHeader), (PVOID)&(pBmi->bmiHeader), sizeof(BITMAPINFOHEADER) );
pBmi2->bmiHeader.biBitCount = 8;
pBmi2->bmiHeader.biSizeImage = nImageSize2;

//初始化新调色板
LPRGBQUAD pRGB2 = pBmi2->bmiColors;
for ( int i = 0; i < 256; i++ )
  pRGB2[i].rgbRed = pRGB2[i].rgbGreen = pRGB2[i].rgbBlue = i;

//填写新图像的各像素
int nLineStart1;             //原 图像每行的起始位置
int nLineStart2;             //新 图像每行的起始位置
LPRGBQUAD pRGB1 = pBmi->bmiColors;         //原 调色板指针
for ( int h = 0; h < GetHeight(); h++ )
{
  nLineStart1 = nBytesPerLine1 * h;
  nLineStart2 = nBytesPerLine2 * h;
  int nDbColors;
  int nColor;
  for ( int w = 0; w < GetWidth(); w++ )
  {
   nDbColors = pBits[ nLineStart1+w/2 ];      //包含两个像素信息
   if ( w%2==0 )            //前一像素
   {
    nColor = nDbColors / 16;
    pBits2[ nLineStart2+w ] = int( (float)pRGB1[nColor].rgbRed * 0.299 + \
            (float)pRGB1[nColor].rgbGreen * 0.587 + \
            (float)pRGB1[nColor].rgbBlue * 0.114 );
   }
   else              //后一像素
   {
    nColor = nDbColors % 16;
    pBits2[ nLineStart2+w ] = int( (float)pRGB1[nColor].rgbRed * 0.299 + \
            (float)pRGB1[nColor].rgbGreen * 0.587 + \
            (float)pRGB1[nColor].rgbBlue * 0.114 );
   }
  }
}

//删除原图像信息并赋新值
delete pBmi;
pBmi = pBmi2;
delete pBits;
pBits = pBits2;

return TRUE;
}
////////////////////////////////////////////////////////////////////////
//8位位图转为灰度图
BOOL CBmp::ToGrayScaleImage_256Color( )
{
//修改像素值
int nLineStart;
LPRGBQUAD pRGB = pBmi->bmiColors;
for ( int h = 0; h < GetHeight(); h++ )
{
  nLineStart = GetBytesPerLine( ) * h;
  int nColor;
  for ( int w = 0; w < GetWidth(); w++ )
  {
   nColor = pBits[ nLineStart+w ];
   pBits[ nLineStart+w ] = int( (float)pRGB[nColor].rgbRed * 0.299 + \
          (float)pRGB[nColor].rgbGreen * 0.587 + \
          (float)pRGB[nColor].rgbBlue * 0.114 );
  }
}

//修改调色板
for ( int i = 0; i < 256; i++ )
  pRGB[i].rgbRed = pRGB[i].rgbGreen = pRGB[i].rgbBlue = i;

return TRUE;
}

//真彩色位图转为灰度图
BOOL CBmp::ToGrayScaleImage_TrueColor( )
{
//计算几组数据
int nBytesPerLine1 = GetBytesPerLine( );        //原 图像每行字节数
int nBytesPerLine2 = ( (GetWidth()+3)/4 ) * 4;       //新 图像每行字节数
int nImageSize2 = nBytesPerLine2 * GetHeight( );      //新 像素数据长度
int nInfoSize2 = sizeof( BITMAPINFOHEADER ) + 256 * sizeof( RGBQUAD ); //新 位图信息头+调色板 长度

//定义新图像结构
PBITMAPINFO pBmi2 = (PBITMAPINFO)new BYTE[ nInfoSize2 ];
PBYTE pBits2 = new BYTE[ nImageSize2 ];

//为新位图信息头赋值
memcpy( (PVOID)&(pBmi2->bmiHeader), (PVOID)&(pBmi->bmiHeader),sizeof(BITMAPINFOHEADER) );
pBmi2->bmiHeader.biBitCount = 8;
pBmi2->bmiHeader.biSizeImage = nImageSize2;

//初始化新调色板
LPRGBQUAD pRGB = pBmi2->bmiColors;
for ( int i = 0; i < 256; i++ )
  pRGB[i].rgbRed = pRGB[i].rgbGreen = pRGB[i].rgbBlue = i;

//填写新图像的各像素
int nLineStart1;             //原 图像每行的起始位置
int nLineStart2;             //新 图像每行的起始位置
for ( int h = 0; h < GetHeight(); h++ )
{
  nLineStart1 = nBytesPerLine1 * h;
  nLineStart2 = nBytesPerLine2 * h;
  for ( int w = 0; w < GetWidth(); w++ )
   pBits2[nLineStart2+w] = int( (float)pBits[nLineStart1 + 3 * w] * 0.114 + \
           (float)pBits[nLineStart1 + 3 * w + 1] * 0.587 + \
           (float)pBits[nLineStart1 + 3 * w + 2] * 0.299 );
}

//删除原图像信息并赋新值
delete pBmi;
pBmi = pBmi2;
delete pBits;
pBits = pBits2;

return TRUE;
}

////////////////////////////////////////////////////////////////
//二值化
void CBmp::Binarize( int threshold )
{
if ( !IsGrayScaleImage() )
{
  AfxMessageBox( "不是灰度图!" );
  return;
}

int nLineStart;  //每行开始的字节号
for ( int h = 0; h < GetHeight(); h++ )
{
  nLineStart = GetBytesPerLine( ) * h;
  for ( int w = 0; w < GetWidth(); w++ )
   if ( pBits[nLineStart+w] < threshold )
    pBits[ nLineStart+w ] = 0;
   else
    pBits[ nLineStart+w ] = 255;
}