vc++ bmp图像二值化

在网上看到2个例子:

方法一:http://blog.csdn.net/mydreamremindme/article/details/9950453      我生成的不是白色底,是蓝色底不知道为何

方法二:http://download.csdn.net/download/s200692269/2663986


测试Demo

1、新建基于mfc的dialog程序,添加2个按键,分别对应上面那俩方法代码

2、.h的代码

private:
	bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, 
		int biBitCount, RGBQUAD *pColorTable);
	bool readBmp(char *bmpName);
public:
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();

3、.cpp代码

// bmp2zhiDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "bmp2zhi.h"
#include "bmp2zhiDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// Cbmp2zhiDlg 对话框




Cbmp2zhiDlg::Cbmp2zhiDlg(CWnd* pParent /*=NULL*/)
	: CDialog(Cbmp2zhiDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void Cbmp2zhiDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(Cbmp2zhiDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON1, &Cbmp2zhiDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &Cbmp2zhiDlg::OnBnClickedButton2)
END_MESSAGE_MAP()


// Cbmp2zhiDlg 消息处理程序

BOOL Cbmp2zhiDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void Cbmp2zhiDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void Cbmp2zhiDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR Cbmp2zhiDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void Cbmp2zhiDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	int threshold=100;  
	FILE* stream=fopen("D:\\1.bmp","rb");  
	if(stream==NULL)  
	{  
		//cout<<"文件不存在"<<endl;
		AfxMessageBox("文件不存在");
		return;  
	}  

	int sizeFileHeader=sizeof(BITMAPFILEHEADER);  
	int sizeInfoHeader=sizeof(BITMAPINFOHEADER);  

	BITMAPFILEHEADER* bitmapFileHeader=new BITMAPFILEHEADER[sizeFileHeader+1];  

	BITMAPINFOHEADER* bitmapInfoHeader=new BITMAPINFOHEADER[sizeInfoHeader+1];  

	memset(bitmapFileHeader,0,sizeFileHeader+1);  
	memset(bitmapInfoHeader,0,sizeInfoHeader+1);  
	fread(bitmapFileHeader,sizeof(char),sizeFileHeader,stream);  
	fseek(stream,sizeFileHeader,0);  
	fread(bitmapInfoHeader,sizeof(char),sizeInfoHeader,stream);  
	fseek(stream,sizeInfoHeader+sizeFileHeader,0);  
	RGBQUAD* pRgbQuards=new RGBQUAD[256];  
	for (int k=0;k<256;k++)  
	{  
		fread(&pRgbQuards[k],sizeof(RGBQUAD),1,stream);  
	}  

	int count=(((bitmapInfoHeader->biWidth)*8+31)/32)*4-bitmapInfoHeader->biWidth*(bitmapInfoHeader->biBitCount/8);  
	BYTE* tempData=new BYTE[count+1];  
	memset(tempData,0,count+1);  
	fseek(stream,sizeFileHeader+sizeInfoHeader+256*sizeof(RGBQUAD),0);  
	BYTE** data=new BYTE*[bitmapInfoHeader->biHeight];  
	for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
	{  
		data[i]=new BYTE[bitmapInfoHeader->biWidth];  
		for (int j=0;j<bitmapInfoHeader->biWidth;j++)  
		{  
			fread(&data[i][j],sizeof(char),1,stream);  
			if(data[i][j]>threshold)  
				data[i][j]=255;  
			else  
				data[i][j]=0;  
		}  
		for (int n=0;n<count;n++)  
		{  
			fread(&tempData[n],sizeof(char),1,stream);  
		}  
	}  

	fclose(stream);  



	//写入。。  
	FILE* fileWrite=fopen("D:\\09.bmp","a+");  
	fwrite(bitmapFileHeader,sizeof(char),sizeof(BITMAPFILEHEADER),fileWrite);  
	fwrite(bitmapInfoHeader,sizeof(char),sizeof(BITMAPINFOHEADER),fileWrite);  
	fwrite(pRgbQuards,sizeof(RGBQUAD),256,fileWrite);  

	for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
	{  
		for(int j=0;j<bitmapInfoHeader->biWidth;j++)  
		{  
			fwrite(&data[i][j],sizeof(BYTE),1,fileWrite);  
		}  
		for(int m=0;m<count;m++)  
			fwrite(&tempData[m],sizeof(char),1,fileWrite);  
	}  
	fclose(fileWrite);  

	AfxMessageBox("success");
}


//几个全局变量,存放读入图像的位图数据、宽、高、颜色表及每像素所占位数(比特) 
//此处定义全局变量主要为了后面的图像数据访问及图像存储作准备
unsigned char *pBmpBuf;//读入图像数据的指针
int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD *pColorTable;//颜色表指针
int biBitCount;//图像类型

void Cbmp2zhiDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	//读入指定BMP文件进内存
	char readPath[]="D:\\leangray.bmp";
	readBmp(readPath);

	//输出图像的信息
	//printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpHeight,biBitCount);


	//循环变量,图像的坐标
	int i,j;
	//每行字节数
	int lineByte=(bmpWidth*biBitCount/8+3)/4*4;

	//循环变量,针对彩色图像,遍历每像素的三个分量
	int k;

	//二值化处理
	if(biBitCount==8){//对于灰度图像
		for(i=0;i<bmpHeight;i++){
			for(j=0;j<bmpWidth;j++){

				int p=*(pBmpBuf+i*lineByte+j);
				if(p<=160)
					*(pBmpBuf+i*lineByte+j)=0;
				else
					*(pBmpBuf+i*lineByte+j)=255;				
			}
		}
	}
	else if(biBitCount==24){//彩色图像
		for(i=0;i<bmpHeight/2;i++){
			for(j=0;j<bmpWidth/2;j++){
				for(k=0;k<3;k++)//每像素RGB三个分量分别置0才变成黑色
					*(pBmpBuf+i*lineByte+j*3+k)=0;
			}
		}
	}

	//将图像数据存盘
	char writePath[]="D:\\lean_threshold_160.bmp";
	saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);

	//清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间
	delete []pBmpBuf;
	if(biBitCount==8)
		delete []pColorTable;

}


/***********************************************************************
* 函数名称:
* readBmp()
*
*函数参数:
*  char *bmpName -文件名字及路径
*
*返回值:
*   0为失败,1为成功
*
*说明:给定一个图像文件名及其路径,读图像的位图数据、宽、高、颜色表及每像素
*      位数等数据进内存,存放在相应的全局变量中
***********************************************************************/
bool Cbmp2zhiDlg::readBmp(char *bmpName)
{
	//二进制读方式打开指定的图像文件
	FILE *fp=fopen(bmpName,"rb");
	if(fp==0) return 0;


	//跳过位图文件头结构BITMAPFILEHEADER
	fseek(fp, sizeof(BITMAPFILEHEADER),0);


	//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
	BITMAPINFOHEADER head;  
	fread(&head, sizeof(BITMAPINFOHEADER), 1,fp); 

	//获取图像宽、高、每像素所占位数等信息
	bmpWidth = head.biWidth;
	bmpHeight = head.biHeight;
	biBitCount = head.biBitCount;

	//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
	int lineByte=(bmpWidth * biBitCount/8+3)/4*4;

	//灰度图像有颜色表,且颜色表表项为256
	if(biBitCount==8){
		//申请颜色表所需要的空间,读颜色表进内存
		pColorTable=new RGBQUAD[256];
		fread(pColorTable,sizeof(RGBQUAD),256,fp);
	}

	//申请位图数据所需要的空间,读位图数据进内存
	pBmpBuf=new unsigned char[lineByte * bmpHeight];
	fread(pBmpBuf,1,lineByte * bmpHeight,fp);

	//关闭文件
	fclose(fp);

	return 1;
}

/***********************************************************************
* 函数名称:
* saveBmp()
*
*函数参数:
*  char *bmpName -文件名字及路径
*  unsigned char *imgBuf  -待存盘的位图数据
*  int width   -像素为单位待存盘位图的宽
*  int  height  -像素为单位待存盘位图高
*  int biBitCount   -每像素所占位数
*  RGBQUAD *pColorTable  -颜色表指针

*返回值:
*   0为失败,1为成功
*
*说明:给定一个图像位图数据、宽、高、颜色表指针及每像素所占的位数等信息,
*      将其写到指定文件中
***********************************************************************/
bool Cbmp2zhiDlg::saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, 
			 int biBitCount, RGBQUAD *pColorTable)
{
	//如果位图数据指针为0,则没有数据传入,函数返回
	if(!imgBuf)
		return 0;

	//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
	int colorTablesize=0;
	if(biBitCount==8)
		colorTablesize=1024;

	//待存储图像数据每行字节数为4的倍数
	int lineByte=(width * biBitCount/8+3)/4*4;

	//以二进制写的方式打开文件
	FILE *fp=fopen(bmpName,"wb");
	if(fp==0) return 0;

	//申请位图文件头结构变量,填写文件头信息
	BITMAPFILEHEADER fileHead;
	fileHead.bfType = 0x4D42;//bmp类型

	//bfSize是图像文件4个组成部分之和
	fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
		+ colorTablesize + lineByte*height;
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;

	//bfOffBits是图像文件前三个部分所需空间之和
	fileHead.bfOffBits=54+colorTablesize;

	//写文件头进文件
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);

	//申请位图信息头结构变量,填写信息头信息
	BITMAPINFOHEADER head; 
	head.biBitCount=biBitCount;
	head.biClrImportant=0;
	head.biClrUsed=0;
	head.biCompression=0;
	head.biHeight=height;
	head.biPlanes=1;
	head.biSize=40;
	head.biSizeImage=lineByte*height;
	head.biWidth=width;
	head.biXPelsPerMeter=0;
	head.biYPelsPerMeter=0;
	//写位图信息头进内存
	fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);

	//如果灰度图像,有颜色表,写入文件 
	if(biBitCount==8)
		fwrite(pColorTable, sizeof(RGBQUAD),256, fp);

	//写位图数据进文件
	fwrite(imgBuf, height*lineByte, 1, fp);

	//关闭文件
	fclose(fp);

	return 1;
}


原图和效果图分别如下:




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值