#include "stdafx.h"
#include <math.h>
class CBmp : public CObject
{
public:
CBmp();
CBmp(const CBmp& a);
virtual ~CBmp();
public:
LPBITMAPINFO bmi;
LPBYTE pBits;
public:
BOOL Read(CString FileName); //读入图像
BOOL Write(CString FileName); //存储图像
int GetPaletteSize() const; //调色板大小
int GetBytesPerLine() const; //图像每行实际占字节数
int GetWidth() const; //宽度
int GetHeight() const; //高度
BOOL IsValid() const; //图像是否有效
BOOL IsGrayScaleImage() const; //判断是灰度图像
BOOL ToGrayScaleImage(); //转换为256级灰度图像
BOOL ProduceHistogramData(int PixelNum[]) const; //产生原图直方图
void Equalize(); //直方图均衡化处理图像
void NegtivePhaseChange(); //反色变换
void Binarize(int threshold); //二值化
void SegmentalLinearTransformate(int x1,int y1,int x2,int y2);//分段线性变换
void LogAlter(int c); //灰度对数变换
void PowerAlter(float c, float r, float b); //灰度幂次变换
void ExpAlter(float b, float c, float a); //灰度指数变换
public:
CBmp& operator=(const CBmp& bmp); //重载运算符
private:
BOOL TwoToGray(); //黑白图像转为256级灰度图像
BOOL FourToGray(); //16色彩色图像转为256级灰度图像
BOOL EightToGray(); //256色彩色图像转为256级灰度图像
BOOL TrueColorToGray(); //真彩色图像转为256级灰度图像
}
CBmp::CBmp()
{
bmi = NULL;
pBits = NULL;
}
CBmp::CBmp(const CBmp& a)
{
int infoSize = sizeof(BITMAPINFOHEADER) + a.GetPaletteSize() * sizeof(RGBQUAD);
bmi = (LPBITMAPINFO)new BYTE[infoSize];
memcpy( (LPVOID)bmi, (LPVOID)a.bmi,infoSize);
pBits = new BYTE[bmi->bmiHeader.biSizeImage];
memcpy( (LPVOID)pBits,(LPVOID)a.pBits,bmi->bmiHeader.biSizeImage);
}
CBmp::~CBmp()
{
if(bmi)
{
delete bmi;
bmi = NULL;
}
if(pBits)
{
delete pBits;
pBits = NULL;
}
}
CBmp& CBmp::operator=(const CBmp& a)
{
if(this == &a) return *this;
if(bmi)
delete bmi;
if(pBits)
delete pBits;
int infoSize = sizeof(BITMAPINFOHEADER) + a.GetPaletteSize() * sizeof(RGBQUAD);
bmi = (LPBITMAPINFO)new BYTE[infoSize];
memcpy( (LPVOID)bmi, (LPVOID)a.bmi,infoSize);
pBits = new BYTE[bmi->bmiHeader.biSizeImage];
memcpy( (LPVOID)pBits,(LPVOID)a.pBits,bmi->bmiHeader.biSizeImage);
return *this;
}
BOOL CBmp::Read(CString FileName)
{
CFile file;
BITMAPFILEHEADER bmfh;
//打开文件
if(!file.Open(FileName,CFile::modeRead))
{
AfxMessageBox("File cannot open!");
return FALSE;
}
//读文件信息头
file.Read( (LPVOID)&bmfh, sizeof(bmfh) );
if(bmfh.bfType != 0x4d42)
{
AfxMessageBox("This is not a bmp file!");
return FALSE;
}
if(bmi)
{
delete bmi;
bmi = NULL;
}
if(pBits)
{
delete pBits;
pBits = NULL;
}
//读位图信息头和调色板
int infoSize = bmfh.bfOffBits - sizeof(bmfh);
bmi = (LPBITMAPINFO)new BYTE[infoSize];
file.Read( (LPVOID)bmi, infoSize);
if(bmi->bmiHeader.biBitCount!=1 && bmi->bmiHeader.biBitCount!=4
&& bmi->bmiHeader.biBitCount!=8 && bmi->bmiHeader.biBitCount!=24)
{
AfxMessageBox("The number of colors is not valid!");
return FALSE;
}
//读图像数据
pBits = new BYTE[bmi->bmiHeader.biSizeImage];
file.Read( (LPVOID)pBits, bmi->bmiHeader.biSizeImage);
return TRUE;
}
BOOL CBmp::Write(CString FileName)
{
CFile file;
BITMAPFILEHEADER bmfh;
if(! (bmi && pBits))
{
AfxMessageBox("Data is not valid!");
return FALSE;
}
//创建文件
if(!file.Open(FileName,CFile::modeCreate | CFile::modeWrite))
{
AfxMessageBox("File creating fails!");
return FALSE;
}
//填写文件信息头
bmfh.bfType = 0x4d42;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
int nInfoSize = sizeof(BITMAPINFOHEADER) + GetPaletteSize() * sizeof(RGBQUAD);
bmfh.bfOffBits = sizeof(bmfh) + nInfoSize;
bmfh.bfSize = bmfh.bfOffBits + bmi->bmiHeader.biSizeImage;
//写文件
file.Write( (LPVOID)&bmfh, sizeof(bmfh));
file.Write( (LPVOID)bmi, nInfoSize);
file.Write( (LPVOID)pBits, bmi->bmiHeader.biSizeImage);
return TRUE;
}
int CBmp::GetPaletteSize() const
{
switch(bmi->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
{
return bmi->bmiHeader.biSizeImage / bmi->bmiHeader.biHeight;
}
int CBmp::GetWidth() const
{
if(bmi)
return bmi->bmiHeader.biWidth;
else
return 0;
}
int CBmp::GetHeight() const
{
if(bmi)
return bmi->bmiHeader.biHeight;
else
return 0;
}
BOOL CBmp::IsValid() const
{
return bmi && pBits;
}
BOOL CBmp::IsGrayScaleImage() const
{
if(bmi->bmiHeader.biBitCount != 8)
return FALSE;
else
{
for(int i = 0; i<256; ++i)
if( !(bmi->bmiColors[i].rgbBlue == bmi->bmiColors[i].rgbGreen && bmi->bmiColors[i].rgbGreen == bmi->bmiColors[i].rgbRed) )
return FALSE;
}
return TRUE;
}
BOOL CBmp::ToGrayScaleImage()
{
switch(GetPaletteSize())
{
case 2: return TwoToGray();
case 16: return FourToGray();
case 256: return EightToGray();
case 0: return TrueColorToGray();
default: return FALSE;
}
}
BOOL CBmp::TwoToGray()
{
LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];//申请新信息头空间
memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头
newbmi->bmiHeader.biBitCount = 8;//修改位图信息头信息
int newBytesPerLine = (int)( (bmi->bmiHeader.biWidth * 8 + 31) / 32 ) * 4;//每行实际字节数
newbmi->bmiHeader.biSizeImage = newBytesPerLine * newbmi->bmiHeader.biHeight;//修改位图信息头信息
//生成新调色板
LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);
for (int i = 0; i < 256; ++i)
{
pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;
pRGBQUQD[i].rgbReserved = 0;
}
//新图像数据
LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];
int originalBytePosition, newBytePosition;
for (i = 0; i < newbmi->bmiHeader.biHeight; ++i)
{
WORD test = 0x0080;
for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j)
{
originalBytePosition = i * GetBytesPerLine() + j / 8;//原图中该像素所在的字节号
newBytePosition = i * newBytesPerLine + j;//新图中该像素所在的字节号
if(pBits[originalBytePosition] & (test>>(j%8)) )//该像素在原图中对应的数据位
newpBits[newBytePosition] = 0xff;
else
newpBits[newBytePosition] = 0;
}
while(newBytePosition%4 != 3)//处理填充字节
newpBits[++newBytePosition] = 0;
}
delete bmi;
bmi = newbmi;
delete pBits;
pBits = newpBits;
return TRUE;
}
BOOL CBmp::FourToGray()
{
LPBITMAPINFO newbmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];//申请新信息头空间
memcpy( (LPVOID)newbmi, (LPVOID)bmi, sizeof(BITMAPINFOHEADER));//拷贝位图信息头
newbmi->bmiHeader.biBitCount = 8;//修改位图信息头信息
int newBytesPerLine = (int)( (bmi->bmiHeader.biWidth * 8 + 31) / 32 ) * 4;//每行实际字节数
newbmi->bmiHeader.biSizeImage = newBytesPerLine * newbmi->bmiHeader.biHeight;//修改位图信息头信息
//生成新调色板
LPRGBQUAD pRGBQUQD = &(newbmi->bmiColors[0]);
for (int i = 0; i < 256; ++i)
{
pRGBQUQD[i].rgbRed = pRGBQUQD[i].rgbGreen = pRGBQUQD[i].rgbBlue = i;
pRGBQUQD[i].rgbReserved = 0;
}
LPBYTE newpBits = new BYTE[newbmi->bmiHeader.biSizeImage];
int originalBytePosition, newBytePosition,index;
pRGBQUQD = &(bmi->bmiColors[0]);
for (i = 0; i < newbmi->bmiHeader.biHeight; ++i)
{
for (int j = 0; j < newbmi->bmiHeader.biWidth; ++j)
{
originalBytePosition = i * GetBytesPerLine() + j / 2;//原图中该像素所在的字节号
newBytePosition = i * newBytesPerLine + j;//新图中该像素所在的字节号
if(j%2 == 0)//提取前半字节
{
index = pBits[originalBytePosition] / 16;
newpBits[newBytePosition] = (BYTE)( (float)pRGBQUQD[index].rgbRed * 0.299
+ (float)pRGBQUQD[index].rgbGreen * 0.587