/*********************************************************************
对灰度图进行位二值化,输入图像像素部分的宽度和高度以及存储灰度像素值
得一维数组,对灰度值进行直方图统计,通过OSTU大律法公式,确定自动灰度
图的阈值,进而进行二值化处理,存储
*********************************************************************/
#include "StdAfx.h"
#include<iostream>
#include<Windows.h>
using namespace std;
void glay(DWORD w,DWORD h, unsigned char * newImageData)
{
/***************对灰度图的像素值进行统计************************/
int graycolor[256]; //定义灰度等级存储数组,用来存储每个颜色等级的像素数量
int smooth_graycolor[51]; //平滑后灰度信息存储数组
unsigned char *Binarization=new unsigned char[w*h]; //复制灰度图像的像素值
for (int n=0;n<256;n++) graycolor[n]=0;
int k; //用来临时存储每个像素点的灰度值
for(int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
*(Binarization+i*w+j)=*(newImageData+i*w+j);
k=*(Binarization+i*w+j);
//cout<<k;
graycolor[k]++;
}
}
//for(int a=0;a<256;a++)
//{cout<<graycolor[a]<<"\t";} //输出每个颜色等级的灰度像素数量
/***************对灰度图的像素值进行直方图平滑选择临近五个坐标***********************
int sumgray=0; //相邻五个灰度等级的值
int ave_sumgray=0;
for(int i=1;i<52;i++)
{
for(int j=(i-1)*5;j<i*5;j++)
{
if(i=51)
{
for(int k=250;k<256;k++){sumgray=graycolor[k]+sumgray;}
}
else
{
sumgray=graycolor[j]+sumgray;
}
}
cout<<sumgray<<endl;
ave_sumgray=(int)sumgray/5;
smooth_graycolor[i-1]=ave_sumgray;
}
for(int b=0;b<51;b++)
{cout<<smooth_graycolor[b]<<"\t";} //输出每个颜色等级的灰度像素数量
*/
/*************************OSTU大律法公式参看http://blog.csdn.net/zyzhangyue/article/details/45841255*********************************/
//计算每个直方图占总数的概率
double Prob_gray[256]; //存储每个直方图占总数的概率
for(int a=0;a<256;a++)
{
Prob_gray[a]=(double)graycolor[a]/(w*h);
//cout<<a<<":"<<Prob_gray[a]<<endl; //输出每个灰度级的像素数量占用总像素数量的概率
}
//定义两个数组存储计算的概率,假设t为阙值,计算每个t的前后像素的概率
double Pa=0,Pa1=0,Pb=0,Pb1=0; //存储概率
double Wa[256],Wb[256],Wo[256],Wz[256],Wz1[256];//存储概率的数组,Wa为A区域的平均灰度值,Wb为B区域的平均灰度值,
//Wo为图像全局的灰度平均值,Wz,Wz1 A、B两个区域的类间方差
for (int t=0;t<256;t++)
{
Wa[t]=0;
Wb[t]=0;
Wo[t]=0;
Wz[t]=0;
Wz1[t]=0;
}
for (int t=0;t<256;t++)
{
Pa=0;Pb=0;Pa1=0;Pb1=0;
for(int p=0;p<t+1;p++)
{
Pa=Prob_gray[p]*p+Pa;
Pa1=Prob_gray[p]+Pa1;
}
Wa[t]=Pa/Pa1; //每个t的前几项的概率方差
//cout<<Wa[t]<<endl;
for(int q=t+1;q<256;q++)
{
Pb=Prob_gray[q]*q+Pb;
Pb1=Prob_gray[q]+Pb1;
}
Wb[t]=Pb/Pb1; //每个t的后几项的概率方差
Wo[t]=Wa[t]*Pa1+Wb[t]*Pb1;
Wz[t]=Pa1*(Wa[t]-Wo[t])*(Wa[t]-Wo[t])+Pb1*(Wb[t]-Wo[t])*(Wb[t]-Wo[t]);
//cout<<Wz[t]<<endl; //输出每个灰度级作为分割线后前后的方差
}
double max=0; //存储最大的方差值
int Threshold=0; //存储作为阈值的灰度级
for (int t=0;t<256;t++)
{
Wz1[t]=Wz[t];
if(Wz1[t]>max) max=Wz1[t];
}
cout<<"max"<<max<<endl; //输出的为最大的方差
for (int t=0;t<256;t++)
{
if(Wz[t]>=max)
Threshold=t;
}
/*************************二值化灰度图像*********************************/
int m=0;
for(int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
m=*(Binarization+i*w+j);
if(m>=Threshold) *(Binarization+i*w+j)=255;
else *(Binarization+i*w+j)=0;
}
}
/*************************窗口中绘制图像显示*********************************/
HWND wnd; //窗口句柄
HDC dc; //绘图设备环境句柄
unsigned char *p2; //临时像素指针
int r2,pix2;
int x2=300,y2=300;
wnd=GetForegroundWindow(); //获取窗口句柄
dc=GetDC(wnd); //获取绘图设备
p2=Binarization;
for(int j=0;j<h;j++)
{
for(int i=0;i<w;i++)
{
r2=*p2++;
pix2=RGB(r2,r2,r2);//指定要用来绘制该点的颜色
SetPixel(dc,x2+i,y2+h-j,pix2);//在屏幕中绘制此像素
}
}
/**********************构造新图像的文件信息头*********************/
int nWidthBytes=(w*3+3)/4*4; //计算每行的字节数
BITMAPFILEHEADER newheader={0};
newheader.bfType=MAKEWORD('B','M');
newheader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256;
newheader.bfSize=newheader.bfOffBits+h*nWidthBytes/3;//头文件加位图实际大小
/**********************构造灰度图的位图信息头*********************/
BITMAPINFOHEADER targetinfoheader={0};
targetinfoheader.biBitCount=8;
targetinfoheader.biSize=sizeof(BITMAPINFOHEADER);
targetinfoheader.biHeight=h;
targetinfoheader.biWidth=w;
targetinfoheader.biPlanes=1;
targetinfoheader.biCompression=BI_RGB;
targetinfoheader.biSizeImage=nWidthBytes*h/3;
targetinfoheader.biXPelsPerMeter=0;
targetinfoheader.biYPelsPerMeter=0;
targetinfoheader.biClrImportant=0;
targetinfoheader.biClrUsed=0;
/*****************构造灰度图的调色板信息需要256个*****************/
RGBQUAD rgbquad[256];
int i;
for(i=0;i<256;i++)
{
rgbquad[i].rgbBlue=i;
rgbquad[i].rgbGreen=i;
rgbquad[i].rgbRed=i;
rgbquad[i].rgbReserved=0;
}
/*****************将灰度图像的信息写入到文件中*****************/
FILE *fpw1; //定义保存文件指针
unsigned char *p,*p3; //像素指针
char fileName3[300]; //定义打开保存图像名字
cout<<"请输入要保存文件的名字:";
cin>>fileName3;
if((fpw1=fopen(fileName3,"wb"))==NULL)
{
cout<<"文件未找到!";
exit(0);
}
fwrite(&newheader,sizeof(newheader),1,fpw1); //写入文件头
fwrite(&targetinfoheader,sizeof(BITMAPINFOHEADER),1,fpw1);//写入位图信息头
fwrite(&rgbquad,sizeof(RGBQUAD),256,fpw1); //写入调色板信息
p3= Binarization; //得到存储灰度像素信息的一维数组地址
for (int i=0;i<w*h;i++)
{
fwrite(p3++,1,1,fpw1);
}
fclose(fpw1);
}
c++对8位灰度图进行二值化处理
最新推荐文章于 2022-10-08 17:29:19 发布