vc++ bmp图像二值化

来源:互联网 发布:jquery数组删除元素吗 编辑:程序博客网 时间:2024/06/13 06:48

在网上看到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_MAPON_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;//跳过位图文件头结构BITMAPFILEHEADERfseek(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;//灰度图像有颜色表,且颜色表表项为256if(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字节,彩色图像颜色表大小为0int 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 0