1、直方图计算
灰度图如上所示,灰度范围为0-3,则
共4*4=16个像素 灰度范围i=[0,3]
灰度0:V0=3/16
灰度1:V1=5/16
灰度2:V2=4/16
灰度3:V3=4/16
直方图为:
2、RGB直方图
与灰度图直方图同理,分别计算每个像素三个分量RGB的256个灰度值,可以绘制成3个直方图
例子:显示2.bmp的rgb直方图
void MyFrame::OnPaint()
{
CPaintDC dc(this);
FILE* fp;
if (fopen_s(&fp, "2.bmp", "rb") != 0)
{
return;
}
bmpFileHeader bfHead;
bmpInfoHeader biHead;
fread_s(&bfHead, 14, 14, 1, fp);
fread_s(&biHead, 40, 40, 1, fp);
unsigned char* p = (unsigned char*)malloc(biHead.biSizeImage * sizeof(unsigned char));
fseek(fp, bfHead.bfOffBits, SEEK_SET);
fread_s(p, biHead.biSizeImage * sizeof(unsigned char), biHead.biSizeImage * sizeof(unsigned char), 1, fp);
//rgb直方图
unsigned int* Rhists,* Ghists,* Bhists;
Rhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
Ghists = (unsigned int*)malloc(256 * sizeof(unsigned int));
Bhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
memset(Rhists, 0x0, 256 * sizeof(unsigned int));
memset(Ghists, 0x0, 256 * sizeof(unsigned int));
memset(Bhists, 0x0, 256 * sizeof(unsigned int));
unsigned long x = 0;
for (int i = 0; i < biHead.biHeight; i++)
{
for (int j = 0; j < biHead.biWidth; j++)
{
Rhists[p[x + 2]]++;
Ghists[p[x + 1]]++;
Bhists[p[x]]++;
x += 3;
}
}
//绘制R直方图坐标轴
dc.MoveTo(10, 500);
dc.LineTo(310, 500);
dc.MoveTo(10, 500);
dc.LineTo(10, 0);
//绘制R直方图
for (int j = 0; j < 256; j++)
{
dc.MoveTo(20 + j, 500);
dc.LineTo(20 + j, 500 - Rhists[j] / 100);
}
//绘制G直方图坐标轴
dc.MoveTo(320, 500);
dc.LineTo(620, 500);
dc.MoveTo(320, 500);
dc.LineTo(320, 0);
//绘制G直方图
for (int j = 0; j < 256; j++)
{
dc.MoveTo(330 + j, 500);
dc.LineTo(330 + j, 500 - Ghists[j] / 100);
}
//绘制B直方图坐标轴
dc.MoveTo(630, 500);
dc.LineTo(930, 500);
dc.MoveTo(630, 500);
dc.LineTo(630, 0);
//绘制B直方图
for (int j = 0; j < 256; j++)
{
dc.MoveTo(640 + j, 500);
dc.LineTo(640 + j, 500 - Bhists[j] / 100);
}
}
结果:
3、直方图均衡化
首先通过一个例子来人工进行直方图均衡化:
仍然是这幅图片,共0-3四个灰度级
第一步:统计每个灰度级像素点个数 V[0-3]={3,5,4,4}
第二步:统计灰度频率 V[0-3]={3/16,5/16,4/16,4/16}
第三步:计算累计密度 V[0-3]={3/16,8/16,12/16,16/16}
第四步:均衡化
V0=3/16*(灰度级个数-1)=3/16*3≈1(四舍五入)
V1=8/16*(灰度级个数-1)=8/16*3≈2(四舍五入)
V2=12/16*(灰度级个数-1)=12/16*3≈2(四舍五入)
V3=16/16*(灰度级个数-1)=16/16*3≈3(四舍五入)
第五步:则0对应灰度级1,1对应灰度级2,2对应灰度级2,3对应灰度级3
代码实现(RGB图
void hist()
{
CPaintDC dc(this);
FILE* fp1;
if (fopen_s(&fp1, "C:\\Users\\Administrator\\Desktop\\BMP1\\BMP1\\1.bmp", "rb") != 0)
{
return;
}
bmpFileHeader bfHead1;
bmpInfoHeader biHead1;
fread_s(&bfHead1, 14, 14, 1, fp1);
fread_s(&biHead1, 40, 40, 1, fp1);
uchar* p1 = (uchar*)malloc(biHead1.biSizeImage * sizeof(uchar));
fseek(fp1, bfHead1.bfOffBits, SEEK_SET);
fread_s(p1, biHead1.biSizeImage * sizeof(uchar), biHead1.biSizeImage * sizeof(uchar), 1, fp1);
//统计每个分量下的像素个数
unsigned int* Rhists, * Ghists, * Bhists;
Rhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
Ghists = (unsigned int*)malloc(256 * sizeof(unsigned int));
Bhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
memset(Rhists, 0x0, 256 * sizeof(unsigned int));
memset(Ghists, 0x0, 256 * sizeof(unsigned int));
memset(Bhists, 0x0, 256 * sizeof(unsigned int));
unsigned long x = 0;
for (int i = 0; i < biHead1.biHeight; i++)
{
for (int j = 0; j < biHead1.biWidth; j++)
{
Rhists[p1[x + 2]]++;
Ghists[p1[x + 1]]++;
Bhists[p1[x]]++;
x += 3;
}
}
//统计灰度频率
double Rhists_prob[256] = { 0 };
double Ghists_prob[256] = { 0 };
double Bhists_prob[256] = { 0 };
for (int i = 0; i < 256; i++)
{
Rhists_prob[i] = (double)Rhists[i] / (biHead1.biHeight * biHead1.biWidth);
Ghists_prob[i] = (double)Ghists[i] / (biHead1.biHeight * biHead1.biWidth);
Bhists_prob[i] = (double)Bhists[i] / (biHead1.biHeight * biHead1.biWidth);
}
//计算累计密度
double Rhists_distribution[256] = { 0 };
double Ghists_distribution[256] = { 0 };
double Bhists_distribution[256] = { 0 };
Rhists_distribution[0] = Rhists_prob[0];
Ghists_distribution[0] = Ghists_prob[0];
Bhists_distribution[0] = Bhists_prob[0];
for (int i = 1; i < 256; i++)
{
Rhists_distribution[i] = Rhists_distribution[i - 1] + Rhists_prob[i];
Ghists_distribution[i] = Ghists_distribution[i - 1] + Ghists_prob[i];
Bhists_distribution[i] = Bhists_distribution[i - 1] + Bhists_prob[i];
}
//重新计算均衡化后的灰度值,四舍五入。参考公式:(N-1)*T+0.5
int Rhists_equal[256] = { 0 };
int Ghists_equal[256] = { 0 };
int Bhists_equal[256] = { 0 };
for (int i = 0; i < 256; i++)
{
Rhists_equal[i] = (unsigned char)(255 * Rhists_distribution[i] + 0.5);
Ghists_equal[i] = (unsigned char)(255 * Ghists_distribution[i] + 0.5);
Bhists_equal[i] = (unsigned char)(255 * Bhists_distribution[i] + 0.5);
}
//展示直方图均衡化后的图片
x = 0;
for (int i = 0; i < biHead1.biHeight; i++)
{
for (int j = 0; j < biHead1.biWidth; j++)
{
dc.SetPixel(j, (biHead1.biHeight - i), RGB(Rhists_equal[p1[x + 2]], Ghists_equal[p1[x + 1]], Bhists_equal[p1[x]]));
x += 3;
}
}
//重新统计每个分量下的像素个数
unsigned int* Rhistsnew, * Ghistsnew, * Bhistsnew;
Rhistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
Ghistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
Bhistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
memset(Rhistsnew, 0x0, 256 * sizeof(unsigned int));
memset(Ghistsnew, 0x0, 256 * sizeof(unsigned int));
memset(Bhistsnew, 0x0, 256 * sizeof(unsigned int));
x = 0;
for (int i = 0; i < biHead1.biHeight; i++)
{
for (int j = 0; j < biHead1.biWidth; j++)
{
Rhistsnew[Rhists_equal[p1[x + 2]]]++;
Ghistsnew[Ghists_equal[p1[x + 1]]]++;
Bhistsnew[Bhists_equal[p1[x]]]++;
x += 3;
}
}
//绘制R分量直方图
//绘制R直方图坐标轴
dc.MoveTo(10, 500);
dc.LineTo(310, 500);
dc.MoveTo(10, 500);
dc.LineTo(10, 0);
//绘制R直方图
for (int j = 0; j < 256; j++)
{
dc.MoveTo(20 + j, 500);
dc.LineTo(20 + j, 500 - Rhistsnew[j] / 100);
}
}
左原图,右均衡化后图:
均衡化后直方图: